Skip to content

Agent-driven asset loop

The Asset studio tabs let you drive vendor-API generation by hand. The agent-driven asset loop lets the agent do the same thing, and wire the result straight back into your chat with a one-click open-in-tool button. You ask, you wait a few seconds, you preview, you click into the editor to tweak.

This page covers the loop end-to-end. Reference docs for the underlying primitives:

The agent calls a Forge MCP tool. Forge runs the operation, saves the file under <project>/.forge/generated/<kind>/, and returns a ready-to-paste forge-link block. The agent drops the block in chat; the chat renders an inline preview card with a one-click open button.

ToolWhatTier
forge.list_voicesReturn the user’s ElevenLabs voice list (call before generate_voice)free
forge.generate_voiceElevenLabs TTSfree
forge.generate_sfxElevenLabs SFX (0.5–22s)free
forge.generate_musicElevenLabs Music (10–300s)paid
forge.generate_palette5-color palette from a curated theme or explicit hexeslocal
forge.generate_spritesheetPack pre-generated frames into one PNG + JSON descriptorlocal
forge.generate_tilesetProcedural tileset PNG (forest / dungeon / platformer / cave / scifi)local
forge.generate_tilemapProcedural Tiled .tmj using a tilesetlocal
forge.generate_shaderSave an agent-authored GLSL fragment shaderlocal
forge.generate_parallax_layersStack pre-generated layer images with per-layer scroll multiplierslocal
forge.generate_platformer_levelBundle tilemap + parallax + character into one level descriptor (tile-grid; best for top-down)local
forge.generate_platformer_scenePainted ground silhouette + entity spawn points + parallax (no tile grid; best for side-scrolling art)local
forge.generate_animation_clipsDefine named clips (idle / run / jump) against a sprite sheetlocal
forge.generate_dialog_treeBranching dialog tree with per-node voice idslocal

local = no vendor API call, no key needed. free and paid = ElevenLabs key required.

Ask “generate me a sunset palette” and the agent picks the curated sunset theme. The card renders an inline swatch row right in chat:

Chat showing a sunset palette card with five swatches: dark purple, magenta, persimmon red, orange, and amber yellow. An "Open in palette" button sits below the swatches, and a forge-propose ASSETS.md card logs the generation.

Click Open in palette and the palette tool opens with the sunset palette pre-loaded as a “Loaded palette” field, the first swatch seeded as the base color, and the harmony tools ready to derive variants:

Palette tool tab open with the loaded sunset palette displayed at the top. Base color seeded to the first swatch, split-comp harmony showing derived swatches, and a lightness ramp visible below.

“Build me a 50×30 forest level” triggers two MCP calls: tileset first, then tilemap. The chat gets two cards in document order — the tile strip preview and the mini-rendered map (each tile drawn at preview scale by reading the saved .tmj data array):

Chat showing two stacked cards: Forest Tileset with an 8-tile colored strip, and Forest Level 50×30 with a mini-rendered green tilemap showing scattered trees, paths, and grass patches. Below them, a forge-propose ASSETS.md card logs both files.

Clicking the tilemap card opens the tilemap editor with the tileset auto-loaded, the level data already painted, and the tile palette ready for further edits:

Tilemap editor showing the full 50×30 forest level painted: green grass with darker patches, scattered trees, dirt paths, and water tiles. Tile palette on the left with eight forest tiles plus an eraser. "1500 painted" indicator shows every cell hydrated.

Ask for a wave-distortion fragment shader. The agent writes the GLSL inline and saves it via forge.generate_shader. The card runs a live WebGL2 preview at ~30fps right in chat — no editor open required, and compile errors render in red inline:

Chat showing a Wave Distortion 01 Ripple shader card with an animated blue ripple pattern in a small canvas. Card stats show "fragment shader · 27 lines" and an "Open in shader" button to load the source into the sandbox for editing.

ElevenLabs free-tier SFX and TTS render as inline waveform cards with play buttons:

