The problem this solves

You describe a character in a prompt and get an image you like. Then you need that same character somewhere else — different place, different light, same face. You paste the description into a second prompt and get a different person. So you attach the first image as a reference, along with a photo of the alley you want them standing in, and now the model has two images and no way to know which one is the character and which one is the alley.

Later you change something about them. A jacket, a haircut, their name. Every prompt that mentions them is now out of date. There are eleven of those prompts, spread across four projects, and you either edit all of them by hand or you accept that they have drifted apart.

And when a generation finally comes out right, nothing records what produced it. The prompt is somewhere in a scroll-back. The reference photos were dragged in from a folder. The model was whatever the dropdown happened to say that afternoon.

This is what a single text box costs you. Not quality; the models are good. Structure. A prompt written as one paragraph has no parts you can address, so nothing in it can be reused, corrected in one place, or pointed at individually.

GenAI Composer gives the prompt parts.

What it is

A canvas. Each piece of what you are describing is its own node: a character, a place, a style, a constraint. Nodes have typed input and output ports, and you connect them with wires. A character node and a place node feed a scene node; the scene node feeds an output.

Click Run on a node and the editor walks the wires backwards, gathers everything bound to that node’s inputs, assembles the prompt, calls the model, and records the result. Run All sorts the whole graph in dependency order and executes it in one pass.

The canvas is the visible half. The half that does the work is a split between two kinds of thing: what a picture means, and how you arranged one.

Reuse a character without leaking edits

A Concept is a named semantic anchor: “Jean-Claude Van Damme”, “Tokyo at night”, “cinematic lighting”. It is shared. A Project is your canvas: nodes, wires, positions, the reference photo you uploaded. It is private.

A node on your canvas instantiates a concept. It does not copy it.

Two projects both use the JCVD concept. Rename the concept and both projects show the new name. Change how he is phrased in project A — “JCVD on a rocky shore at dawn” — and project B is untouched; its node still falls back to the concept’s own description. Upload a reference photo in project A and the photo stays in project A.

That is the whole contract: shared meaning propagates, canvas state does not. It is the difference between a character you maintain and eleven copies of a paragraph you have to remember to update.

Tell the model which image is which

Reference images are the part most tools get wrong, because they send you a list of attachments and hope the model works it out.

Each segment of the prompt carries its own images, and the payload is built interleaved: the segment’s text, then an instruction describing what its images are for, then the images themselves, in that order. Repeatable segments are numbered even when there is only one, so a prompt can say “holding the sunglasses from Character 1” and the model can resolve it.

The ceiling is the provider’s: 14 reference images per request on Gemini (ten objects and four characters on Flash, six and five on Pro), inside a 20 MB request. Structure does not buy you more images. It buys you the model knowing what each one is.

Start from a sentence

Type a description into the prompt bar on the landing page and you get back a populated, editable graph — nodes, concepts, ports, wires, laid out — rather than a finished image.

That distinction is the point. A finished image is an outcome you can accept or reject. A graph is a thing you can open up, rewire, and rerun. The router reads your sentence, picks the medium, and generates a structure that matches it: a photo request builds a scene graph, a video request builds a motion-shaped one.

One graph, several media

You can ask for more than one format from the same description. Image and video of the same scene, or a track to go under it. The run path handles image, video, and music, and the front door lets you select the formats instead of guessing at one.

Cinematic techniques, bullet time and the rest of a technique library, are properties of an output node, not text melted into your prompt. So a technique is a thing you can see, edit, swap, and remove, and when a graph has two outputs, each one carries its own.

Mix models inside one run

Model choice is normally global: change it and every node moves. Here a node can override the provider and model it runs against, and everything else falls back to the default.

Draft your character reference on the cheap fast model, render the final scene on the expensive one, in the same project, in one Run All pass. Providers are derived from the transport library rather than hand-listed, so a capability the library supports is a capability the app offers.

The record survives your edits

Every model call produces a Generation: a frozen record of the request, the response, and the state of the project at the moment it ran. Generations are append-only. Rewrite a node’s text afterwards, rewire a port, swap the reference photo — none of it reaches back and rewrites what that generation recorded.

So the canvas can be a scratchpad and the history can still be true. Each result carries its model, token count, timestamp, and the exact prompt, with a copy button. Six weeks later you can still answer “what made this one”.

Common pitfalls

Problem: your project opens on another machine and the reference images are missing. Export carries the graph, the concepts, and the artifacts. An older export that predates this carries dangling references, and a generation will quietly run without the reference image rather than failing loudly. Solution: re-export from a current version before moving a project.

Problem: a three-shot video request comes back as one frantic clip. Text to video models emit a single fixed-length clip, so three shots inside one eight-second output get under three seconds each. This is a known limitation: the fix is generating one clip per shot and concatenating, which needs a server-side render layer that does not exist yet. Solution: for now, generate shots as separate video nodes and assemble them yourself.

Problem: a run fails with a rate limit and nothing retries. The editor surfaces the provider’s error and stops rather than looping on your key and your bill. Solution: click Run again.

Problem: video takes minutes and looks stuck. Video generation is submit-then-poll by nature. Solution: it is running; the node reports when the job returns.

What it costs to try

Nothing, and you bring your own API key.

There is no account, no sign-up, and no server holding your work. Projects live in your browser. The key lives in your browser. Providers that cannot be called directly from a browser go through a relay that adds CORS headers, forwards only to an allowlist of provider hosts, and logs nothing: not the key, not the prompt, not the response.

The honest trade: you have to go get a Google API key before anything generates, which is real friction on the first run. In exchange, your prompts and your reference images are not sitting in someone else’s database, and inference is billed to you at cost with nothing marked up on top.

Next steps

  • Open studio.aktagon.com. The landing page starts you from a template, from a worked example, or from a sentence.
  • Build the same character into two projects and rename the concept. That one experiment shows you the whole model in about a minute.
  • A desktop build that keeps projects on your own filesystem is the next thing on the roadmap.