An AI agent such as Claude Code can work in the editor (#429). It works inside your open editor tab, not on the stored project: you see everything it does as it happens, and you take it back with Ctrl+Z like your own work. It speaks MCP (the Model Context Protocol) to a relay on the server, and the relay passes its tool calls to your tab.
The agent sees what you see, reads the project and changes it through the same commands your clicks run. Laying out the graphs it builds comes next (see the issue).
Setting it up
-
Make a token. Account menu (top right) → Agent tokens… → a name, a lifetime (30 days, 90 days or a year) → New token. The dialog shows the token once, with Copy token, and the line that sets it up in Claude Code, with Copy command:
claude mcp add --transport http feuerwerk https://feuerwerk.nockal.com/mcp --header "Authorization: Bearer fwa_..."The server keeps only a hash of the token; close the dialog without copying it and it is gone, make a new one.
-
Switch the agent on in the tab you want it to work in: account menu → Agent. A badge appears beside the account menu and shows how many agents are connected: an agent counts while it keeps its event stream open or has called a tool in the last two minutes. Claude Code opens spare sessions when it connects, they never call a tool and do not count. A click on the badge switches the agent off again. Follow agent right below decides whether the editor shows you what the agent changes (on unless you switch it off, see below).
-
Ask Claude Code about the editor. Without a tab switched on, every tool answers that no editor is connected and how to fix that.
Open the editor at https://feuerwerk.nockal.com/ for the agent. At nockal.com/feuerwerk/ the
proxy in front of the server passes the tab's WebSocket messages only one way, and the badge stays
at Agent offline. The agent itself reaches the relay at either address.
Tokens
- A token opens the relay for an agent of your account, and nothing else: no route of the API takes it, so it cannot read or write a project behind the tab's back.
- Agent tokens… lists your tokens with the day each was made, expires and was last used, and Revoke ends one at the agent's next request.
- Every token of an account ends when its password changes, also when an administrator sets it, and when the account is renamed or deleted.
- An account has at most 20. Wrong tokens count as wrong passwords: five from one address within 15 minutes lock that address out for 15 minutes.
- A guest (see Accounts) has no tokens and no Agent switch.
One tab at a time
The agent works in the tab of your account that switched it on last: switching it on in a second tab switches it off in the first, which says so. The switch is kept for the browser tab, so a reload (a deployment) comes back with the agent on, and signing out switches it off. If the connection to the relay is lost, the tab tries again on its own, every few seconds at first and then every 30; the badge says Agent offline meanwhile.
What the agent can do
| Tool | What it does |
|---|---|
get_view |
What you are looking at: the project, the tab and the document it shows, the selection with names (objects, nodes by type, frames, keys ...), the camera of the view, whether the game is playing or paused, tabs in windows of their own, and the menu or dialog on top (a menu by its first entries) |
screenshot |
The whole editor as drawn, as a PNG, at most maxWidth pixels wide (1280 unless asked otherwise) |
list_assets |
The project's settings (start scene, layers, play settings, master bus) and the assets with ids, names and types, by type or a part of the name |
list_files |
The pictures, typefaces, sounds or videos the server holds for your account, the demo material among them, whether a project uses them or not: file, upload name, size, a picture's size, a video's state, length, frame rate and sound, and the asset wearing it in this project. add_file_asset makes an asset of one, see below |
get_asset |
One asset as stored, with the rows of its properties and the named objects of a scene or container, the content of a placed container too (marked fromContainer, ids like <container object>~<path>). A graph is only counted, and so are the cells of a map past 400. Pixel art lists its palette as colors and, up to 16 384 pixels over all layers and frames, every layer of every frame as rows of characters (. is transparent, 1-9, a-z, A-Z the indices 1 to 61); a bigger one says how many pixels are painted. Colors of palettes and vector art read as #rrggbb. An animation lists what its rows may aim at (targets, the root as ""), with the properties each offers. Each track of a song carries its automation lanes and, under params, the parameters a lane of it can move, each with its default. Under usedBy: every asset naming it or one of its frames or clips, with the objects, nodes, items or keys in there that do, and the start scene, master FX or master routing of the project; empty when nothing uses it |
get_graph |
A graph: every node with its settings and its ports as they are now (the ports it declares itself under ports), the edges, the groups and comments with their boxes and colors |
lint_graph |
How a graph reads, counted as you see it: nodes on top of each other, links that cross, links running over a node that is not theirs, links running right to left, comments a node lies on, the longest links, with a few ids of each |
catalog |
What there is to make: the commands by area with what each does, and with a query (an area or command names) their arguments; the nodes a graph can hold (all of them, or the best matches of a search in full); the asset types and their properties; the variable kinds |
run_commands |
Changes the project, see below |
open |
Brings up an asset's tab, or the scene or game tab |
select |
Selects an asset, objects of a scene or container, or nodes of a graph |
play |
Play, pause, resume, stop. With until, the game runs on to that game time and holds there. Says so when no camera is on, since the game then shows nothing |
play_input |
Keys and the mouse in the running game, step by step, see below |
get_runtime |
The running game: time, pause, camera, keys held, mouse, every object with its position (behaviors with their variables), the Variables assets, what is heard (audio), the last console lines |
undo, redo |
Like Ctrl+Z and Ctrl+Y, up to 20 steps at once |
There is also a resource, feuerwerk://view, with the same answer as get_view. An agent that
subscribes to it hears when you switch the tab, the document or the selection, start or stop
playing, or open a dialog; moving the camera is no news. Not every client follows subscriptions,
so the relay also tells the agent with its next tool answer that the view has changed since it
last looked, in one line.
Changing the project
run_commands takes a list of steps, each a command of the catalog with its arguments, and runs
them as one undo step: in the Edit history it is called Agent: and the label the agent gave
it. One Ctrl+Z takes the whole call back.
- All or nothing. The arguments of every step are checked against the command's schema; if a
step fails, the steps before it are taken back and the answer names the step and why
(
Step 8 (connect): Cannot connect number to exec). Nothing of a failed call stays. - Steps build on each other. A step with
"as": "walk"gives later steps its id as"$walk"(and"$walk.closing"for the second node a Find adds). Each step is built after the one before has run, so one call can make a behavior and fill its graph. - Nodes come from the palette.
add_nodetakes the id of an entry of the catalog for that graph:OnKeyHeld,Move,RunBehavior:<id>for another behavior. - The editor places the nodes. Nodes added without
xandyare arranged when the call has run, the way the Arrange button does it, and the move is part of the same undo step. Nodes that were there before stay where they are, so what you laid out by hand is never shuffled; the new ones go next to the node they link to, where their links cross the fewest others. When that node is in a group, the new ones go into it and the group grows round them — unless it would then take in a node not its own. New nodes put between two that stay, say a filter between an instrument's Delay and its Output, make room: what they feed and everything right of it moves right as one, so no link runs backwards.arrange_grapharranges nodes the agent names, or the whole graph, which the agent is told to do only when you ask. - Readable graphs. The agent is told to fetch a value needed far away with a second Get or
Owner node next to where it is used rather than one long link, and to check with
lint_graph— the crossings too, witharrange_graphwhen there are more than the links need. Nodes that belong together go into a group (add_group), with a comment on what they do (add_comment). Both take the nodes they are about rather than a box: a group is drawn around them, a comment just above — below them where another node or a group's title bar stands above — and when the call arranges its nodes they follow them there, still in the same undo step. A group made round new nodes alone gets room as they are arranged: a node or another such group that would stand in it goes below it, so it holds its own nodes only. The group is the one Group in the graph's menu draws around a selection.lint_graphalso counts comments a node lies on (coveredNotes), whichfit_groupputs back by their nodes. - Copying nodes.
copy_nodescopies nodes into the same graph or another, as Ctrl+C and Ctrl+V do: with the links between them and the groups and comments about them alone. Each copy is named by the id of its original ("$copy.<id>"), so later steps can link it. Withoutxandythe copies are arranged like new nodes, with them the copy keeps its layout. Nodes the other graph cannot hold are refused by name, by the same rule the graph tab pastes with. The variables a copied Variables node reads from its behavior come along into the other behavior, with their default, Keep and Private. One declared there in another kind is refused. - Silent music. A pattern plays nothing without an instrument, and an instrument sounds only
the notes its Notes nodes take in (C4 to B4 in a new one). Nothing else says so.
get_assetlists undersilentwhat of a pattern, a song or a composition is not heard: all of it for want of an instrument, or the notes outside what the instrument sounds, in a song after the transpose of the item. Each line names the notes, what the instrument sounds instead and how to mend it.add_notesmentions both. The keys the pattern tab greys out are worked out the same way.apply_presetputs one of the instrument tab's presets in, which take every note. - Files the server holds. The agent uploads nothing.
list_fileslists what is there andadd_file_assetmakes a texture, font, sound or video of it, as the picker does: named after the upload unless the agent names it. A file the project has an asset of already is refused with that asset named, and so are a picture whose size the server could not read and a video not converted yet. A song's bakes and streaming copies are not listed. - What uses an asset.
get_assetlists it underusedBy, read off the data rather than field by field, so a song item, a Sample, a key or a cell counts as much as a property. The agent is told to look there before it deletes or reworks an asset. - Variables in a graph. A Variables node reads (and with
set_port_writewrites) a variable onceadd_portnames it; the port takes the kind of the variable. Properties and Sound FX parameters nodes work the same way, a start or end node or a struct gets ports of a kind given. A port naming nothing the node knows is refused with the names there are. - Deleting asks you. A call that deletes an asset that was there before opens a dialog The agent asks: Delete "..."? with the same text as your own Delete. The call waits for your answer, up to 110 seconds; Cancel, Escape or no answer leave everything as it was.
- You see what the agent works on. After each call the editor brings up what its last step
worked on: the graph's tab with every node the call touched there selected, the scene or
container with its objects selected, the tab of an animation, curve, texture, tile, tilemap, pixel art, vector art, pattern, song, sound, video or composition
(with the frame picked when the call worked on one), or the asset in the inspector. Objects in another scene
switch the scene, inside the agent's undo step, so Ctrl+Z goes back to the scene you had.
Account menu → Follow agent switches this off (kept in this browser); while the game runs the
editor never follows.
openandselectstay for anything else the agent wants to show. In a graph tab that is open already the camera goes after the nodes: by just as much as it takes to bring them in, at the same zoom, and not at all when they are in sight. Only nodes too far apart to fit at this zoom are framed afresh, which zooms out. - While the game runs a change goes into the running copy, as yours would, and the answer says it is gone when the game stops.
The commands come in areas; catalog lists them with what each does, and gives the arguments
for an area or for command names asked for.
| Area | Commands |
|---|---|
| assets | create_asset, add_file_asset, rename_asset, duplicate_asset, delete_asset, set_asset_property, reset_asset_property, set_start_scene, set_machine_scope, set_machine_start, set_variables_scope, set_variables_persistent, make_project_asset |
| variables | add_variable, remove_variable, rename_variable, move_variable, set_variable_kept, set_variable_private, add_struct_field, remove_struct_field, rename_struct_field, move_struct_field, set_struct_type, make_struct_type, set_list_item_type, make_list_item_type |
| objects | place_asset, remove_objects, move_object, reorder_object, set_editor_offset, rename_object, set_override, clear_override, apply_override_to_asset, apply_override_to_container, revert_override_to_container, apply_position_to_container, revert_position_to_container, set_parent, group_objects, set_object_group, rename_object_group, ungroup_objects, create_container, unpack_container, add_collider, add_rigidbody, add_joint, fit_collider |
| graphs | add_node, copy_nodes, arrange_graph, remove_node, move_node, set_node_param, collapse_nodes, resize_node, connect, disconnect, fold_edge, name_transition, add_group, add_comment, fit_group, edit_annotation, remove_annotation, add_port, repoint_port, remove_port, rename_port, move_port, set_port_write, set_port_machine, set_port_default, set_node_struct_type, split_output, set_list_node_type |
| animation | set_animation_root, add_animation_track, remove_animation_tracks, retarget_animation_track, set_track_relative, set_animation_key, set_key_easing, remove_animation_keys, move_animation_keys, shift_animation_frames, key_straight_run, set_curve_points |
| textures | add_frame, set_frame_rect, rename_frame, remove_frame, slice_frames, set_nine_slice, set_sort_line, set_frame_collision |
| tiles | add_tile_picture, remove_tile_picture, move_tile_picture, paint_tiles, add_tilemap_layer, duplicate_tilemap_layer, remove_tilemap_layer, move_tilemap_layer, set_tilemap_layer, resize_placed_tilemap |
| pixelart | paint_pixels, add_pixel_layer, duplicate_pixel_layer, remove_pixel_layer, set_pixel_layer, move_pixel_layer, merge_pixel_layer_down, add_pixel_frame, remove_pixel_frame, move_pixel_frame, resize_pixel_canvas, set_palette_colors, remove_palette_color |
| vectorart | add_vector_shape, set_vector_shape_outline, set_vector_shape_style, transform_vector_shapes, duplicate_vector_shape, remove_vector_shapes, combine_vector_shapes, rename_vector_shape, order_vector_shape, move_vector_shapes, group_vector_shapes, ungroup_vector_shapes, add_vector_layer, remove_vector_layer, move_vector_layer, set_vector_layer |
| music | add_notes, change_notes, remove_notes, set_loop, apply_preset, add_song_track, change_song_track, move_song_track, remove_song_track, set_song_lane, add_song_marker, change_song_marker, remove_song_marker, add_song_item, change_song_item, remove_song_items, set_send, add_clip, change_clip, remove_clip |
| composition | add_composition_track, change_composition_track, move_composition_track, remove_composition_track, add_composition_item, change_composition_item, remove_composition_items, add_composition_clip, change_composition_clip |
| project | rename_project, set_layer_names, set_play_from, set_while_playing, set_game_link_zoom, set_symbol_scale, set_master_volume, set_master_fx |
A change to the fields of a Struct asset reaches every variable and node of that type, as it does from the inspector.
- Animations name a row by its target and property, as
get_assetlists them, and a key by its row and frame. An easing is a name likesine-outorcurve:<id>for a Curve asset; how long an animation runs, its fps and playback, are properties as in the inspector. - Painting a tilemap takes rectangles and single cells in one step; the rectangles go first, so a cell can cut a hole into one. A cell outside the grid is refused, the grid being the largest the tilemap has, its own or that of a placement grown at an edge. At most 20 000 cells a step.
- A nine-slice without
fillkeeps the fill the picture has. Generate collision stays with you: it reads the pixels of the texture, so the agent sets outlines by their corners. - Painting pixel art goes one layer on one frame a step, through draw steps in order:
rows(a small picture in the charactersget_assetreads, a space leaving the pixel alone),pixels,line,rect,ellipse,fillandclear, with palette indices, 0 erasing. An index the palette lacks or a pixel outside the canvas is refused. The cel is kept in the browser and saved like one you painted. Merging, resizing and taking a palette color out use the same rule as the side panel. - Vector shapes take rings of points in canvas pixels, or a
rector anellipsegiven by its box. Fill, opacity, a gradient or picture fill and the outline go along when the shape is made, or later withset_vector_shape_style;paintof typesolidand an outline of width 0 take them away again.transform_vector_shapesmoves, scales, turns and mirrors shapes and groups with their paints, round their middle unlessaboutnames a point. - Notes are counted in ticks, 480 to a quarter note, and a pitch is a MIDI number or a name
like
C4orF#3.get_assetreads a pattern's notes with their names and how many ticks it is long; a note starting past its end is refused. The routing of a song and the master routing (#routing) are graphs: links are drawn withconnectand set withset_send. - Song and composition items without a length are as long as their pattern, their sound or
video, or what they play, else 3 s; on a composition such an item keeps following it. How long a
sound lasts is only known once the editor has loaded it (
get_assetsaysseconds), so a sound not loaded yet needs a length. An object item's object is set with the commands of area objects, in = the composition. Moving an item takes the clips that belong to it along, as dragging does, and a clip that would come to lie over another is refused. - Automation of a song track (#337) is one command,
set_song_lane: the lane by its target (volume,panorparam:<name>, asget_assetlists it), and all its points at once, each a tick, a value and an easing as for animation keys. Points on one tick stay in the order given, which makes a jump. A value outside the lane, an easing there is none of and a Curve asset that is not there are refused.points: []takes the lane of the volume or the pan away. A parameter lane is only made for a parameter something on the track has (paramsinget_asset); withoutminandmaxit gets the range the Song tab would offer, round the default.removetakes it away. - Markers of a song (#338):
add_song_markerputs one on a tick (named Marker n without a name) and gives its id,change_song_markerrenames or moves it,remove_song_markertakes it away. A blank name is refused.get_assetlists them undermarkers, in the order of their ticks. Not for the agent, on purpose: uploading a file (it takes one the server holds), pasting needs the clipboard (the agent builds directly instead), and switching a plugin on would run its code.
A behavior acts on the object it is placed under. The smallest walking object is therefore a
sprite, a behavior placed with the sprite as parent, and in the behavior an OnKeyHeld whose
exec and dt feed a Move, with an Owner on its object.
Playing the game
The agent can test what it built without you pressing a key: play, then play_input to play
it, then get_runtime to see what happened.
play_inputtakes steps, and each does one thing.{"key": "ArrowLeft", "hold": 0.5}holds a key,{"key": "Space"}taps it for one frame,"keep": "down"leaves a key held after the call and"keep": "up"lets it go.{"mouse": "click", "at": {"object": "<id>"}}clicks an object,"at": {"x": .., "y": ..}a point in world units;down,upandmovedo just that.{"wheel": -1}turns the wheel,{"wait": 1}lets the game run on. Keys go by theirKeyboardEvent.keyname (a,ArrowUp,Enter), andSpaceis the space bar.- A moment of the game is held, not caught. Between two calls the game runs on, often for
seconds, so a call that only reads comes too late for a short moment.
playwithuntil(game seconds, asget_runtimegives them, at most 30 ahead) lets the game run to that time and pauses it there:{"action": "play", "until": 0.5}starts it,resumeandpausego on from where it is. The frame that would go past the time is cut short, so the game stands at 0.5 s exactly, not a frame later. A lastplay_inputstep{"pause": true}does the same after the step before: after a wait at its time exactly, after a key or a click at once.get_runtimeandscreenshotthen show that moment. - Until is called off when the user pauses first, or a
Breaknode does (the answer says it paused before the time), and when aLoad sceneorRestart gamestarts the time over. A recording not in real time keeps its own frames, so there the pause comes with the first frame at or past the time. - Time is the game's. Every step takes at least one frame, so a tap is seen as a press and then a release. Hold and wait count game seconds, at most 30 per call. A call over 5 seconds tells the relay it takes longer.
- What the answer tells: the game time it took and the one it is at, whether it is paused, the keys still held, where the mouse is, whether a click on an object landed on it, and the new console lines.
- A tapped or held key is let go again, even when a step fails. Only
keepleaves one down. - It needs the game playing, not paused, and the editor tab in front. A tab in the background runs no frames, so the call says so right away. If the game time stands still for 25 seconds (paused by a behavior, the tab sent to the background), the call stops and names the step.
- Your own mouse over the game view still moves the game's mouse. While the agent clicks, leave it outside the Game tab.
get_viewwarns when the scene Play starts has no camera switched on, and while playing when the game has none.
Hearing the game
The agent has no ears, so get_runtime tells it under audio what you would hear. Whether music
really sounds, it reads there, not only in the silent of get_asset, which is worked out from the
data and misses a bus at 0, a send that leads nowhere, a sound FX that filters everything out or a
sound that did not load.
clock: the state of the audio clock and the second it is at. While a pause holds it, the state is the one it had as the pause took hold.suspendedthere means the browser held it while the game ran: nothing was heard and notes stayplanned, andaudiosays so in ahint. Chrome starts it only once the page has had a click or a key, so after a reload the user clicks into the editor once before the agent plays.levels: the master, each bus of the mix, each pattern, song or composition playing and the tracks of a song, each withpeakandrmsin dB, orsilentbelow -90 dB. A level is taken after the volume and the pan of its bus, over the lastwindowseconds (about 0.7, so the gap between two notes is not taken for silence).- Held while paused. A pause holds the audio clock, and with it the levels:
playwithuntiland a read after it give the last 0.7 s before that moment. voices: what sounds now, a sound by its name (a clip asSound / Clip), a note as its instrument and note name (E4), the bake of a pattern or song as such, each with its bus and the object it belongs to (by),releasedonce its note is let go andringingonce only its echoes are left. At most 40 are listed and the rest counted.plannedcounts the notes already set to start a moment later.playing: the patterns, songs and compositions playing, withended,fadingorbaked.waitingandfailed: voices whose bytes have not come yet, and files that would not load.- Measured only while the agent is switched on. Each bus then has a second tap beside the meter of the Song tab, an analyser for each side; switched off, they are let go.
How it works
Claude Code --- MCP over HTTPS ---> /mcp ---> relay (tools/mcp/) <--- WebSocket --- your editor tab
|
+--- whose token, whose ticket? ---> api/index.php
- The relay (
tools/mcp/relay.mjs) is a Node service without dependencies in the containerfeuerwerk-mcp. The agent's side is MCP's Streamable HTTP: JSON-RPC by POST, an event stream by GET for notifications, DELETE to end a session. Your tab's side is a WebSocket on the same path, with anOrigincheck. - It knows no accounts. Every request of an agent asks the API who its token belongs to, so a revoked token stops at once. A tab gets onto it with a one-minute ticket the API gives it for its session (the session cookie does not travel to the relay's path).
- The tools live in the editor (
src/editor/agent/). The relay knows only their list,src/editor/agent/tools.json, and passes a call to the tab of the token's account and the answer back. A call to an account without a tab on gets "no editor connected" and never reaches another account's tab. - A call has 30 seconds. One that asks you something (a delete) or plays the game for more than 5 seconds tells the relay to wait, and then has two minutes.
tools.jsonholds each tool's argument schema; the editor checks every call against it (argCheck.ts). The commands and their schemas are incatalog/, one file per area, gathered incommandCatalog.ts; the all-or-nothing undo step ineditPlan.ts, the reading tools inreadTools.ts.
What is behind it on the server, and the routes it uses: API, Development.
Tests
tests/mcp/relay.test.ts: the relay between a fake API, MCP clients and fake tabs, without a browser: tokens refused and braked, sessions per account, tabs refused from another origin or without a ticket, one tab per account, timeouts, the view resource and its notifications.tests/php/agents.test.php: tokens and tickets on disk.tests/php/rights.test.phpasks the new routes as everybody, with and without the relay's key.tests/editor/agent-view.test.ts: whatget_viewanswers, its one line, the tools' arguments.tests/editor/agent-edit.test.ts: a walking object built in one call and taken back whole by one undo, a failing step that leaves nothing, argument checks, deletes that ask, nodes arranged at the end of a call while placed ones stay, a new node linked into a group put into it within the same undo step,arrange_graph, what the editor shows after a call (and the scene switch inside the undo step, and nothing with Follow agent off), the reading tools and the catalog (every area in full under the size an answer is cut at).tests/editor/agent-copy.test.ts: nodes copied into another behavior with their links, a group and a comment, a variable carried along and later steps linking the copies, all taken back by one undo; a copy placed by hand keeping its layout; nodes a shader cannot hold and a variable of another kind refused.tests/editor/agent-catalog.test.ts: a Variables node reading a variable onceadd_portnames it (and refusing a name it does not know), a group and a comment fitted to the nodes after the call arranged them, a field of a Struct asset reaching the variables of that type, a container's content listed by the ids an override takes, object groups, and the project settings.tests/editor/agent-art.test.ts: an animation keyed with easing in one call and shown in its tab, the targets of a scene root, an easing there is none of, keys moved and copied, frames inserted; a curve held from x 0 to x 1; a frame handed on, nine-sliced (and its fill kept) and picked in its tab, a sheet sliced into a grid; a tilemap painted with rectangles and cells and read back, cells outside the grid, tiles that are none and too many cells refused, the grid of a placement grown at its edge, layers added, changed and moved.tests/editor/agent-drawing.test.ts: pixel art painted with rows, a rect and a fill in order and read back as rows, indices the palette lacks, pixels outside and unknown characters refused, a copied frame and a second layer merged down and resized round the middle, a palette color taken out with its pixels, a big canvas only counted; an ellipse lying on its box all the way round, a rect turned round its middle, a gradient and an outline set and taken away, a shape moved on top of a group, and unknown shapes refused.tests/editor/agent-music.test.ts: notes added by number and by name and read back with their names, a note past the end and a name there is none of refused, notes changed, removed and replaced, a loop set and cleared; a pattern laid on a song as long as it is, a sound by its loaded length and refused while not loaded, tracks added, changed, moved and removed (the last one kept) with the routing following, sends of a song and of the master routing (a sound only after its level); a volume lane set in the order of its ticks with its easings, a value, an easing, a Curve asset and a range out of place refused, and the lane cleared with no points; a parameter lane refused for a parameter not on the track, made round its default, its points held to a narrower range, set while its parameter is gone and removed, withparamsper track; a clip of a sound added, changed and removed; an object, a picture and a pattern laid on a composition, an animation and the composition itself refused as items, an item moved with its clip, a clip over another refused, fades only on what sounds, an item removed with its object, and the tracks of a composition; what of a pattern, a song and a composition is silent without an instrument, until the item or the pattern has one; the notes outside the range of the instrument named, in a song after the transpose, until the range of its Notes node takes them in.tests/editor/agent-files.test.ts: the stored files of a kind listed as the picker offers them (a song's bake left out) with the asset wearing one; a texture, a sound and a video made of them in one undo step, fetching only the lists the steps need; a file already in the project, a picture without a size, a video not converted yet and a file not there refused; a preset in an instrument, after which a low note is heard, and refused for a pattern;usedBynaming the sprite wearing a frame, the scene an object of it stands in, the start scene, the Sample of an instrument, the song item playing a pattern, and nothing for a song only the master routing has.tests/editor/graph-follow.test.ts: a new node feeding one in a group joining it while the group grows round it (and not, where it would take in a stranger), a new node taking from one in a group put beside it rather than where it waited, a group fitted again after Arrange with its comment going along, one moved as it is, room made between an instrument's Notes and Output (and none where there is room), comments put below their nodes where above is taken, and covered comments counted.tests/editor/graph-arrange.test.ts: the layout on the graph an agent really built for "walk with the arrow keys" (no overlaps, no link over a node, none backwards, at most 8 crossings with one Owner for four moves and 4 with one each), chains running straight, the flow on top when two orders cross as often, nodes that stay, a new node placed where its link crosses least and level with the port it feeds, groups kept clear, loops, and whatlint_graphcounts.tests/editor/agent-play.test.ts: a held key walks the object as far as the game seconds say, a tapped one fires a key-down once, a kept one stays down across calls, a click on an object lands and one beside it does not, a call that gives up when the game stands still and lets go of its key, calls turned down before anything runs,get_runtimewith what is heard (levels by bus name in dB, the inner buses of a track left out, voices by sound or note, planned, waiting and failed), and the camera hint. Pausing at a game time:playwithuntillanding on it exactly from a start, a resume and a pause, what it turns down, giving up when the time stands still, a pause that came first, and a lastpausestep after a wait and after a tap.tests/editor/graph-framing.test.ts: how far the camera goes after nodes: not at all when they are in sight, just far enough otherwise, zooming out only for what does not fit.- e2e step 71 (
tools/e2e/71-mcp.mjs): a token made in the dialog, the agent switched on in the account menu, an MCP client reading the view, hearing a tab switch and taking a screenshot; the agent building a walking object whose graph comes up with its nodes selected and arranged, Arrange in the header untangling it as one undo step, the open tab's camera going after a node added far away, a Variables node with a port and a group framing every drawn node, an animation keyed by the agent coming up in its tab, pixel art it paints read back as rows and its cel saved to the server, notes it writes read back by name and a pattern and a sprite it lays on a composition opening in its tab, a sound you uploaded listed, made an asset nothing uses yet, and a preset filling an instrument, the object moving when played, the agent holding the arrow and clicking the object itself and reading withget_runtimehow far it went,playwithuntiland a lastpausestep holding the game at the time asked for, a sound looping on the master and on a bus at 0 heard and silent, held as they are while paused, one Ctrl+Z taking it back, a delete waiting for the user's Cancel; and the badge switching it off.
Using the editor
- Concepts
- Accounts
- Agents (MCP)
- Scenes
- Scene editing
- Behaviors
- Structs
- Colliders
- Physics
- Textures
- Vector art
- Pixel art
- Fonts
- Videos
- Sounds
- Instruments
- Patterns
- Songs
- Animations
- Curves
- Tiles
- Tilemaps
- State machines
- Shaders
- Particles
- Containers
- Compositions
- Keyboard
Working on the code