Model or dataset
nilbuild/page-mascot avatar
nilbuild/page-mascot

nilbuild/page-mascot: a React sprite-sheet character that follows the cursor

A mascot that watches the cursor and blinks when you poke it

583 stars48 forksPythonMIT

At a glance

What is it?
page-mascot is an MIT-licensed React component that renders a character from two 3x3 sprite sheets: one for head direction, one for reactions. It is a small, opinionated package, and the interesting parts are the sheet alignment rules and the agent skill that draws the art for you.
Who is it for?
Adopt page-mascot if you want a cursor-aware character on a React page and you are willing to produce or commission two 3x3 sheets, or to run the bundled agent skill that draws them. Skip it if your page has no fine pointer, if you need a non-React binding, or if you want a component that ships its own artwork.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 16, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What page-mascot actually solves, and for whom

A portfolio or landing page usually gets its personality from static images. page-mascot makes that personality react to the pointer: the character looks toward the cursor and shows a reaction cell when clicked. The README describes it as "an interactive character that watches the cursor and blinks when you poke it." That is the whole scope. It is not a chat widget, not an avatar generator, and not a general animation library.

The audience is narrow and specific. You are building a React page, you have a character design or are willing to have one drawn, and you want the character to feel present without writing animation code. The package is published on npm as version 0.1.0, so it is early. The peer dependency is react >=18, the engines field requires node >=20, and the package is marked sideEffects: false, which matters for tree shaking in bundlers. The MIT licence and the author credit (Kamran Ahmed) are stated in both the README and package.json.

The value proposition is that the hard part of a cursor-tracking mascot is not the tracking math. It is producing a set of drawings that stay aligned when the head turns. page-mascot fixes the format (two 3x3 sheets) so the runtime can stay trivial.

Two 3x3 sheets, one angle lookup, and a dead zone

Each character is two sprite sheets of nine cells each. The directions sheet holds nine head directions; the reactions sheet holds nine expressions. The README shows both sheets as an image and states that the pointer's angle picks a cell on the directions sheet. There is a dead zone so the head settles when the cursor is close, which is the detail that stops the head from jittering when the pointer sits near the character's center. A click shows a cell from the reactions sheet for half a second.

That is the entire data flow: pointer position relative to the element, angle computed, angle mapped to one of nine cells, cell rendered. The reaction is a timed state change, not an animation sequence. No sprite atlas library, no canvas, no requestAnimationFrame loop is mentioned in the README.

The style system is separate from the character. The same character can be drawn in six styles: colour, ink, sketch, riso, paper and pixel. The README is explicit that "only the rendering changes, so the alignment holds." This is the design decision worth noticing. Because every style shares the same nine-cell grid, you can swap a colour fox for a pixel fox without touching the component or re-measuring anything. The cost is that all six styles must obey the same cell boundaries, so an artist cannot let one pose overflow its cell.

Two accessibility behaviours are documented. Tracking switches off without a fine pointer, so touch devices do not get a head that never moves. The click squash honours prefers-reduced-motion. The label prop defaults to 'mascot' and is what a screen reader calls the element.

Install and put the fox on a page

The README gives one install command and one component example. Install the package from npm:

bash
npm i page-mascot

Then get artwork. The README points at the demo page at koboyo.com/page-mascot, where you pick a character and download its two sheets into public/mascots. Once the files are in place, import the component and pass the two paths:

tsx
import { Mascot } from 'page-mascot'

<Mascot
  directions="/mascots/fox-directions.webp"
  reactions="/mascots/fox-reactions.webp"
/>

The README notes that the paths are whatever your app serves, so imported images work too. That means a bundler-resolved import is a valid value here, not only a public URL. What you should see after this step is a character on the page whose head turns as you move the pointer across it, and a reaction when you click.

The remaining props are optional. size defaults to 140 and is described as px, square. label defaults to 'mascot'. className is accepted. The package exports types from dist/index.d.ts, so the props are typed in an editor.

If you would rather have an agent do the wiring, the README shows a slash command once the skill is installed:

code
/page-mascot put the fox on my page

Both routes end at the same two props.

Drawing your own character with the page-mascot skill

The more unusual half of this project is the skill. It installs globally through the skills CLI:

bash
npx skills add nilbuild/page-mascot --skill page-mascot --global --yes

After that, the README shows prompts like `/page-mascot a chibi otter with chocolate-brown fur`, `/page-mascot make one that looks like me` with a photo attached, and `/page-mascot a chibi fox, in the riso style`. According to the README, the skill draws the nine directions and nine expressions, builds them into two aligned sheets, checks that the character does not jump between them, and places the component on your page with the same two props.

The alignment check is the part that makes this more than a prompt wrapper. Nine separate generated images will not line up by default; the skill is described as verifying that the character does not jump between cells. If that check is weak, the result is a mascot whose head twitches as it turns, which is worse than a static image.

Drawing needs an image tool. Codex has its own; Claude Code goes through the OpenAI images API, which requires an environment variable:

bash
export OPENAI_API_KEY=sk-...

If you do not want an agent in the loop at all, the README points at the prompt file at skills/page-mascot/reference/prompts.md and says you can take those prompts into any chat UI. That is the escape hatch, and it is the honest one: the prompts are the asset, the agent is just the runner.

