spritegen-cli 0.1.0__py3-none-any.whl
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.
- spritegen/__init__.py +3 -0
- spritegen/atlas.py +99 -0
- spritegen/cli.py +178 -0
- spritegen/clip.py +81 -0
- spritegen/drive.py +163 -0
- spritegen/endpoints.py +113 -0
- spritegen/fal.py +228 -0
- spritegen/imaging.py +219 -0
- spritegen/ledger.py +143 -0
- spritegen/matting.py +136 -0
- spritegen/migrate.py +162 -0
- spritegen/prompts.py +96 -0
- spritegen/rrdb.py +91 -0
- spritegen/settings.py +127 -0
- spritegen/sheet.py +370 -0
- spritegen/skill/__init__.py +303 -0
- spritegen/skill/files/SKILL.md +553 -0
- spritegen/stages/__init__.py +490 -0
- spritegen/stages/anchor.py +215 -0
- spritegen/stages/board.py +68 -0
- spritegen/stages/matte.py +209 -0
- spritegen/stages/motion.py +164 -0
- spritegen/stages/pose.py +172 -0
- spritegen/stages/video.py +196 -0
- spritegen/upscale.py +444 -0
- spritegen/workspace.py +852 -0
- spritegen_cli-0.1.0.dist-info/METADATA +16 -0
- spritegen_cli-0.1.0.dist-info/RECORD +30 -0
- spritegen_cli-0.1.0.dist-info/WHEEL +4 -0
- spritegen_cli-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spritegen
|
|
3
|
+
description: Generate sprite resources for the game with the spritegen CLI — item icons, HUD pieces, box art, single sprites, character anchors, and full animated character sheets (walk, idle, attack). Use it whenever art has to be generated for the game, when someone asks for a sprite, an icon, a portrait or an animation, when a half-finished asset needs picking up again, and before spending on any fal image or video call, because every paid call here is recorded.
|
|
4
|
+
argument-hint: [what to generate, e.g. iron sword icon | female warrior walk cycle]
|
|
5
|
+
allowed-tools: Bash(spritegen *)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# spritegen
|
|
9
|
+
|
|
10
|
+
Asked for: $ARGUMENTS
|
|
11
|
+
|
|
12
|
+
A generator for the game's sprite resources: one image at a time for anything static, or a
|
|
13
|
+
whole pipeline for anything animated. Everything belonging to one asset lives under
|
|
14
|
+
`assets/<name>/`, and no stage takes an input or an output path — that is what lets
|
|
15
|
+
`status` say what comes next and what lets a stage refuse to run out of order.
|
|
16
|
+
|
|
17
|
+
## Running it
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
spritegen --help
|
|
21
|
+
spritegen status
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
It needs `FAL_KEY`. Export it, or put it in a `.env` at the working directory or above —
|
|
25
|
+
an exported variable wins over the file.
|
|
26
|
+
|
|
27
|
+
Assets go in `assets/` under the working directory, so run every command from the same
|
|
28
|
+
place or set `SPRITEGEN_ASSETS` to say where they live. `status` reads that directory: it
|
|
29
|
+
gives every asset, the stage that completed last, and the stages that could run now.
|
|
30
|
+
|
|
31
|
+
**If nobody named an asset, resume the one in the middle rather than opening a new one.**
|
|
32
|
+
If there is no half-finished asset, ask what to generate instead of choosing.
|
|
33
|
+
|
|
34
|
+
## What a sprite's workspace holds
|
|
35
|
+
|
|
36
|
+
Everything about one sprite is under `spritegen/assets/<sprite>/`, in directories named
|
|
37
|
+
after **what the thing is** rather than after the stage that made it:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
prompts/ anchor.v1.md anchor.v2.md video.v1.md
|
|
41
|
+
box-art/ anchor/ icon/
|
|
42
|
+
frames/ cutout/
|
|
43
|
+
sheet/as-is/ sheet/sharp/ sheet/pixel-art/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Box art and the anchor belong to the same sprite, so they live in the same directory —
|
|
47
|
+
`anchor --kind box-art` rather than a second asset. The same sheet closed in two art
|
|
48
|
+
directions is two directories under `sheet/`, and **neither of them is the sheet**.
|
|
49
|
+
|
|
50
|
+
**`spritegen show <sprite>`** answers what exists, where, and which prompt version made
|
|
51
|
+
it, without opening a directory. `--json` is the same answer for a program.
|
|
52
|
+
|
|
53
|
+
**Prompts are kept and versioned.** The text is copied into the sprite before the paid
|
|
54
|
+
call, so a `--prompt-file` from outside cannot be edited out from under the record. The
|
|
55
|
+
same text twice is one version; an edit is a new one and the old text stays.
|
|
56
|
+
|
|
57
|
+
## Pick the route before spending anything
|
|
58
|
+
|
|
59
|
+
| What was asked for | Route |
|
|
60
|
+
|---|---|
|
|
61
|
+
| An item icon, a HUD piece, a single static sprite | `anchor --kind icon`, and stop |
|
|
62
|
+
| Box art, concept art, a look to settle before a character exists | `anchor --kind box-art`, then feed it to the anchor as `--ref` |
|
|
63
|
+
| A character that has to move: walk, idle | the pipeline — `anchor`, then `motion` or `video`, `matte`, `board` |
|
|
64
|
+
| A movement that starts somewhere the anchor is not: attack, cast, death | the same, with `pose` between the anchor and the movement |
|
|
65
|
+
|
|
66
|
+
All of them are the same stage writing into different directories of the same sprite. The
|
|
67
|
+
difference is what the image is for, and whether anything runs after it.
|
|
68
|
+
|
|
69
|
+
## The pipeline
|
|
70
|
+
|
|
71
|
+
<!-- generated: stages -->
|
|
72
|
+
|
|
73
|
+
`motion` and `video` are alternatives: both hand frames to `matte`, which takes whichever
|
|
74
|
+
of them completed most recently. **Prefer `motion`** — its movement comes from a reference
|
|
75
|
+
sheet that has already been measured, where `video` asks a model to invent a cycle. The
|
|
76
|
+
number is under *Movement* below.
|
|
77
|
+
|
|
78
|
+
## Generate cheap, finish local
|
|
79
|
+
|
|
80
|
+
This is the whole cost strategy, and it is why the defaults look low.
|
|
81
|
+
|
|
82
|
+
**A paid call buys composition and identity. It does not have to buy resolution or a
|
|
83
|
+
clean edge**, because both of those are local now:
|
|
84
|
+
|
|
85
|
+
- **`spritegen upscale <sprite>`** enlarges an artifact with Real-ESRGAN on this machine.
|
|
86
|
+
Free, no ledger line, and the original is kept as `<name>.raw.png` so a second run
|
|
87
|
+
starts from it rather than compounding the model's invention twice.
|
|
88
|
+
- **`matte --backend local`** cuts the background with BiRefNet through `rembg` — the same
|
|
89
|
+
family of model the paid endpoint runs, on the GPU, for nothing. It is the default.
|
|
90
|
+
|
|
91
|
+
So `anchor --quality low` and `video --resolution 480p` are the defaults on purpose. Take
|
|
92
|
+
the cheap tier, then enlarge. Both local steps need an optional extra
|
|
93
|
+
(`spritegen-cli[upscale]`, `spritegen-cli[matte]`) and say so when it is missing.
|
|
94
|
+
|
|
95
|
+
## Before you spend
|
|
96
|
+
|
|
97
|
+
The remaining paid stages are `anchor`, `motion` and `video`, and they are not cheap.
|
|
98
|
+
|
|
99
|
+
1. **Say what the first paid call costs and what it decides, before making it.** On the
|
|
100
|
+
pipeline route the anchor is the extreme case: identity comes from that one image, so an
|
|
101
|
+
anchor that came out wrong wastes every call after it. Show it and get agreement before
|
|
102
|
+
running `motion`.
|
|
103
|
+
2. **`--dry-run` first, on any paid stage.** It prints the exact payload and spends
|
|
104
|
+
nothing. It also cannot advance an asset, so a dry run leaves `status` untouched.
|
|
105
|
+
3. **`spritegen cost <asset>`** says what has been spent already, read from that
|
|
106
|
+
asset's `ledger.jsonl` and nothing else — still right for an asset whose files were
|
|
107
|
+
deleted.
|
|
108
|
+
|
|
109
|
+
`board` and `upscale` are free and local, and `matte` is free on its local backend. A row
|
|
110
|
+
that came out wrong costs nothing to rebuild from frames that were paid for once, so
|
|
111
|
+
re-run `board` with a different `--scale`, `--grid` or `--art` rather than regenerating
|
|
112
|
+
anything.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
# Route one — a single image
|
|
117
|
+
|
|
118
|
+
`anchor` is a general image stage: a prompt, optional references, a flat background cut to
|
|
119
|
+
alpha, and the native pixel grid recovered afterwards. An item icon *is* one `anchor` call.
|
|
120
|
+
So is a HUD piece, a portrait, or box art. Open the asset, run one stage, stop — `status`
|
|
121
|
+
will keep offering `motion` and `video`, and for a static asset there is nothing to run.
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
spritegen new iron-sword
|
|
125
|
+
spritegen anchor iron-sword --kind icon --prompt-file sword.md --transparent --pixelart --count 4
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Generate large and let `--pixelart` bring it down.** The endpoint refuses anything under
|
|
129
|
+
about 655,000 pixels and rounds each side to a multiple of 16, so a 64 px icon cannot be
|
|
130
|
+
asked for directly. Ask for `1024x1024`, describe the icon as drawn at a small native
|
|
131
|
+
resolution, and let `--pixelart` recover that grid. `--scale` then upsizes by an integer
|
|
132
|
+
factor with no resampling.
|
|
133
|
+
|
|
134
|
+
**Cut the background, do not hope for transparency.** `--transparent` puts the chroma field
|
|
135
|
+
in the prompt and cuts it to alpha afterwards. `--chroma` defaults to `00b140`, chroma
|
|
136
|
+
green, far from skin, steel, fire and stone; change it if the subject is green, and say in
|
|
137
|
+
the prompt that nothing in the subject uses that colour. `--chroma-mode flood` takes only
|
|
138
|
+
what the border reaches, which is what keeps an enclosed hole — the ring of a hilt, a
|
|
139
|
+
window in a HUD frame — from being punched out; `global` takes the key anywhere.
|
|
140
|
+
`--despill` pulls the leaked key out of edge pixels.
|
|
141
|
+
|
|
142
|
+
**`--count 4` is four candidates for one prompt.** The cheapest place in the whole tool to
|
|
143
|
+
be picky.
|
|
144
|
+
|
|
145
|
+
What changes between the kinds:
|
|
146
|
+
|
|
147
|
+
| `--kind` | Size | Pixel grid | Background |
|
|
148
|
+
|---|---|---|---|
|
|
149
|
+
| `icon` — item, HUD piece | square, one object, centred, filling the frame | `--pixelart`, small native resolution | `--transparent` |
|
|
150
|
+
| `anchor` — a sprite | square or portrait | see route two; usually **no** `--pixelart` | `--transparent` |
|
|
151
|
+
| `box-art` — illustration | large, `landscape_4_3` or `portrait_4_3` | **no** `--pixelart` — it is not a sprite | keep the scene; it is art, not an asset |
|
|
152
|
+
|
|
153
|
+
**`--pixelart` here recovers a grid the art already has.** It is right for an icon drawn
|
|
154
|
+
as flat blocks and wrong for anything else — on a smooth render the detector votes on
|
|
155
|
+
nothing and returns nonsense. The report's `cols` and `rows` are how you check a grid was
|
|
156
|
+
there at all.
|
|
157
|
+
|
|
158
|
+
Box art is worth one image before a character exists: it settles the silhouette, the
|
|
159
|
+
palette, which shoulder the scabbard is on, what the hair does — things a 166 px sprite is
|
|
160
|
+
too small to argue about. Then it becomes the character's identity reference.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
# Route two — an animated character
|
|
165
|
+
|
|
166
|
+
## 1 · The anchor — the one image everything else inherits
|
|
167
|
+
|
|
168
|
+
The character, once, standing still. Every later stage animates *this image*, so identity
|
|
169
|
+
is decided here and nowhere else.
|
|
170
|
+
|
|
171
|
+
- **Neutral, facing south.** Straight at the camera, weight even, both feet planted and
|
|
172
|
+
flat, arms down. No swing, no cast, no spell lit, no weapon raised. A pose-driven
|
|
173
|
+
endpoint reads the anchor as the rest state it deforms from; an anchor caught mid-swing
|
|
174
|
+
puts that swing into every frame of the walk.
|
|
175
|
+
- **The weapon hangs clear of the body**, down along the side and angled out, whole blade
|
|
176
|
+
visible, crossing no part of the figure. A blade drawn across the torso merges with it at
|
|
177
|
+
166 px and the matte cuts them out as one shape.
|
|
178
|
+
- **Fill the frame, feet to hair.** The row stage scales the whole set by one transform read
|
|
179
|
+
from the box that holds every frame, so a figure sitting small in its frame arrives small
|
|
180
|
+
in the sheet cell.
|
|
181
|
+
### Do not ask for pixel art here
|
|
182
|
+
|
|
183
|
+
This is the change that matters most, and it goes against the obvious instinct.
|
|
184
|
+
|
|
185
|
+
**The anchor is a clean, sharp render in the target art direction — not pixel art.** Ask
|
|
186
|
+
for flat blocks and you get an anchor a video model cannot animate: it deforms blocks
|
|
187
|
+
rather than a drawing, and what comes back is six similar characters instead of one
|
|
188
|
+
character moving. It was measured — an anchor at 23 colours in ~7 px blocks produced a
|
|
189
|
+
walk that did not hold together, and the same figure rendered sharp did.
|
|
190
|
+
|
|
191
|
+
The second reason is that a target's own sheet is usually not blocky either. A 166 px
|
|
192
|
+
cell can carry thousands of colours and a real anti-aliased edge; "pixel art" is one art
|
|
193
|
+
direction among several, and the tool supports it as a direction rather than assuming it.
|
|
194
|
+
|
|
195
|
+
So ask for **the game's proportions and palette discipline, rendered crisply**: hard
|
|
196
|
+
readable silhouette, flat-ish shading in a few steps, no photographic depth of field, no
|
|
197
|
+
soft glow, no film grain — but a normal sharp raster, not blocks on a grid. Generate large
|
|
198
|
+
(`1024x1024`), at `--quality low`, and let the local upscale and the local matte do the
|
|
199
|
+
finishing.
|
|
200
|
+
|
|
201
|
+
**Pixel art, if the project wants it, is decided at the end and locally.** `board --art
|
|
202
|
+
pixel-art` recovers a grid; `board --art sharp` lands the crisp render on the cell. Both
|
|
203
|
+
are free, both are re-runnable, and both can exist for one sprite at the same time.
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
spritegen anchor <character> --kind box-art --prompt-file boxart.md --quality low
|
|
207
|
+
spritegen anchor <character> --prompt-file anchor.md --ref <sprite>/box-art/box-art.png --transparent --count 4
|
|
208
|
+
spritegen upscale <character> --artifact anchor --scale 2
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 2 · The four directions
|
|
212
|
+
|
|
213
|
+
Outfits are usually drawn south, west and east, with west being east mirrored. The anchor
|
|
214
|
+
is south; the others are anchors of their own, one asset each, taking the south anchor as
|
|
215
|
+
their identity reference:
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
spritegen new <character>-east
|
|
219
|
+
spritegen anchor <character>-east --prompt-file east.md \
|
|
220
|
+
--ref <assets>/<character>/anchor/anchor.png
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Each prompt says only what changed: the same character, seen from the east, the same
|
|
224
|
+
palette and proportions. **Do not try to turn a character with `motion`** — a pose-driven
|
|
225
|
+
endpoint moves the figure, it does not rotate it.
|
|
226
|
+
|
|
227
|
+
**West is east flipped, and that is where asymmetry bites.** A scabbard on one hip, a single
|
|
228
|
+
bracer, a braid over one shoulder, the hand holding the weapon — flipping moves every one of
|
|
229
|
+
them to the wrong side. Fix them after the flip, or generate west as its own anchor. In
|
|
230
|
+
motion nobody sees which hip the sword is on; everybody sees it swap hips between two
|
|
231
|
+
directions.
|
|
232
|
+
|
|
233
|
+
## 3 · `pose` — where an animation starts, when the anchor is not it
|
|
234
|
+
|
|
235
|
+
**Skip this for a walk or an idle.** The anchor already is where those start, and a pose
|
|
236
|
+
would be a paid call for an image you have.
|
|
237
|
+
|
|
238
|
+
Reach for it when the movement begins somewhere the anchor is not: an attack begins with
|
|
239
|
+
the weapon already drawn back, a cast with the hands already raised. Asking a video model
|
|
240
|
+
to introduce the weapon *and* the movement in one call asks for two things, and identity
|
|
241
|
+
is the one that gets dropped — the character comes back holding a different sword.
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
spritegen pose <character> --animation attack --prompt-file attack_start.md --transparent
|
|
245
|
+
spritegen video <character> --pose attack --prompt-file swing.md --model seedance
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
- **One pose per animation**, in `pose/<animation>/`. The anchor is always its first
|
|
249
|
+
reference, which is what keeps the character the same character. **`status` offers
|
|
250
|
+
`pose` once and then stops**, because how many animations a sprite wants is unbounded
|
|
251
|
+
and it could never say "complete" otherwise — make another whenever you need one, and
|
|
252
|
+
`show` lists the ones that exist.
|
|
253
|
+
- **The last frame is the first, copied.** `end.png` is `start.png` unless you pass
|
|
254
|
+
`--end-prompt`, because a cycle that ends where it began is the ordinary case and a
|
|
255
|
+
second paid call for the same image buys nothing but drift between the two ends.
|
|
256
|
+
`--no-end` for a movement that does not return — a death. On such a pose, `--loop` on
|
|
257
|
+
the video still means what it always meant, and closes the clip on the start frame.
|
|
258
|
+
- **`video --pose` sends both ends.** `start.png` as the first frame, `end.png` as the
|
|
259
|
+
last where the endpoint takes one, which is what `--loop` was approximating with the
|
|
260
|
+
anchor. `motion --pose` uses the start frame as the image the movement is applied to;
|
|
261
|
+
there is no last frame there, because a pose-driven endpoint deforms one image.
|
|
262
|
+
|
|
263
|
+
## 4 · Movement
|
|
264
|
+
|
|
265
|
+
**Use `motion`.** It builds a clip locally out of a reference sheet the project already
|
|
266
|
+
has and hands it to a pose-driven endpoint together with the anchor: identity from the anchor,
|
|
267
|
+
movement from the clip — movement that was measured rather than invented.
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
spritegen motion <character> --sheet <path>/<reference_sheet>.png --row 1 --frames 6
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`--row` is an animation, and the sheet says which is which: the JSON written beside it lists
|
|
274
|
+
`animations[]` with a `row`, a `name` and a step count. Read it rather than guessing: which
|
|
275
|
+
row holds which animation is the sheet's business, not a convention to assume.
|
|
276
|
+
|
|
277
|
+
`--frames` is how many frames come out. **Match the reference sheet, not a tutorial's
|
|
278
|
+
advice**: a six-step row is six frames, and `board --grid 3x2` closes them. `--pick
|
|
279
|
+
0,4,9,14,19,24` names exact indices when the even sample lands badly; `--start` and `--end`
|
|
280
|
+
narrow the window it samples from.
|
|
281
|
+
|
|
282
|
+
**Why not prompt an image model for the grid of frames.** That is the natural thing to try,
|
|
283
|
+
and it was tried: asking for a 3x2 grid of walk frames moved the head-and-torso region 0.25
|
|
284
|
+
between steps against 0.11 for the reference sheet, because the model redraws the character
|
|
285
|
+
in every cell instead of moving it. The result reads as six similar characters rather than
|
|
286
|
+
one character walking. There is deliberately no stage for it.
|
|
287
|
+
|
|
288
|
+
**`video` is the fallback and the most expensive call here** — billed by second of output.
|
|
289
|
+
Reach for it when there is no sheet row for the movement: an attack, a cast, a death.
|
|
290
|
+
Keep it in place and say so, say no camera movement, close the cycle where it began —
|
|
291
|
+
`--pose` when the movement starts somewhere the anchor is not, `--loop` when it does not, and remember that an image-to-video clip's first frame is the input image standing
|
|
292
|
+
still — start the sample after it rather than at `0`.
|
|
293
|
+
|
|
294
|
+
## 5 · `matte` — cutting the background
|
|
295
|
+
|
|
296
|
+
Segmentation, not a colour key: a chroma cut decides by distance to one colour, so it eats
|
|
297
|
+
art wherever the subject is near that colour and leaves halo wherever the key painted over
|
|
298
|
+
a thin contour. Hair is the worst of it — a strand is thinner than the tolerance band.
|
|
299
|
+
|
|
300
|
+
**`--backend local` is the default, and it costs nothing.** It runs BiRefNet through
|
|
301
|
+
`rembg` on this machine, which is the same family of model the paid endpoint runs. On a GPU
|
|
302
|
+
it is not slower; on a CPU it is, and it says so. Each frame is cut at its own full size,
|
|
303
|
+
with one session shared across all of them — which is where the single consistent edge
|
|
304
|
+
decision comes from.
|
|
305
|
+
|
|
306
|
+
`--backend fal` is the paid endpoint, for a machine with neither the extra nor a usable
|
|
307
|
+
GPU. There, every frame is joined into one image and cut in a single call, then taken back
|
|
308
|
+
apart: one charge instead of six, and one edge decision instead of six. What it costs is
|
|
309
|
+
resolution, because the endpoint operates at a fixed size. `--no-join` undoes that, at six
|
|
310
|
+
times the price.
|
|
311
|
+
|
|
312
|
+
Either way, edge decontamination is on and is what kills the coloured halo; if the figure
|
|
313
|
+
is losing its own outline instead, `--no-refine`.
|
|
314
|
+
|
|
315
|
+
## 6 · `board` — closing it into a sheet row
|
|
316
|
+
|
|
317
|
+
Free, local, and the stage to re-run rather than regenerate.
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
spritegen board <character> --grid 3x2 --frames 6 --art sharp
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**`--art` is the direction, and it is also the directory.** Three of them, and none is a
|
|
324
|
+
weaker version of another:
|
|
325
|
+
|
|
326
|
+
| `--art` | What it does | When |
|
|
327
|
+
|---|---|---|
|
|
328
|
+
| `sharp` | Lands the crisp render on the cell: reduces by the exact fraction that fits, then cuts the matte's smear off the alpha without making the outline binary | the art-direction anchor above — **this is the usual one** |
|
|
329
|
+
| `pixel-art` | Recovers a native grid the art already has and rewrites the frames on it | art that is genuinely blocky already |
|
|
330
|
+
| `as-is` | Neither | the art arrived in the direction it was wanted in |
|
|
331
|
+
|
|
332
|
+
Each writes `sheet/<direction>/`, so one sprite can carry more than one and you can look
|
|
333
|
+
at them side by side. `--colors N` quantises, over the whole row at once.
|
|
334
|
+
|
|
335
|
+
Three things it does that matter, each a way the animation breaks otherwise:
|
|
336
|
+
|
|
337
|
+
- **One grid and one palette over the whole row at once**, never per frame. Frame by frame,
|
|
338
|
+
each cell lands on its own and the sprite flickers.
|
|
339
|
+
- **Cells cut by the declared grid, not by islands of alpha.** The frames arrived in equal
|
|
340
|
+
cells; finding each figure by its alpha would lose where it sits inside its cell — and
|
|
341
|
+
where it sits *is* the movement.
|
|
342
|
+
- **One transform for the whole set.** Scale and offset come from the box holding every
|
|
343
|
+
frame, applied equally. Anchoring each frame on its own pushes the rising frame back down
|
|
344
|
+
and the walk stands still.
|
|
345
|
+
|
|
346
|
+
Cells are `--cell` px square, 166 by default. Under `sharp`, a figure larger than the cell
|
|
347
|
+
comes down to it; under the others it does not, and `warning: does not fit the cell` means
|
|
348
|
+
giving a smaller `--scale` or passing `--fit`. **Watch the GIF it writes beside the row** —
|
|
349
|
+
a slide, a hitch or a limb popping shows up in the loop and not in the still.
|
|
350
|
+
|
|
351
|
+
## 7 · Afterwards
|
|
352
|
+
|
|
353
|
+
The row is a sheet row, and that is where this tool stops. Packing it into an atlas and
|
|
354
|
+
getting it in front of a player belongs to the project the row is for; so does building the
|
|
355
|
+
reference sheet `motion` drives from. Both are upstream or downstream of spritegen rather
|
|
356
|
+
than stages of it.
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
# When it comes out wrong
|
|
361
|
+
|
|
362
|
+
| What you see | Where it came from |
|
|
363
|
+
|---|---|
|
|
364
|
+
| The animation is six similar characters, not one moving | a pixel-art anchor. Generate the anchor sharp and take the pixel art at `board --art` |
|
|
365
|
+
| `board --art pixel-art` returned nonsense, `native` looks wrong | there was no grid to recover; the art is smooth, so `--art sharp` is the one |
|
|
366
|
+
| The icon came back at the wrong size | the endpoint's minimum area; generate large, recover the grid with `--pixelart` |
|
|
367
|
+
| A hole in the subject was punched out | `--chroma-mode global`; use `flood`, which takes only what the border reaches |
|
|
368
|
+
| A coloured fringe | the chroma leaked into the edge; `--despill`, and check the subject never uses that colour |
|
|
369
|
+
| Halo around a matted figure | matte edge refinement; leave it on, and check the chroma |
|
|
370
|
+
| A dark rim after `upscale` | should not happen — the transparent RGB is filled before the network sees it. Report it |
|
|
371
|
+
| The character changes between frames | a grid prompt instead of `motion`, or `matte`/`board` run per frame |
|
|
372
|
+
| It flickers | the grid or palette was applied per frame; re-run `board` over the whole set |
|
|
373
|
+
| It slides instead of walking | the movement was not in place — a `video` prompt that let the camera or the figure travel |
|
|
374
|
+
| The figure is tiny in its cell | the anchor did not fill its frame |
|
|
375
|
+
| It does not fit the cell | `--art sharp`, or `--fit`, or a smaller `--scale` |
|
|
376
|
+
| The sword changed hips | a mirrored direction with an asymmetric prop |
|
|
377
|
+
| The attack starts from a neutral stance | no `--pose`; the clip began at the anchor |
|
|
378
|
+
| The weapon appears out of nowhere in frame one | the video call was asked to introduce the weapon and the movement at once. Generate the pose first |
|
|
379
|
+
| The clip does not return to where it started | the endpoint takes no last frame, or the pose was made with `--no-end` |
|
|
380
|
+
| The character changed after re-running an earlier stage | `--force` on `anchor` invalidates every artifact that quoted it — poses, frames, the row. Nothing tracks that; re-run them, in order |
|
|
381
|
+
| `status` shows nothing and the files are there | an older layout; `spritegen migrate` |
|
|
382
|
+
| `show` reports drift | a file was added or removed by hand. Nothing is rewritten for you; decide which side is right |
|
|
383
|
+
| `the upscale needs torch` / `the local matte needs rembg` | the optional extra is not installed; the message names the command |
|
|
384
|
+
| It runs on the CPU and takes minutes | onnxruntime or torch has no GPU build here |
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
# Prompt skeletons
|
|
389
|
+
|
|
390
|
+
`--prompt-file` sends the file verbatim, so copy a skeleton, fill every `<slot>`, and drop
|
|
391
|
+
what does not apply — an over-specified prompt fights itself.
|
|
392
|
+
|
|
393
|
+
## An item icon or HUD piece
|
|
394
|
+
|
|
395
|
+
> True pixel art. A single `<the object>` and nothing else: one object, centred, upright,
|
|
396
|
+
> filling the frame, seen `<straight on / at a slight three-quarter angle>`. No character, no
|
|
397
|
+
> hand holding it, no ground, no scene, no shadow cast onto anything.
|
|
398
|
+
>
|
|
399
|
+
> `<Describe the object: its material, its parts, its trim, what is worn or damaged.>`
|
|
400
|
+
>
|
|
401
|
+
> Resolution — this governs everything: it is drawn at a native resolution of roughly `<32>`
|
|
402
|
+
> art pixels square, then shown enlarged with nearest-neighbour scaling, so every art pixel
|
|
403
|
+
> is a large solid square block of exactly one flat colour, all the same size, aligned to one
|
|
404
|
+
> strict square grid, edges perfectly straight and perfectly hard. No anti-aliasing, no blur,
|
|
405
|
+
> no gradient, no airbrush, no smooth shading, no glow, no glossy specular highlight, no drop
|
|
406
|
+
> shadow, no partially transparent pixel. Shading steps between a small number of flat tones.
|
|
407
|
+
> Diagonals appear as stair steps of whole blocks.
|
|
408
|
+
>
|
|
409
|
+
> Palette: at most `<sixteen>` flat colours in the whole image, hard borders between
|
|
410
|
+
> neighbouring colour areas. `<The colours that matter.>`
|
|
411
|
+
>
|
|
412
|
+
> Background: one single flat colour, uniform across the whole image, touching no part of the
|
|
413
|
+
> object's own palette.
|
|
414
|
+
>
|
|
415
|
+
> No text, no watermark, no border, no frame, no grid lines drawn over the art.
|
|
416
|
+
|
|
417
|
+
## Box art
|
|
418
|
+
|
|
419
|
+
`anchor --kind box-art`. Not a sprite: no native resolution, no palette cap, no
|
|
420
|
+
`--pixelart`. Say what the character is, what they wear and carry, the mood and the light,
|
|
421
|
+
and ask for a full-body illustration against a plain background. Its only job is to be the
|
|
422
|
+
identity reference the anchor quotes, and it lives in the same sprite's directory.
|
|
423
|
+
|
|
424
|
+
## A character anchor
|
|
425
|
+
|
|
426
|
+
**The one that changed.** No block language, no native resolution, no palette cap — this
|
|
427
|
+
image is animated, and a model deforms a drawing far better than it deforms blocks. What
|
|
428
|
+
it *does* say is everything about the art direction that is not resolution: proportions,
|
|
429
|
+
flat shading, hard silhouette, no photographic finish.
|
|
430
|
+
|
|
431
|
+
> `<One reference image is supplied. It is the character, and it is used for identity only:
|
|
432
|
+
> take from it EVERY IDENTIFYING DETAIL — hair colour and how it is worn, eyes, the garment
|
|
433
|
+
> and its colours, the armour pieces and their seams, the belt, the footwear, the weapon and
|
|
434
|
+
> its grip and guard, which hand holds it, which hip the scabbard sits on. Take nothing of
|
|
435
|
+
> how it is drawn, nothing of its lighting, and nothing of its background.>`
|
|
436
|
+
>
|
|
437
|
+
> A single top-down RPG character sprite for a tile-based mobile MMORPG, one character only,
|
|
438
|
+
> centred, standing still in a neutral idle pose and facing south, straight toward the
|
|
439
|
+
> camera.
|
|
440
|
+
>
|
|
441
|
+
> Rendering — this governs everything: crisp, clean 2D game art with hard, precise edges and
|
|
442
|
+
> a silhouette that reads instantly at small size. Flat cel shading in a small number of
|
|
443
|
+
> tone steps, each step a clear area rather than a blend. No photographic realism, no depth
|
|
444
|
+
> of field, no bloom, no lens flare, no film grain, no ambient glow, no soft focus, no
|
|
445
|
+
> painterly brush texture, no drop shadow cast onto anything. Colours are saturated and
|
|
446
|
+
> separated: neighbouring areas differ enough to stay distinct when the image is reduced.
|
|
447
|
+
>
|
|
448
|
+
> `<Do NOT ask for pixel art, for a native resolution, for blocks, for nearest-neighbour
|
|
449
|
+
> scaling or for a palette cap. This image is going to be animated, and blocks animate
|
|
450
|
+
> badly. The pixel treatment happens afterwards, locally.>`
|
|
451
|
+
>
|
|
452
|
+
> Proportions: a squat, big-headed game sprite. The head including `<the hair>` is about
|
|
453
|
+
> `<forty>` percent of the figure's total height. Narrow shoulders, a short blocky torso,
|
|
454
|
+
> short thick arms and legs, simple chunky hands and feet. The figure stands upright and
|
|
455
|
+
> fills the frame from `<the top of the head>` to `<the soles of both feet>`, feet flat and
|
|
456
|
+
> planted slightly apart.
|
|
457
|
+
>
|
|
458
|
+
> Camera: roughly forty-five degree top-down three-quarter view, seen slightly from above
|
|
459
|
+
> while still facing the viewer. The camera does not tilt and the figure is not foreshortened.
|
|
460
|
+
>
|
|
461
|
+
> Palette: `<the five or six colours that matter>`, used in flat areas with clean borders
|
|
462
|
+
> between them.
|
|
463
|
+
>
|
|
464
|
+
> Silhouette: `<what keeps the figure from reading as one solid slab — a garment cut short so
|
|
465
|
+
> both legs read as separate shapes, a break at the top of the silhouette.>` In `<the right>`
|
|
466
|
+
> hand, held down along the side and angled out from the body so the whole `<blade>` is
|
|
467
|
+
> visible and crosses no part of the figure: `<the weapon, described>`. `<The other>` hand
|
|
468
|
+
> hangs open and empty. `<The scabbard sits at the belt on the opposite hip.>`
|
|
469
|
+
>
|
|
470
|
+
> Background: one single flat colour, uniform across the whole image, touching no part of the
|
|
471
|
+
> figure's own palette.
|
|
472
|
+
>
|
|
473
|
+
> No text, no watermark, no border, no frame, no grid lines drawn over the art.
|
|
474
|
+
|
|
475
|
+
### If the project really does want blocks in the anchor
|
|
476
|
+
|
|
477
|
+
It is the wrong trade for anything that moves, and the reason is above. For a **static**
|
|
478
|
+
sprite that will never be animated, the icon skeleton's resolution paragraph is the one to
|
|
479
|
+
paste in, together with `--pixelart` — prompt and flag, never one of them. Prompt alone
|
|
480
|
+
gives a smooth render that merely looks blocky; the flag alone gives a clean grid over
|
|
481
|
+
mush.
|
|
482
|
+
|
|
483
|
+
## An animation's starting pose
|
|
484
|
+
|
|
485
|
+
The anchor's skeleton, minus everything about the character, plus what changed. Its whole
|
|
486
|
+
job is to be the same character in a different position, so most of it is a refusal to
|
|
487
|
+
change anything.
|
|
488
|
+
|
|
489
|
+
> One reference image is supplied. It is the character, and everything about the character
|
|
490
|
+
> comes from it and only from it: `<hair, eyes, the garment and its colours, the armour
|
|
491
|
+
> pieces, the belt, the footwear, the weapon and its grip, which hand holds it, which hip
|
|
492
|
+
> the scabbard sits on>`. Same palette, same proportions, same rendering, same camera.
|
|
493
|
+
>
|
|
494
|
+
> Only the pose changes. `<The character has drawn the sword back over the right shoulder,
|
|
495
|
+
> both hands on the grip, weight shifted onto the back foot, torso turned slightly away
|
|
496
|
+
> from the camera, the blade angled up and clear of the head so its whole length is
|
|
497
|
+
> visible against the background.>`
|
|
498
|
+
>
|
|
499
|
+
> The character still faces `<south, toward the camera>` and still fills the frame from
|
|
500
|
+
> the top of the head to the soles of both feet.
|
|
501
|
+
>
|
|
502
|
+
> Nothing is added and nothing is taken away — no effects, no particles, no glow, no
|
|
503
|
+
> motion blur, no trails, no added light, no impact lines.
|
|
504
|
+
>
|
|
505
|
+
> Background: one single flat colour, uniform across the whole image, touching no part of
|
|
506
|
+
> the figure's own palette.
|
|
507
|
+
>
|
|
508
|
+
> No text, no watermark, no border, no frame.
|
|
509
|
+
|
|
510
|
+
## A video movement
|
|
511
|
+
|
|
512
|
+
Four things carry the whole prompt and none are optional: **in place**, **no camera
|
|
513
|
+
movement**, **the loop closes**, **the character does not change**.
|
|
514
|
+
|
|
515
|
+
> The character in the supplied image performs `<one walk cycle / one sword swing and
|
|
516
|
+
> recovery / one casting gesture>`, and nothing else happens in the clip.
|
|
517
|
+
>
|
|
518
|
+
> The character stays exactly where it is. It moves in place: it does not travel across the
|
|
519
|
+
> frame, does not step toward or away from the camera, and does not drift in any direction.
|
|
520
|
+
> It faces `<south, straight toward the camera>` for the entire clip. It never turns, never
|
|
521
|
+
> rotates, never shows a `<side or back>` view.
|
|
522
|
+
>
|
|
523
|
+
> The camera does not move. No pan, no zoom, no dolly, no orbit, no shake, no change of
|
|
524
|
+
> framing or focal length. The framing at the last frame is the framing at the first.
|
|
525
|
+
>
|
|
526
|
+
> The clip is one complete cycle and it loops: the final pose returns to the starting pose,
|
|
527
|
+
> so the last frame runs into the first with no jump.
|
|
528
|
+
>
|
|
529
|
+
> The character does not change. Same `<colours, palette, proportions, garment, armour,
|
|
530
|
+
> weapon and how it is held>` as the supplied image, in every frame. Nothing added, nothing
|
|
531
|
+
> taken away — no effects, no particles, no glow, no motion blur, no trails, no added light.
|
|
532
|
+
>
|
|
533
|
+
> The movement itself: `<alternating leg steps, a small vertical bob, a small arm swing, the
|
|
534
|
+
> hair swaying with the step. The blade stays clear of the body throughout.>`
|
|
535
|
+
>
|
|
536
|
+
> The background stays one single flat colour, uniform and unchanged across every frame, with
|
|
537
|
+
> nothing in it: no scenery, no ground plane, no shadow cast onto it, no gradient, no
|
|
538
|
+
> vignette. Nothing in the character uses that colour.
|
|
539
|
+
>
|
|
540
|
+
> No text, no watermark, no border, no frame, no user interface.
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
# Every option
|
|
545
|
+
|
|
546
|
+
Read out of the CLI's own stage registry when this file was written, so it describes the
|
|
547
|
+
spritegen that wrote it rather than one someone remembers.
|
|
548
|
+
|
|
549
|
+
<!-- generated: options -->
|
|
550
|
+
|
|
551
|
+
<!-- generated: endpoints -->
|
|
552
|
+
|
|
553
|
+
<!-- generated: free -->
|