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.