A side-scroller needs two families of image assets no single generation gives: pixel sprites that
animate cleanly on one feet line, and painted level layers that stack into parallax and repeat
without seams. This route comes from a browser side-scroller made in one agent session (one hero,
two ground enemies, five levels):
The finish is local on purpose: keying, the loop search, the shared palette and the seamless
cross-fade need pixels on disk, and the deliverables are game files. If the user wants the finished
strips on the platform too, upload_asset them into a collection.
A user asks: "Make the art for my side-scroller: a fox knight hero with a rapier, a mole miner enemy
with a pickaxe, and two levels, a mushroom forest and a crystal mine." Pass team_id and
project_id on every call (the scenario skill covers picking them).
-
Hero still.
recommend { "capability": "txt2img", "prompt": "<the user's request>; needs reference image input, transparent output" },
model_schema_get the pick, price the
two-pose template (left:
standing ready facing right; right: mid-jump facing right) with
model_run { "model_id": "<pick>", "dry_run": true, "parameters": { "prompt": "...", "width": 1536, "height": 1024, "quality": "high", "background": "opaque", "numOutputs": 2 } }.
Tell the user the price, run (jobs_wait with its job_id if it returns in progress),
asset_display both takes; keep one with both poses on model, in a pure side profile (every clip
inherits a three-quarter body), and nothing pink or purple, asset_download it and curl -L it
to fox_two_pose.png.
-
First frames. python3 scripts/reframe_stills.py fox_two_pose.png --name fox --out frames
writes frames/fox_rest.png (left pose, the first frame of every ground clip) and
frames/fox_action.png (the jump). Check both, then
upload_asset { "file_name": "fox_rest.png", "content_type": "image/png", "kind": "image", "file_size": <bytes> },
PUT the parts, upload_asset_complete { "upload_id": "<id>" }; same for the action frame, which
only the air spin uses.
-
Hero clips.
recommend { "capability": "img2video", "features": ["endImage"], "prompt": "<the user's request>; square clip, no audio" },
then model_schema_get. One payload per cycle from the
motion templates. With the
build's schema:
run: { "prompt": "<run sentence> <facing and tail>", "negativePrompt": "<negative>, slowing down, stopping, standing still",
"startImage": "<fox_rest id>", "duration": "3", "aspectRatio": "1:1", "generateAudio": false }
atk1: { "prompt": "<attack: a fast rapier thrust ... returns to the starting ready pose> <facing and tail>", "negativePrompt": "<negative>",
"startImage": "<fox_rest id>", "endImage": "<fox_rest id>", "duration": "3", "aspectRatio": "1:1", "generateAudio": false }
Idle and hurt pin like the attack; the air spin uses the action id as both frames. Price each
distinct payload with dry_run: true (first frame only, pinned, changed guidance), give the user
the total, launch the clips with "wait": false in waves within the team's concurrency ceiling
(the parallel-custom-jobs row in the scenario skill: a launch refused with that 429 created
no job, so relaunch it in the next wave instead of dropping it), and collect them with one
jobs_wait { "job_ids": [...] }, re-called with the returned pending_job_ids as job_ids
while any is in progress (never poll job_get). asset_download each (omit format on video)
and save as clips/fox_<cycle>.mp4, <cycle> being exactly the step 5 --cycles name (run,
idle, atk1, spin, hurt). Review each as a local contact sheet
(ffmpeg -i clips/fox_run.mp4 -vf "fps=6,scale=240:-1,tile=6x3" fox_run_sheet.png), since
asset_display shows no frames of a video; re-run only one that turns toward or away from the
camera or travels.
-
Pose sheet. Text to image with referenceImages: ["<chosen still id>"] and the
pose-sheet template (fall, wall cling,
plunge, dash). Price, tell the user, run, download as fox_poses.png.
-
Strips.
python3 scripts/side_sprites.py --clips clips --name fox --cycles run:loop:8,idle:loop:8,atk1:attack:7,spin:attack:8,hurt:attack:5 --report
python3 scripts/side_sprites.py --clips clips --name fox --height 56 --palette 28 \
--cycles run:loop:8,idle:loop:8,atk1:attack:7,spin:attack:8,hurt:attack:5 \
--poses fox_poses.png --jump frames/fox_action.png --webp --out sprites
View the strips at 4x, nearest-neighbor. If the slash trail keyed into a white block, re-run with
--drop atk1=<index> (0-based) and --force.
-
Enemy. Same route: two-pose still (rest, and an attack wind-up that keeps the design
consistent), reframe, upload only mole_rest.png; walk with the first frame only, the
armed-enemy walk wording and a lower guidance
such as cfgScale: 0.7 if the schema has one; attack and hurt pinned.
side_sprites.py --clips clips --name mole --height 72 --cycles walk:loop:8,attack:attack:8,hurt:attack:5 --report;
a walk flagged as a weak loop gets --range walk=12:48 before any re-run.
-
Level layers. Fill the five
environment templates for the mushroom
forest (opaque background and texture, the rest transparent). dry_run each distinct setting,
tell the user the total, run, download as env/bg1.png, env/mid1.png, env/tex1.png,
env/ledge1.png, env/props1.png, then
python3 scripts/process_env.py --env env --out assets --levels 1. Put level 1 in the game with
the fox on it before generating the crystal mine; process that one alone with --levels 2, (a
bare 2 is a count and redoes level 1), --force after a re-render.
-
Check. Play each strip at its fps from <name>_meta.json, tile the texture across a wall,
and draw a long and a short platform.