comicforge 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- comicforge-0.0.1/.claude/skills/comicforge/SKILL.md +325 -0
- comicforge-0.0.1/.claude/skills/comicforge/reference.md +644 -0
- comicforge-0.0.1/.github/workflows/ci.yml +84 -0
- comicforge-0.0.1/.github/workflows/release.yml +69 -0
- comicforge-0.0.1/.gitignore +36 -0
- comicforge-0.0.1/.python-version +1 -0
- comicforge-0.0.1/CLAUDE.md +97 -0
- comicforge-0.0.1/PKG-INFO +136 -0
- comicforge-0.0.1/README.md +123 -0
- comicforge-0.0.1/comicforge/__init__.py +10 -0
- comicforge-0.0.1/comicforge/__main__.py +5 -0
- comicforge-0.0.1/comicforge/bubbles.py +133 -0
- comicforge-0.0.1/comicforge/cli.py +396 -0
- comicforge-0.0.1/comicforge/inspire.py +246 -0
- comicforge-0.0.1/comicforge/library.py +235 -0
- comicforge-0.0.1/comicforge/pixelart.py +80 -0
- comicforge-0.0.1/comicforge/render.py +560 -0
- comicforge-0.0.1/comicforge/scaffold.py +144 -0
- comicforge-0.0.1/comicforge/scene.py +112 -0
- comicforge-0.0.1/comicforge/validate.py +192 -0
- comicforge-0.0.1/docs/starting-a-project.md +70 -0
- comicforge-0.0.1/examples/README.md +43 -0
- comicforge-0.0.1/examples/README.md.old +22 -0
- comicforge-0.0.1/examples/pes/characters/bara/character.yaml +14 -0
- comicforge-0.0.1/examples/pes/characters/bara/face-happy.svg +10 -0
- comicforge-0.0.1/examples/pes/characters/bara/face-neutral.svg +11 -0
- comicforge-0.0.1/examples/pes/characters/bara/poses/sit/base.svg +25 -0
- comicforge-0.0.1/examples/pes/characters/bara/poses/sit/pose.yaml +4 -0
- comicforge-0.0.1/examples/pes/characters/bara/poses/walk/base.svg +28 -0
- comicforge-0.0.1/examples/pes/characters/bara/poses/walk/pose.yaml +5 -0
- comicforge-0.0.1/examples/pes/characters/tom/arms-crossed.svg +8 -0
- comicforge-0.0.1/examples/pes/characters/tom/arms-down.svg +8 -0
- comicforge-0.0.1/examples/pes/characters/tom/arms-hips.svg +8 -0
- comicforge-0.0.1/examples/pes/characters/tom/arms-point.svg +8 -0
- comicforge-0.0.1/examples/pes/characters/tom/arms-thumbsup.svg +12 -0
- comicforge-0.0.1/examples/pes/characters/tom/arms-wave.svg +8 -0
- comicforge-0.0.1/examples/pes/characters/tom/base.svg +31 -0
- comicforge-0.0.1/examples/pes/characters/tom/character.yaml +9 -0
- comicforge-0.0.1/examples/pes/characters/tom/face-angry.svg +9 -0
- comicforge-0.0.1/examples/pes/characters/tom/face-happy.svg +9 -0
- comicforge-0.0.1/examples/pes/characters/tom/face-laugh.svg +10 -0
- comicforge-0.0.1/examples/pes/characters/tom/face-neutral.svg +7 -0
- comicforge-0.0.1/examples/pes/characters/tom/face-sad.svg +10 -0
- comicforge-0.0.1/examples/pes/characters/tom/face-surprised.svg +11 -0
- comicforge-0.0.1/examples/pes/characters/tom/face-wink.svg +8 -0
- comicforge-0.0.1/examples/pes/pages/dvur-scene.yaml +21 -0
- comicforge-0.0.1/examples/pes/pages/kosticka.yaml +47 -0
- comicforge-0.0.1/examples/pes/pages/slepice.yaml +45 -0
- comicforge-0.0.1/examples/pes/pixel/bone.yaml +11 -0
- comicforge-0.0.1/examples/pes/pixel/heart.yaml +11 -0
- comicforge-0.0.1/examples/pes/pixel/star.yaml +11 -0
- comicforge-0.0.1/examples/pes/pixel/sun.yaml +13 -0
- comicforge-0.0.1/examples/pes/references.yaml +18 -0
- comicforge-0.0.1/examples/pes/scenes/dvur/base.svg +31 -0
- comicforge-0.0.1/examples/pes/scenes/dvur/scene.yaml +7 -0
- comicforge-0.0.1/examples/pes/scenes/dvur/weather-clear.svg +3 -0
- comicforge-0.0.1/examples/pes/scenes/dvur/weather-rain.svg +17 -0
- comicforge-0.0.1/examples/pes/scenes/pokoj/base.svg +16 -0
- comicforge-0.0.1/examples/pes/scenes/pokoj/scene.yaml +3 -0
- comicforge-0.0.1/examples/pes/theme.yaml +22 -0
- comicforge-0.0.1/poe_tasks.toml +60 -0
- comicforge-0.0.1/pyproject.toml +95 -0
- comicforge-0.0.1/skills/comicforge/SKILL.md +325 -0
- comicforge-0.0.1/skills/comicforge/reference.md +644 -0
- comicforge-0.0.1/tests/__init__.py +0 -0
- comicforge-0.0.1/tests/conftest.py +36 -0
- comicforge-0.0.1/tests/test_bubbles.py +32 -0
- comicforge-0.0.1/tests/test_cli.py +84 -0
- comicforge-0.0.1/tests/test_inspire.py +93 -0
- comicforge-0.0.1/tests/test_library.py +54 -0
- comicforge-0.0.1/tests/test_pixelart.py +47 -0
- comicforge-0.0.1/tests/test_render.py +117 -0
- comicforge-0.0.1/tests/test_scaffold.py +49 -0
- comicforge-0.0.1/tests/test_scene.py +34 -0
- comicforge-0.0.1/tests/test_validate.py +125 -0
- comicforge-0.0.1/uv.lock +817 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: comicforge
|
|
3
|
+
description: >
|
|
4
|
+
Author comic pages and standalone illustrations as declarative YAML specs that
|
|
5
|
+
ComicForge renders to SVG / PNG / PDF. Use this skill whenever the user wants to
|
|
6
|
+
make a comic strip, comic page, cartoon panel, or single illustration with
|
|
7
|
+
ComicForge — placing characters (base SVG + stackable face/arms overlays), scene
|
|
8
|
+
backgrounds, speech/thought/shout bubbles, and pixel-art sprites in a row/panel
|
|
9
|
+
grid. Also triggers on adding a new character, scene, or sprite to a ComicForge
|
|
10
|
+
project, or on questions about the spec grammar, panel coordinates, or the
|
|
11
|
+
`comicforge` CLI (`init`, `render`, `scene`, `panel`, `validate`, `characters`,
|
|
12
|
+
`scenes`).
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# ComicForge — authoring comics from YAML
|
|
16
|
+
|
|
17
|
+
You write a **comic page as a YAML spec**; the engine renders it to SVG/PNG/PDF.
|
|
18
|
+
This file is the authoring contract. For deeper explanations (path resolution,
|
|
19
|
+
how to add characters/scenes, pixel-art format, Python API, full CLI reference)
|
|
20
|
+
see [`reference.md`](reference.md) in this skill directory.
|
|
21
|
+
|
|
22
|
+
## Loop
|
|
23
|
+
|
|
24
|
+
All art belongs to a **project** (e.g. `examples/pes/`) — there is no shared
|
|
25
|
+
library. A project owns `characters/`, `scenes/`, `pixel/`, and its page specs
|
|
26
|
+
under `pages/`. Paths below assume you are working inside one project.
|
|
27
|
+
|
|
28
|
+
Starting from scratch? `cmf init <dir>` scaffolds those four asset dirs, a
|
|
29
|
+
renderable starter page, and a copy of this skill — a data-only project that
|
|
30
|
+
needs no Python (see [`reference.md`](reference.md)).
|
|
31
|
+
|
|
32
|
+
1. Read the project's assets:
|
|
33
|
+
- `cmf characters --library examples/pes/characters` → JSON
|
|
34
|
+
of every character, its **slots**, **variants** per slot, and the defaults.
|
|
35
|
+
- `cmf scenes --scenes examples/pes/scenes` → JSON of every
|
|
36
|
+
scene background and its slots.
|
|
37
|
+
2. Write a spec under `pages/` (see grammar below). Spec-level keys declare where
|
|
38
|
+
assets live, relative to the spec file (siblings are one level up):
|
|
39
|
+
```yaml
|
|
40
|
+
library: "../characters"
|
|
41
|
+
scenes_dir: "../scenes"
|
|
42
|
+
pixel_dir: "../pixel"
|
|
43
|
+
```
|
|
44
|
+
3. Validate before rendering: `cmf validate mystrip.yaml` — checks every actor,
|
|
45
|
+
scene, pixel sprite, slot variant, pose, and bubble speaker against the
|
|
46
|
+
libraries without drawing anything, and lists *all* problems at once. Unlike
|
|
47
|
+
`render`, it flags mis-spelled keys (e.g. `fcae:`) that render silently
|
|
48
|
+
ignores. Exits non-zero when anything is wrong. Works on page and `scene` specs.
|
|
49
|
+
4. Render:
|
|
50
|
+
- comic page: `cmf render mystrip.yaml -o out.pdf`
|
|
51
|
+
- single illustration: `cmf scene myscene.yaml -o out.png`
|
|
52
|
+
- one character on its own (to eyeball a pose/expression):
|
|
53
|
+
`cmf character bara sit happy --library examples/pes/characters`
|
|
54
|
+
— extra args are bare pose/variant names or `key=value` (`pose=walk`,
|
|
55
|
+
`face=happy`), rendered on a white background. Also writes a smaller
|
|
56
|
+
`….small.png` companion — read that one to save tokens.
|
|
57
|
+
- Omit `-o` and the file lands in the gitignored `output/` dir with a
|
|
58
|
+
timestamp (`output/<name>-<YYYYMMDD-HHMMSS>.png`), so renders accumulate and
|
|
59
|
+
you can compare how a page/character evolved. Pass `-o` to choose a path.
|
|
60
|
+
5. Look at the output; adjust `x` / `y` / `scale` / `to` and re-render.
|
|
61
|
+
|
|
62
|
+
## Coordinates
|
|
63
|
+
|
|
64
|
+
Every position inside a panel is a **fraction 0..1 of that panel**:
|
|
65
|
+
`x` = left→right, `y` = top→bottom. `(0.5, 0.5)` is the panel centre.
|
|
66
|
+
`scale` for actors/pixel art = height as a fraction of the panel height.
|
|
67
|
+
|
|
68
|
+
## Spec grammar
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
title: "Optional page title" # bold caption strip at the top
|
|
72
|
+
type: page # page (default) | scene — see below
|
|
73
|
+
page: A4 # A4 | A5 | letter | [w_mm, h_mm]
|
|
74
|
+
px_per_mm: 4 # raster scale (vector PDF ignores it)
|
|
75
|
+
margin_mm: 14
|
|
76
|
+
gutter_mm: 6
|
|
77
|
+
library: "../characters" # path to character dir
|
|
78
|
+
scenes_dir: "../scenes" # path to scenes dir (omit if no scenes used)
|
|
79
|
+
pixel_dir: "../pixel" # path to pixel-art dir (omit if inline only)
|
|
80
|
+
|
|
81
|
+
rows: # page is a stack of rows…
|
|
82
|
+
- height: 1.0 # relative row height (default 1)
|
|
83
|
+
panels: # …each row is a left→right list of panels
|
|
84
|
+
- width: 1.0 # relative panel width (default 1)
|
|
85
|
+
bg: "#fbfaf6" # optional flat panel background
|
|
86
|
+
scene: dvur # optional scene background (see below)
|
|
87
|
+
actors: [ ... ] # characters (drawn back→front in list order)
|
|
88
|
+
pixel: [ ... ] # pixel-art sprites (drawn behind actors)
|
|
89
|
+
bubbles:[ ... ] # speech/thought/shout (drawn on top)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### actor
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
- char: tom # character name (from `comicforge characters`)
|
|
96
|
+
pose: walk # OPTIONAL: which body to draw; defaults to the character's default pose
|
|
97
|
+
face: happy # any slot -> a valid variant; omitted slots use defaults
|
|
98
|
+
arms: wave
|
|
99
|
+
x: 0.35 # centre (panel fraction)
|
|
100
|
+
y: 0.62
|
|
101
|
+
scale: 0.85 # height as fraction of panel height
|
|
102
|
+
flip: false # mirror horizontally (face the other way)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Slots and poses are per character. `tom` is single-pose with `face`
|
|
106
|
+
(neutral/happy/surprised/sad/angry/laugh/wink) and `arms`
|
|
107
|
+
(down/wave/point/crossed/hips/thumbsup); `bara` has poses `sit`/`walk` and a
|
|
108
|
+
shared `face` (neutral/happy). Omit `pose` to get the default. Some slots are
|
|
109
|
+
shared across poses, some are pose-specific — the manifest shows both. Always
|
|
110
|
+
confirm against `comicforge characters --library <project>/characters` — never
|
|
111
|
+
guess a pose or variant that isn't listed.
|
|
112
|
+
|
|
113
|
+
### scene (panel background)
|
|
114
|
+
|
|
115
|
+
A scene is a reusable illustrated background, scaled to *cover* the panel.
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
scene: dvur # just the name…
|
|
119
|
+
scene: {name: dvur, weather: rain} # …or pick scene slot variants
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Confirm scenes/slots with `comicforge scenes --scenes <project>/scenes`.
|
|
123
|
+
Seeds in `examples/pes/`: `dvur` (farmyard, slot `weather: clear|rain`),
|
|
124
|
+
`pokoj` (room, no slots). Both live in `examples/pes/scenes/`.
|
|
125
|
+
|
|
126
|
+
## Standalone illustration (no comic grid)
|
|
127
|
+
|
|
128
|
+
Render one scene filling the whole canvas with actors/bubbles on top — good for
|
|
129
|
+
covers and single panels. Render with `comicforge scene file.yaml -o out.png`.
|
|
130
|
+
|
|
131
|
+
Set `type: scene` so the spec declares which command renders it: `render`
|
|
132
|
+
rejects a scene spec (and `scene` rejects a page spec) with a clear message
|
|
133
|
+
instead of a confusing crash, and `validate` checks the type matches the
|
|
134
|
+
structure. `type:` is optional — when omitted it's inferred (a top-level
|
|
135
|
+
`scene` with no `rows` == a scene) — but declare it on standalone illustrations.
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
title: "Optional"
|
|
139
|
+
type: scene
|
|
140
|
+
scene: {name: dvur, weather: clear}
|
|
141
|
+
scale: 3 # px per scene unit (canvas = scene viewbox × scale)
|
|
142
|
+
library: "../characters"
|
|
143
|
+
scenes_dir: "../scenes"
|
|
144
|
+
actors: [ ... ] # same actor grammar; x/y/scale are canvas fractions
|
|
145
|
+
pixel: [ ... ]
|
|
146
|
+
bubbles: [ ... ]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### bubble
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
- text: "Ahoj!"
|
|
153
|
+
kind: speech # speech | thought | shout
|
|
154
|
+
speaker: tom # OPTIONAL: auto-place above this actor + aim the tail at
|
|
155
|
+
# their head. Prefer this over manual x/y/to.
|
|
156
|
+
x: 0.5 # OPTIONAL bubble centre (panel fraction); else from speaker
|
|
157
|
+
y: 0.18 # OPTIONAL; omit and bubbles stack downward without overlap
|
|
158
|
+
to: [0.4, 0.5] # OPTIONAL tail target (panel fraction); else speaker's head
|
|
159
|
+
max_chars: 22 # wrap width (optional)
|
|
160
|
+
fs: 16 # font size px (optional)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`thought` draws an ellipse with a trail of dots; `shout` draws a spiky burst.
|
|
164
|
+
The tail is a slim line dropping from the bubble underside; its tip is capped
|
|
165
|
+
short so it never overlaps the figure.
|
|
166
|
+
|
|
167
|
+
### pixel art
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
# From the library (needs pixel_dir: in the spec):
|
|
171
|
+
- art: heart # library sprites: heart, sun, star, bone
|
|
172
|
+
x: 0.8 y: 0.25 scale: 0.18
|
|
173
|
+
|
|
174
|
+
# Inline (no pixel_dir needed):
|
|
175
|
+
- grid: ["....", ".RR.", ".RR.", "...."]
|
|
176
|
+
palette: {R: "#e8556d"}
|
|
177
|
+
x: 0.5 y: 0.5 scale: 0.3
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Library sprites live in `<project>/pixel/<name>.yaml`. Inline sprites work with
|
|
181
|
+
no `pixel_dir:` at all.
|
|
182
|
+
|
|
183
|
+
## Adding a character (no code)
|
|
184
|
+
|
|
185
|
+
A character is an **identity** that owns one or more **poses** (different bodies:
|
|
186
|
+
sit, walk, …). Expressions (`face`, …) are authored once and *shared* across
|
|
187
|
+
poses. There are two on-disk shapes — use the simpler one until you need poses.
|
|
188
|
+
|
|
189
|
+
### Single-pose (flat) — the simple case
|
|
190
|
+
|
|
191
|
+
Create `<project>/characters/<name>/`:
|
|
192
|
+
|
|
193
|
+
- `base.svg` — the body, drawn in a local `viewBox` (e.g. `0 0 200 320`).
|
|
194
|
+
- `<slot>-<variant>.svg` — overlays in the **same** viewBox/coords
|
|
195
|
+
(e.g. `face-happy.svg`, `arms-wave.svg`). They stack on top of the base.
|
|
196
|
+
- `character.yaml`:
|
|
197
|
+
```yaml
|
|
198
|
+
name: <name>
|
|
199
|
+
label: <Display Name>
|
|
200
|
+
viewbox: [200, 320]
|
|
201
|
+
default: {face: neutral, arms: down}
|
|
202
|
+
slots: {arms: [down, wave, point], face: [neutral, happy, surprised, sad]}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Multiple poses
|
|
206
|
+
|
|
207
|
+
When the **body** changes between poses (legs differ sit vs walk), give each pose
|
|
208
|
+
its own `base.svg`. Shared overlays (faces) live at the character root and are
|
|
209
|
+
re-registered onto each pose via an **anchor** — a reference point (typically the
|
|
210
|
+
head centre) the faces are drawn around.
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
<project>/characters/bara/
|
|
214
|
+
character.yaml # identity + SHARED slots + default + pose list
|
|
215
|
+
face-happy.svg # SHARED overlays, drawn around the canonical anchor
|
|
216
|
+
face-neutral.svg
|
|
217
|
+
poses/
|
|
218
|
+
sit/ { pose.yaml, base.svg, [<slot>-<variant>.svg …] }
|
|
219
|
+
walk/ { pose.yaml, base.svg, [<slot>-<variant>.svg …] }
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
```yaml
|
|
223
|
+
# character.yaml
|
|
224
|
+
name: bara
|
|
225
|
+
label: Bára
|
|
226
|
+
anchor: [120, 72] # canonical point the shared faces are drawn around
|
|
227
|
+
slots: {face: [neutral, happy]} # SHARED across poses, re-anchored per pose
|
|
228
|
+
default: {pose: sit, face: neutral}
|
|
229
|
+
poses: [sit, walk]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```yaml
|
|
233
|
+
# poses/walk/pose.yaml
|
|
234
|
+
viewbox: [240, 180]
|
|
235
|
+
anchor: [132, 64] # where THIS pose's head-centre lands
|
|
236
|
+
slots: {arms: [trot]} # OPTIONAL pose-specific slots + overlays
|
|
237
|
+
default: {arms: trot}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The engine shifts each shared overlay by `pose.anchor - character.anchor`, so one
|
|
241
|
+
`face-happy.svg` lands correctly on every pose. **Translate-only**: keep the head
|
|
242
|
+
the same *size* across poses — only its position changes. To add a pose, drop in a
|
|
243
|
+
new `poses/<name>/` (its own `base.svg` + `pose.yaml`) and list it under `poses:`.
|
|
244
|
+
|
|
245
|
+
> Tip: the seed art is hand/LLM-authored clean SVG, edited directly in the project.
|
|
246
|
+
> A visual model is useful as *inspiration* for a character or scene — generate a
|
|
247
|
+
> reference image for ideas, then author the crisp SVG by hand. Don't auto-vectorize:
|
|
248
|
+
> it breaks overlay/anchor registration and the editable slot structure.
|
|
249
|
+
> Use `comicforge inspire` (below) to paint those references.
|
|
250
|
+
|
|
251
|
+
## Generating reference images (`comicforge inspire`)
|
|
252
|
+
|
|
253
|
+
Blend a project-wide **theme** (style, color scale, mood) with per-item
|
|
254
|
+
**descriptions** and let an image model paint reference art to author SVG from.
|
|
255
|
+
The output is inspiration only — it is *not* a shipped asset, and you should not
|
|
256
|
+
auto-vectorize it.
|
|
257
|
+
|
|
258
|
+
1. `<project>/theme.yaml` — the central theme applied to every image:
|
|
259
|
+
```yaml
|
|
260
|
+
style: > # the look, in words
|
|
261
|
+
Hand-drawn children's-book comic. Bold black ink outlines, flat cheerful fills.
|
|
262
|
+
palette: ["#f4d35e", "#ee964b", "#0d3b66"] # color scale fed to the model
|
|
263
|
+
mood: warm, playful, gentle
|
|
264
|
+
negative: No text, no letters, no words. # what to avoid (has a default)
|
|
265
|
+
aspect_ratio: "1:1"
|
|
266
|
+
# model: google/imagen-3 # optional Replicate model override
|
|
267
|
+
```
|
|
268
|
+
2. `<project>/references.yaml` — the things to depict (id → filename):
|
|
269
|
+
```yaml
|
|
270
|
+
items:
|
|
271
|
+
- {id: tom, prompt: "A cheerful boy in a striped shirt, full body, neutral pose"}
|
|
272
|
+
- {id: dvur, prompt: "A sunny Czech farmyard with a wooden fence and chicken coop"}
|
|
273
|
+
```
|
|
274
|
+
3. Generate (writes `<project>/references/<id>.png` + `<id>.prompt.txt`):
|
|
275
|
+
```bash
|
|
276
|
+
comicforge inspire <project>/references.yaml --review # + a review.html grid
|
|
277
|
+
comicforge inspire <project>/references.yaml --dry-run # compose prompts, no API call
|
|
278
|
+
comicforge inspire <project>/references.yaml --only tom,dvur --force
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`theme.yaml` and the output `references/` dir default to siblings of the spec
|
|
282
|
+
(override with `--theme` / `-o`). Live generation needs the optional extra
|
|
283
|
+
(`pip install "comicforge[inspire]"`) and a `REPLICATE_API_TOKEN` (env var or a
|
|
284
|
+
`.env` beside the spec). `--dry-run` needs neither — use it to iterate on prompts.
|
|
285
|
+
|
|
286
|
+
## Adding a scene (no code)
|
|
287
|
+
|
|
288
|
+
Create a scene directory (e.g. `<project>/scenes/<name>/`) exactly like a character
|
|
289
|
+
but with `scene.yaml` instead of `character.yaml`. `base.svg` is the full
|
|
290
|
+
background (drawn in its own viewBox); optional `<slot>-<variant>.svg` overlays
|
|
291
|
+
add weather/props. The scene is scaled to cover whatever panel (or canvas) it is
|
|
292
|
+
placed in.
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
<project>/scenes/<name>/
|
|
296
|
+
base.svg
|
|
297
|
+
<slot>-<variant>.svg (optional, one per variant)
|
|
298
|
+
scene.yaml
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Then point your spec at that directory via `scenes_dir:`.
|
|
302
|
+
|
|
303
|
+
## Adding a pixel-art sprite
|
|
304
|
+
|
|
305
|
+
Create `<project>/pixel/<name>.yaml`:
|
|
306
|
+
|
|
307
|
+
```yaml
|
|
308
|
+
palette:
|
|
309
|
+
R: "#e8556d"
|
|
310
|
+
grid:
|
|
311
|
+
- ".RR."
|
|
312
|
+
- "RRRR"
|
|
313
|
+
- ".RR."
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Then reference it with `{art: <name>}` in any panel whose spec has `pixel_dir:`
|
|
317
|
+
pointing at that `pixel/` directory.
|
|
318
|
+
|
|
319
|
+
## Notes / limits (v0.1)
|
|
320
|
+
|
|
321
|
+
- Poses are pre-drawn bodies (a `base.svg` each), not an articulated skeleton;
|
|
322
|
+
shared expressions re-anchor onto them by translation only (no per-pose resize).
|
|
323
|
+
- One title strip; panels are a row/column grid (no free-form panel polygons yet).
|
|
324
|
+
- Text wrap is a width estimate — check long lines in the render.
|
|
325
|
+
- PDF is true vector (crisp at print); PNG is rasterized at `px_per_mm`.
|