Integrate
Asset packs
Using the two shipped packs, registering more than one, and adding a character of your own.
An asset pack supplies the art a document refers to by id: character sprite sheets with a pose table, and backdrop images. The renderer never ships art of its own.
The two shipped packs
| Pack | npm | name | Contents |
|---|---|---|---|
| Comic Chat | @toonstrip/pack-comic-chat |
comic-chat |
15 characters, 3 backdrops. The original Microsoft Comic Chat art, MIT. |
| Example | @toonstrip/pack-example |
example |
1 character (pip), 1 backdrop (meadow). Original, tiny, and the template for your own. |
{
"version": 1,
"panels": [
{
"backdrop": "meadow",
"camera": "medium",
"bodies": [
{
"character": "pip",
"emotion": {
"angle": 0,
"intensity": 0.5
},
"pose": "wave"
}
],
"speakers": [
{
"speaker": "pip",
"balloon": "speech",
"text": "Hi! I'm from the example pack."
}
]
},
{
"backdrop": "meadow",
"camera": "medium",
"bodies": [
{
"character": "pip",
"emotion": {
"angle": 0,
"intensity": 0.2
},
"pose": "shrug"
}
],
"speakers": [
{
"speaker": "pip",
"balloon": "speech",
"text": "One character, one backdrop, one manifest."
}
]
}
]
}Registering more than one
List every pack in the integration and name the ones a strip needs in the component. Ids resolve across all registered packs; a character or backdrop id declared by two packs is a load-time error, not a silent first-match.
// astro.config.mjs
toonstrip({ packs: ["@toonstrip/pack-comic-chat", "@toonstrip/pack-example"] })
<ComicStrip document={doc} packs={["comic-chat", "example"]} client:visible />
{
"version": 1,
"panels": [
{
"backdrop": "meadow",
"camera": "medium",
"bodies": [
{
"character": "pip",
"emotion": {
"angle": 0,
"intensity": 0.6
},
"pose": "wave"
},
{
"character": "anna",
"emotion": {
"angle": 0,
"intensity": 0.6
}
}
],
"speakers": [
{
"speaker": "pip",
"balloon": "speech",
"text": "Two packs, one panel."
},
{
"speaker": "anna",
"balloon": "speech",
"text": "Ids just have to be unique across them."
}
]
}
]
}Pack layout
my-pack/
pack.json # name, version, license, characters[], backdrops[]
characters/<id>/sheet.png # one sprite sheet per character
characters/<id>/<id>.json # that character's parts: faces, torsos, rects, sockets
backdrops/<id>.png
NOTICE # required if any art is not wholly yours
pack.json:
{
"name": "my-pack",
"version": "0.1.0",
"license": "MIT",
"characters": [
{ "id": "pip", "name": "Pip", "manifest": "characters/pip/pip.json", "sheet": "characters/pip/sheet.png" }
],
"backdrops": [
{ "id": "meadow", "file": "backdrops/meadow.png", "width": 240, "height": 240 }
]
}
name is what strips reference, not the npm package name. license is required on every
pack.
A character manifest
A character is parts, not finished drawings: faces and torsos as rectangles in the sheet, each tagged with an emotion point, plus the neck socket so a face sits on any torso.
interface PackedAvatar {
name: string;
type: string;
torsoFirst: boolean; // torso draws over the collar, or under it
sheet: string; // path relative to this manifest
sheetWidth: number;
sheetHeight: number;
faces: PackedPart[];
torsos: PackedPart[];
bodies: PackedPart[]; // unused today; leave empty
}
interface PackedPart {
kind: "face" | "torso" | "body";
index: number;
emotion: string; // "NEUTRAL", "HAPPY", … or a gesture name
angle: number; // wheel angle, or 1001 wave / 1002 point / 1005 shrug
intensity: number;
cx: number; cy: number; // neck socket
cxDelta: number; cyDelta: number;
x: number; // where a balloon tail attaches
figure: { x: number; y: number; width: number; height: number };
aura: { x: number; y: number; width: number; height: number } | null;
}
Minimum: one face with emotion: "NEUTRAL" and one torso. Gestures are torsos at the
sentinel angles (1001 wave, 1002 point, 1005 shrug); support the ones you draw.
Validate
npx toonstrip pack validate ./my-pack
Checks pack.json, every declared file, the NEUTRAL face, and that each backdrop’s real
pixel size matches what pack.json claims. It lists every problem, not just the first.
Warning
A character with faces but no torsos validates today and then renders nothing. Always declare at least one torso.
Adding a character, step by step
- Draw the parts on one sheet (any editor, or a script). At minimum a NEUTRAL face and a torso, each a clean rectangle.
- Write the manifest: copy
pip.jsonfrom the example pack and replace the rectangles and sockets with yours. - Add the character to
pack.json. - Run
pack validate. - Render one panel with it in the playground by serving your pack
locally, or in a Node script through
@toonstrip/core’srenderPanel.
The example pack’s sheet is drawn by a 60-line script with @napi-rs/canvas; it is the
smallest complete pack and the one to copy.
Licensing
Say what the art is. If any of it is not wholly yours, ship a NOTICE crediting the
source and its licence. The default pack’s NOTICE (Microsoft Comic Chat art, MIT, with a
trademark disclaimer) is the worked example.