---
title: Puppets and style kits
summary: How a 2D animated character works in GroundSlate. A style kit sets how the whole show is drawn, a puppet of SVG parts holds one character's body, and an avatar ties the two to a voice. The sheets are HTML and the film is those pages captured. What the doctor, sheet, build, convert and scaffold tools do, and what each one refuses.
lede: SVG parts, an HTML sheet, a voice on one character
eyebrow: Best practice
accent: arc
series: animation
series_order: 6
order: 3
image: /resources/series/animation/style-kit.webp
image_alt: The Sleep Town style kit, swatches and the parts a face is built from
---

Characters built by an agent tend to fail the same way. The pipeline works, the scenes seek cleanly, the render is sound, and the drawing is off model: rectangles for torsos, an even stroke where a hand-drawn line should taper, a second episode with a different look because the palette lived in the first episode's project. GroundSlate gives the drawing a home and a set of rules every agent follows. Each object owns one thing, and every object has a preview.

The drawings are SVG. The sheet you look at is an HTML page. The film is those pages captured frame by frame. A change is an edit to an SVG or a page, then a re-render, not a new generated clip.

## The objects, and where each one lives

A **style kit** sets how the whole show is drawn: the palette, with a role for every colour; the line rule; the cel shadow; the proportions; and the shared sets of mouths, eyes and brows. There is one per show, never one per episode, stored as one kit in a collection of kind `style_kit`.

A **puppet** holds one character's body: the skeleton, the SVG drawings for each authored view, the face sets, the slots a prop attaches to, and the costumes. It is one kit in a collection of kind `puppets`. The character's **avatar** points at it, just as it points at reference media and a voice.

Collections have a `kind` for this. `looks` is the default, and every brand reference collection is already one; the others are `engine`, `puppets`, `sets`, `props` and `style_kit`. The app's Toolkit lists them under Code Kits, labels each card with its kind and opens each one to match. Kits were called templates in earlier releases. A new collection gets its kind from `create_kit_collection`, and `set_collection_kind` relabels one made before kinds existed. The doctors refuse a kit in the wrong kind of collection, so set the kind first.

The drawing helpers ship with the app as a built-in kit, alongside the measurement kit and the transition kit:

```
get_kit("draw kit")
```

That returns `gs-draw.js`: the blob, bean, egg, wedge and tapered line builders that style kits and puppets are drawn with. It makes a good shape the easy option.

## What a style kit is

A kit is a folder of files, and `kit.json` defines it. The palette names every colour with a six digit hex and a **role**, meaning where it paints. The outline colour is called `ink`. The line rule sets two weights, a taper profile, a boil, and a `stroke_policy` with two values. `filled-outline` means every contour is a closed filled path from the draw kit's taper helper, never an SVG stroke. That fixes the even-line look and is always safe to seek. `stroke` means outlines are stroked paths at the kit's weight, which is what a front drawn by another model or by hand usually has. The puppet doctor refuses a `stroke` attribute under `filled-outline`, so decide the policy once, in the kit, to match how the show's fronts are drawn. The cel shadow names a palette colour. The proportions set the range of character heights, measured in heads.

The kit owns the mouth **vocabulary**, the eye states and the brow states, plus a **fallback table** that leads from every viseme back to `rest` with no loops. It ships a drawing for each vocabulary entry, grouped into mouth families a new puppet can use from day one. `kit.css` holds the same values as CSS custom properties, `swatches.html` and `mouths.html` are its preview pages, and `sheets.json` lists them.

The tools that work on it:

**`style_kit_scaffold`** starts a show's kit from a valid one. Give it a name, a collection and a palette. It writes the whole kit (the vocabulary, the fallback table, the starter mouth families, and every eye and brow state drawn with the draw kit and recoloured to your palette by role), then runs the doctor on the result. Your first edit is to a kit that already passes. Leave out the palette and a house starter is used.

**`style_kit_doctor`** checks a kit against its spec and reports findings instead of failing. It checks the shape of `kit.json`, that every palette entry has a role, the line rule, the shadow colour, the vocabularies and fallback chains, and then the drawings. Each of these is a finding with a fix: a `stroke` attribute under the filled outline policy, a `non-scaling-stroke` anywhere, a raw rectangle or ellipse, a path made mostly of straight lines and perfect arcs, an off-palette fill, and a `kit.css` out of sync with `kit.json`. Read the `not_checked` list as carefully as the findings.

**`style_kit_sheet`** renders one of the kit's preview pages and returns the image. `swatches` shows the palette, the line at both weights, the shadow, and one row each of mouths, eyes and brows. `mouths` shows every family's chart and the fallback chains a two-shape and a one-shape puppet follow. It takes about two seconds, so you can adjust a palette or redraw a viseme and look again straight away.

> Start a style kit in GroundSlate for a show called <<SHOW NAME>>, in a new collection of the same name, with an ink of <<INK HEX>>, a paper of <<PAPER HEX>> and one accent of <<ACCENT HEX>>, each with the role it paints. Run the doctor on it, show me the swatches and the mouth chart, and tell me every finding.

Double-bracketed values are yours to fill in before pasting.

## What a puppet is

A puppet is a folder too, and `puppet.json` defines it. `parts/<view>/*.svg` are the base drawings, `costumes/<name>/<view>/*.svg` dress them, `face/` holds the mouth, eye and brow drawings when the puppet does not use the kit's, `sheet.html` is the preview page, and `puppet-<id>.js` is the character file, which is generated and never edited by hand. That file is the character, not the engine. It stays in the kit store, and a page loads it from `_kit/<collection>/<kit>/puppet-<id>.js`, never from a copy inside a project.

The doctor enforces these rules:

- Every joint has a pivot in every authored view. Mirrored views are derived.
- Every part names a joint and a file that exist, with a unique `z` per view.
- A costume that dresses a joint in one view dresses it in every view, and lists the base parts it hides. A costume missing a view is refused, never silently filled in.
- The mouth chart belongs to the puppet. It lists the visemes the puppet actually draws, always including `rest`, and every viseme it does not draw must reach one it does through the kit's fallback table. That way a puppet with two mouth shapes and one with the full set use the same timing data.
- Each view has anchors for the mouth, eyes and brows.
- The line rule comes from the kit.
- The silhouette rule: rectangles, ellipses and straight-line paths used as anatomy, above the kit's threshold, are refused. This catches a character built from basic shapes before anyone reviews it.

The tools that work on it:

**`puppet_convert`** imports a hand-written rig as a puppet, once. It splits an existing `puppet-<name>.js` into `puppet.json`, the part drawings and the face files, writes the sheet page beside them, copies in the engine, and saves it all as one kit in a `puppets` collection. The engine is GroundSlate's own: `gs-tween.js`, `gs-morph.js` and `gs-puppet.js`, the `puppet engine` kit, with no third-party runtime. There is no GSAP and nothing is missing; `get_kit("puppet engine")` returns all three files. The rig is run, not read as text, so a rig that builds its views with JavaScript needs `node` on the Mac. Without it, the conversion is refused and the error explains why. The result includes the doctor's verdict. On a hand-written rig it will flag the silhouette and line rules. That list is what needs redrawing, not a failed import.

**`puppet_doctor`** checks a puppet against the rules, each with its own code, instantly and at no cost. It reads the kit and writes nothing. Every place the puppet overrides a kit value is reported as a note, so drift from the show's look is visible.

**`puppet_sheet`** renders one of the puppet's named sheets and returns the image: `turnaround` for the views in a row, `expressions` for the emotes as busts, `mouths` for the viseme chart in one row so the drawings can be judged as drawings, `hands` for every hand chart state per authored view, `chart:<joint>` for any other joint chart, or a costume by name. It uses the same page capture as the store's previews, so what you see is what a scene renders. It rebuilds the rig first if the drawings have changed since the last build. It takes about two seconds: edit a part, call this, look.

**`puppet_build`** rebuilds the character file from the puppet. It writes one `GS.registerPuppet` call in the same format the hand-written rigs use, with the drawings inlined per view, the joints and pivots, the slots, the mouth, eye and brow sets (the puppet's own or the kit's) and the default costume, plus one extra file per other costume. It does not touch the engine. The rig stays in the kit store and is not copied into scenes: `write_project_file` refuses a copy of one, and `migrate_project_rigs` moves any copies an earlier session left behind. Never edit the output by hand. Redraw the parts, run the doctor, rebuild.

## A chart is a library of drawings on one joint

The mouth was the first chart, and it is no longer a special case. Any joint can have a **chart**: a set of drawings the animation swaps between, declared on the puppet per joint, with the states it draws, the files per authored view, and an anchor. Hands are the obvious second case. A cut-out show does not rig fingers. It draws eight hands and swaps them, because a drawn pose is a designed shape and five rotating finger joints are not.

The kit owns each chart kind's vocabulary and fallback table, as it does for visemes. `hand` has rest, open, point, fist, hold, wave, thumb up and flat; `foot` has rest, toe up and step. A puppet draws the states it wants, always including `rest`, and any state it does not draw falls back through the table to one it does. So a hand with three drawings and a hand with eight respond to the same pose call. A left hand can mirror the right instead of repeating it. A kind the kit does not know, such as an ear, a tail or a hat brim, is declared on the puppet with its own vocabulary.

In a scene, a chart swap works like a viseme: pose the character at a time with the state you want on that joint. The doctor checks each chart per view, as it does the mouth chart, with separate findings for a missing rest, a missing file, a fallback that does not resolve, and a mirror that names no chart. `puppet_sheet` draws a `hands` sheet with every state per view in a row. That shows you whether `point` actually points, and whether `wave` is different enough from `open` to be worth keeping.

## How an avatar binds a puppet

The avatar is already the character's identity record: bio, appearance, voice, traits, reference media. The puppet is the character's body, and it hangs off the same record, so one lookup finds both the voice and the mouths.

`set_avatar_puppet` points an avatar at a puppet kit, by name or id, with an optional default costume that must be one the puppet has. The avatar stores a reference to the kit and collection, never the drawings. From then on `get_avatar` returns the resolved puppet: heads, views, costumes, slots, the visemes it draws, the doctor's verdict and the path of every sheet image, so a visual check of a costume sheet takes one call. In the app, the avatar's Puppet tab shows the same sheets. `clear_avatar_puppet` removes the link and leaves the kit in its collection.

## The order of work

1. Set the kinds on the collections.
2. Scaffold the show's kit, or check the one you have, and look at the swatches.
3. Convert each existing rig, or start from an approved T-pose front, one character per run. If there is no front, write a brief that copies its visual style from the kit and describes the character part by part. Then draw one T-pose front SVG with named groups, or give that brief to any model that returns SVG and check the result. Do not trace a generated sheet.
4. Set the kit's stroke policy to match the fronts before the first cut.
5. Cut the puppet from that front.
6. Run the doctor until the only findings are ones you intended.
7. Look at the turnaround, the expressions, the mouths and every costume as images, because the file cannot show you that a torso is a rectangle.
8. Bind each puppet to its avatar.
9. Build the character file and put the character in a scene.

When the rules are not met, each step refuses instead of guessing, and every refusal names the fix. A character that passes the doctor and reads well on its sheets carries into the next episode unchanged.

A puppet may override the kit where the kit's value is tuned for a full frame: the cel shadow's offset and opacity, the stroke policy, the proportions. The override lives in the puppet's manifest, and the doctor reports it as a note.