Where page-mascot is the wrong tool

The component needs artwork you supply. There is no bundled character in the package. The files field in package.json ships dist, README.md and LICENSE only, so the sheets live in your app, not in the dependency. If you expected a drop-in animated mascot, you will be downloading sheets from the demo page first.

The React binding is not optional. The package exports a single entry point with types at dist/index.d.ts and a peer dependency on react >=18. There is no documented vanilla JS, Vue or Svelte path. If your page is not React, this package is not for you, and the README does not suggest a workaround.

Pointer tracking is desktop-shaped by design. The README states that tracking switches off without a fine pointer. On a phone the character will sit still, which is the correct behaviour but also means the main effect does not exist on mobile. If most of your traffic is touch, you are paying for a component that does one thing you will never see.

The repository has a check:skill script that diffs src/mascot.tsx against skills/page-mascot/mascot.tsx, and build:site runs that check before typecheck and the Vite build. So the component shipped to npm and the copy the skill installs are kept identical by a diff. That is a real safeguard, but it also means the skill's copy of the component is not independently versioned.

Finally, the project is at 0.1.0 with no releases retrieved. Nothing in the README describes a migration path or a stable API commitment.

How it compares with a general animation or sprite library

The obvious alternative is a general-purpose sprite animation library, or simply a CSS and JavaScript animation you write yourself. The difference is where the work sits. A sprite library gives you a timeline, frame rates, and playback controls; you decide what the frames mean. page-mascot gives you no timeline at all. It gives you a fixed grid, an angle-to-cell mapping, a dead zone, and a half-second reaction state. The behaviour is decided for you.

That trade is deliberate and it shows in the props table. There is no animation speed prop, no frame rate, no easing configuration, no event callback for when a reaction finishes. If you want the mascot to look sad for two seconds instead of half a second, the README documents no way to change that. A general animation library would let you, at the cost of defining the whole state machine yourself.

The second alternative is a static illustration with a CSS hover effect. That costs nothing and never breaks. It also never looks at the cursor. page-mascot exists precisely for the case where the character should feel like it is aware of you, which a hover state cannot fake.

The third is drawing the sheets yourself and writing the angle math by hand. It is perhaps forty lines of code. What you would not get is the six-style alignment convention, the reduced-motion handling, the fine-pointer check, and the skill that generates and validates the sheets. Those are the parts worth adopting; the angle math is not.

Maintenance, licence and what upgrading costs

The last push to the repository was on 2026-09-15, two days before this writing, and the repository is not archived. That is the only maintenance signal available here. There are no retrieved releases, so there is no changelog to read and no version history to judge the pace of change by. Treat 0.1.0 as a pre-1.0 API.

The licence is MIT, stated in the README and in the license field of package.json, with copyright credited to Kamran Ahmed. MIT is permissive: you can use, modify and redistribute the code, including commercially, provided the copyright notice and permission notice are retained. That is a description of the licence text, not legal advice, and it says nothing about the artwork. The sheets you download from the demo page or generate with the skill are a separate question, and the README does not state a licence for the character art. If you plan to ship a mascot commercially, that is the gap to resolve before you commit to the design.

Upgrade cost is mostly about the sheets. The component is small and the props surface is five entries, so a breaking change to the component would be cheap to absorb. The expensive asset is the pair of 3x3 sheets. If a future version changed the grid from 3x3 to something else, every existing character would need redrawing, and the README's six-style alignment guarantee would be void. That is the migration risk to weigh, not the JavaScript.

Editorial conclusion

Adopt page-mascot if you want a cursor-aware character on a React page and you are willing to produce or commission two 3x3 sheets, or to run the bundled agent skill that draws them. Skip it if your page has no fine pointer, if you need a non-React binding, or if you want a component that ships its own artwork. Before wiring it in, open the demo page, download the fox sheets into public/mascots, and confirm the two props resolve to files your app actually serves; the README does not document rollback, versioning of sheets, or what happens when a sheet is missing, so test the missing-path case yourself.

Frequently asked questions

What is page-mascot?

It is an MIT-licensed React component that renders an interactive character from two 3x3 sprite sheets: one for nine head directions and one for nine expressions. The head follows the cursor and a click shows a reaction cell for half a second.

How do I install page-mascot and put a mascot on my page?

Run npm i page-mascot, download a character's two sheets from the demo page into public/mascots, then render the Mascot component with the directions and reactions props pointing at those files.

Does page-mascot work on touch devices?

The README states that tracking switches off without a fine pointer, so on a touch device the character renders but does not follow anything. The click squash also honours prefers-reduced-motion.

Do I have to draw the mascot myself?

No. The README documents an agent skill installed with npx skills add nilbuild/page-mascot --skill page-mascot --global --yes that draws the nine directions and nine expressions, builds the two aligned sheets and checks the character does not jump between them. Drawing needs an image tool, and Claude Code goes through the OpenAI images API, which needs OPENAI_API_KEY set.

Official sources

  1. Issues
  2. License: MIT
  3. nilbuild/page-mascot on GitHub
  4. Project website
  5. README
Community notes

Community notes