Chat showing two audio cards stacked: Impact SFX (1s) with a transient-decay waveform, and "Callum: Welcome, traveler" with a speech-rhythm waveform. Both have play buttons and "Open in trimmer" affordances. ASSETS.md card below logs both files with full attribution including voice ID and model.

“Generate 4 frames of a knight idle/run and pack them into a sheet” fires four image-gens (or one composite split, like the agent did here for visual consistency) → one generate_spritesheet call → optional generate_animation_clips. Two summary cards land in chat:

Chat showing a Knight Sprite Sheet card with the packed 2x2 atlas of knight frames, and an Animation clips card with the same sheet plus clip metadata. Both have open-in-tab buttons.

The agent’s clever move: a single composite image with all four poses kept the lighting + proportions consistent, then split into four PNGs before packing:

Source composite image showing four knight poses in a 2x2 grid on green background. Below it, an ASSETS.md propose card lists each frame&#x27;s saved path plus the spritesheet path with full metadata.

Click into both editor tabs and you see the sprite sheet builder side-by-side with the animation timeline — the latter cycling through your idle clip live:

Two editor tabs side by side: Sprite Sheet on the left with the 2x2 atlas preview, and Animation tab on the right showing one knight frame at fit-to-pane scale, two clips listed (idle and run) with their fps sliders, and a Stop button indicating the clip is currently playing.

“Build me a 4-layer forest dusk parallax” → four image-gens → generate_parallax_layers with the saved paths and per-layer scroll multipliers (sky=0, hills=0.2, trees=0.5, branches=1.0). The card shows a static stacked thumbnail composing all four layers at rest:

Chat showing a Forest Dusk Parallax card with a composed thumbnail: gradient sky gradient, dark tree silhouette mid-ground, and foreground branches stacked. Card stats show "4 layers · 800x320 · static thumbnail · drag in editor to scroll" with an "Open parallax" button.

The editor opens with each layer’s scroll multiplier + Y offset slider on the left rail; drag the canvas and the depth comes alive — sky stays still, branches track 1:1:

Parallax editor with four layer cards stacked in the left rail (sky, distant_hills, mid_trees, foreground_branches), each showing scroll multiplier and Y offset sliders. Big composed preview on the right showing the forest dusk scene at rest.

forge.list_voices returns the user’s actual voice list; the agent then assigns distinct voices to each speaker before saving the dialog tree. Each node’s Speak button hits ElevenLabs with the assigned voice:

Dialog tree tab showing a multi-node convo between Mira (a young scout) and Kai (a wary captain). Node list on the left rail, edit panel for the start node with Mira&#x27;s voice id and her opening line, audio player playing the line.

Every successful tool call returns the same shape:

{
"savedPath": "D:\\projects\\forest\\.forge\\generated\\sfx\\1746450000000.mp3",
"projectRelativePath": ".forge/generated/sfx/1746450000000.mp3",
"byteCount": 28345,
"forgeLinkBlock": "```forge-link\npath: ...\npreview: audio\n..."
}

The agent drops forgeLinkBlock verbatim into chat. The chat parses the fenced block and renders the right preview:

  • audio — waveform thumb + play/pause + open-in-trimmer button.
  • image — thumbnail + open-in-image-viewer button.
  • palette — inline swatch row + open-in-palette-tool button.
  • spritesheet — composed sheet thumbnail + open-in-builder.
  • tileset — strip preview + open-in-tilemap.
  • tilemap — mini-rendered map (each tile drawn at preview scale)
    • open-in-tilemap.
  • shader — live WebGL2 preview at ~30fps + open-in-sandbox.
  • parallax — static stacked layers + open-in-editor.
  • level — composed level thumbnail + open-the-level-preview.
  • platformerscene — painted-ground scene thumbnail + open-the-scene-preview.
  • animation — sheet preview + clip count.
  • dialog — node count + character count.

Click the button → the matching editor tab opens with the asset already loaded. No file picker, no copy-paste of paths.

A worked example: a forest level in three turns

Section titled “A worked example: a forest level in three turns”

You ask:

Build me a 60×20 forest level: tileset, populated tilemap, four-layer parallax background, and a hero sprite with idle / run animations.

The agent works through the chain:

1. forge.generate_tileset(theme="forest")
→ savedPath A (forest tileset PNG + .json)
→ drops forge-link card #1: "Forest tileset · 8 tiles · 32px"
2. forge.generate_tilemap(tileset_path=A, width=60, height=20)
→ savedPath B (.tmj with painted forest level)
→ drops forge-link card #2: "Forest level · 60x20 · forest"
3. (4× image-generation calls — sky, hills, trees, foreground)
forge.generate_parallax_layers(layers=[sky, hills, trees, fg])
→ savedPath C (parallax descriptor + thumbnail)
→ drops forge-link card #3: "Forest parallax · 4 layers · 800x320"
4. (8× image-generation calls — hero idle/run frames)
forge.generate_spritesheet(frames=[idle1, idle2, ..., run4])
→ savedPath D (packed sheet + descriptor)
→ drops forge-link card #4: "Hero sheet · 8 frames · 4x2 grid"
5. forge.generate_animation_clips(sheet_path=D, clips=[
{ name: "idle", frames: [0,1], fps: 6 },
{ name: "run", frames: [2,3,4,5,6,7], fps: 12 },
])
→ savedPath E (animation JSON)
→ drops forge-link card #5: "Hero animations · 2 clips"
6. forge.generate_platformer_level(
tilemap_path=B, parallax_path=C, character_sheet_path=D,
)
→ savedPath F (level descriptor + composed thumbnail)
→ drops forge-link card #6: "Forest level · parallax · character"

Six cards in chat, in document order, each clickable. You preview the tileset, then the populated level, then the parallax, then the hero animations cycling, then the bundled level scene with everything composed. You click into card #6 → the level preview tab opens with sky-hills-trees-foreground in the back, the painted tilemap on top, hero sprite at the default position. Drag → parallax depth, tilemap panning, hero anchored to the camera.

If you don’t like the layout: click card #2 → tilemap editor opens with the same tileset + map data, you repaint, re-export. Re-open card #6 to see the new composition.

For platformer-perspective levels (side-scrolling, parallax behind), prefer forge.generate_platformer_scene over generate_platformer_level — it ships a painted ground silhouette instead of a tile grid, so painted parallax stops fighting schematic blocks. See Platformer scenes for the full chain.

The agent’s forge-self.md skill tells it to pair every saved asset with a forge-propose ASSETS.md append in project mode, so your project’s memory keeps a durable log of what was generated, when, and what prompt produced it. The forge-link is for your eyes; the log is for the project’s memory.

  • Project source files: the asset loop never writes to src/ or Assets/. Generated files live under .forge/generated/ and the user copies them into their engine project explicitly. (Engines that use folder mirrors — Godot — pick them up automatically; Unity needs the explicit “Import to Assets/” button on each asset card.)
  • Code edits: those go through the existing forge-propose-edit per-hunk review flow. The asset loop is for content; code edits are for code.
  • Free-tier music: ElevenLabs Music is paid-only. The agent’s skill copy says to confirm with the user before calling generate_music if cost matters.
  • Edit the result. Every preview card opens its tab pre-loaded. The tools you’d use to author from scratch all support re-saving, so you can iterate on the agent’s output without starting over.
  • Override defaults. All tools accept a name and label. The curated theme tools accept overrides (colors, theme, seed).
  • Chain manually. You can call any tool independently — the agent prefers to chain, but each tool is standalone.
  • Disable the loop. Settings → MCP servers → toggle the forge entry off. The tools disappear from Codex’s tool list on next sidecar restart.

Every tool that takes a path argument accepts:

  • An absolute path (drive letter or POSIX root).
  • A project-relative path. Resolved against the active project’s root.
  • Project-relative paths require an active project; in open mode (no project), use absolute paths.

The chained workflow is simpler than it looks: each tool returns savedPath (absolute), and the agent passes that absolute path into the next tool. No path arithmetic needed.