Puppet
A character as a rigid paper cut-out: it sways, glances, blinks, and talks back when poked. The art here is Con; the rig knows nothing about him.




Already built. Use that one.





























Props
| Prop | Type | Required | Default |
|---|---|---|---|
layers | PuppetLayers | Yes | — |
canvas | [number, number] | undefined | No | [1, 1] |
size | number | undefined | No | 240 |
motion | "idle" | "hop" | "still" | undefined | No | idle |
weight | "light" | "heavy" | undefined | No | light |
pivot | number | undefined | No | — |
phase | number | undefined | No | — |
pose | PuppetPose | undefined | No | — |
lidLine | number | undefined | No | 35 |
lookRange | number | undefined | No | 1.7 |
label | string | undefined | No | — |
says | string[] | undefined | No | — |
sayEvery | number | undefined | No | 7000 |
bubble | "start" | "end" | undefined | No | start |
onPoke | (() => void) | undefined | No | — |
Cutting a character into layers
Every layer is a transparent PNG on the same canvas as the body, so they line up 1:1 with no positioning data; canvas only supplies the aspect ratio. wobble[].pivot is where a part hinges, in percent of the canvas. eyesMask is the white of the eyes as an alpha mask: pupils and lids are clipped to it, which keeps a glancing pupil inside the eye. lidLine is how far down the canvas the lids start, because a blink drops them from that line. Only body is required; each other layer switches on one behaviour.
A white sticker outline baked into the body (and each wobble part) gives the die-cut look and lets the character sit on any background. Outline the gaps too, between legs for example, so the cut-out reads as one piece of paper.
Weight, speech, poking
weight="light" (the default) is a paper book: big loose swings and a springy pop-up. weight="heavy" is a concrete block: swings a third the size and nearly twice as slow, with a thud when it lands. says is a list of lines shown in turn every sayEvery ms (paused while the tab is hidden); poking the puppet skips to the next line and restarts the timer. A pose holds one expression and stops all motion, for an empty state or a screenshot.
Accessibility
Under prefers-reduced-motion the body, parts and pupils stop and the blink slows right down. The puppet is decorative by default (aria-hidden); pass label to make it an image with a name when the character itself carries meaning. The speech bubble is flavour and hidden from assistive technology; put anything the user needs to read in the page itself.
data-rebar-* attributes
data-rebar-component="puppet" on the root; data-rebar-motion is idle, hop or still; data-rebar-weight is light or heavy; data-rebar-pose is the held expression, when there is one; data-rebar-poked is present for a moment after a poke. Parts: rise, sway, paper, wobble, body, eyes, pupils, lids, bubble (with data-rebar-side).
Migrating to Ant Design
Not codemod-covered: Ant Design has no mascot component. The component is stacked images and CSS keyframes, so it carries over unchanged.