All Documentation

Forge — 3D Models

Describe a hard-surface asset and get a rigged, textured, game-ready model — with the build script, so it can be refined instead of regenerated

Overview

Forge builds 3D models — one of the kinds of Saved Content, beside pictures, lines, sound effects and music. You describe an asset — "twin-engine attack submarine, angular hull, forward laser cannons, missile pods under the wings" — and an AI agent builds it in Blender: clean hard-surface geometry, named bones and sockets your gameplay code can attach to, real UVs with a baked PBR texture set, optional animation clips, and the parametric build script that made it.

That last part is the difference from diffusion mesh generators. Because the script is kept with the asset, refining a model ("make the wings 20% longer") edits the build rather than starting over, and every result lands as a new version of the same item.

Good fitNot (yet)
Vehicles, ships, submarines, aircraft, drones, turrets, mechs, weapons, crates and machinery, buildings and installationsOrganic shapes — characters, creatures, foliage, cloth. The builder writes parametric hard-surface geometry, so those still come out poorly. Diffusion assists now exist: a seed model turns a description or reference into a starting mesh the agent then edits, and a paint model retextures the surface (both are picked on the New model form). They widen what a build can start from; they do not turn Forge into a character generator.

What You Get

Every version of a model is a set of files under one folder in storage, each downloadable from the detail page or the API:

FileRoleNotes
SK_<Name>.fbxSkeletal meshProduced whenever the contract the agent built to is a rigged one, with the bones and sockets that contract names — see below.
SM_<Name>.fbxStatic meshAlways produced — the static copy for engines or uses that don't need the rig.
A_<Name>_<Clip>.fbxAnimation clipOne per requested clip (detailed tier).
<Name>.glbGLBWeb preview (the viewer on the detail page), Unity, Godot.
T_<Name>_{BaseColor,Roughness,Metallic,Emissive,Normal}.pngTexturesThe maps you asked for, at 1024 or 2048 px.
thumbnail.pngThumbnail512 px render, shown in lists.
<Name>.blendBlender sourceOpen it in Blender 5.2 and keep editing by hand.
build.pyBuild scriptThe parametric script the agent wrote against the Tonetta toolkit — what refine starts from.
meta.jsonMetadataTriangles, bones, sockets, clips, bounds, material slots, texture resolution, model used, turns, cost, and the validation gate results.

Conventions

Models are built +X forward, +Z up, in metres in Blender; the exporter applies the axis and scale conventions of the engine target you choose (Unreal imports at centimetres). The armature object is named root, every vertex is weighted, and bone names are stable, so Unreal code can attach to them with DoesSocketExist without socket assets.

Style

The style decides how the asset looks: what geometry gets built, which materials are used, and how much texture detail is baked. It defaults to stylized, and a project or organization can set a house style that every job in it inherits (a job's own style still wins).

StyleWhat you getCost
flatPrimitive shapes, flat colour, no bevels or wear. Blockouts, placeholders and icons.Cheapest
stylizedThe default game-asset look: bevelled edges, palette colours with gentle roughness variation, 1–2k PBR maps.Today's cost
realisticMeasured PBR materials, bevels on every edge and baked surface detail.More agent time and a bigger bake

Wear is separate and runs 0–1: how much grime, edge chipping and scratching is baked into the maps. It defaults to 0 — factory-new — so ask for it explicitly (a battered warship around 0.6, a scuffed crate 0.3) and leave it at zero for anything new or pristine.

Forge builds parametric hard-surface geometry, so realistic means accurate materials, edge highlights and baked detail — not a scanned-looking product render. Organic and soft-goods shapes (a teddy bear, a pillow, a person) are outside what it does at any style.

Presets and Rig Contracts

The preset is a rig contract: which bones must exist, how they are parented, which of them double as sockets, and which animation clips can be requested. The agent must satisfy it — a model whose rig is missing a contract bone never passes validation.

A contract exists to match something outside Tonetta: the gameplay code that calls DoesSocketExist, the animations that have to retarget onto it, the skeleton a mesh will be reimported over. That is almost always one specific game, so contracts are yours to define. They live in three layers — built-in, organization, project — and resolve by name, most specific first. Resolving means replacing: a project contract named vehicle is used instead of the built-in, never merged with it. Half of one skeleton spliced onto half of another is not a skeleton.

PresetRiggedRequired bonesSocketsClips
noneNone (no rig)no———
submarine · deprecatedProteus submarineyeshull, rudder_front, rudder_rear, cannon_laser_L, cannon_laser_R, cannon_missile_L, cannon_missile_R, engine_L, engine_R, fan_L, fan_R; optional Lamp_Top, Lamp_L, Lamp_R, NavLight_L, NavLight_R, TailLight … +1 moreLeftLaserSocket, RightLaserSocket, LeftMissileSocket, RightMissileSocketflight, attack, idle
droneDrone / Turretyesbase, yaw, pitch, muzzle_L, muzzle_RMuzzleSocket_L, MuzzleSocket_Ridle, fire
weaponWeaponyesgrip, muzzle, mag, slideMuzzleSocket, MagSocketfire, reload
propPropnooptional Root——
structureStructureno———
ue5_mannequinUE5 Mannequin (Manny/Quinn)yesroot, pelvis, spine_01, spine_02, spine_03, spine_04, spine_05, neck_01, neck_02, head, clavicle_l, upperarm_l … +21 more; optional upperarm_twist_01_l, upperarm_twist_02_l, lowerarm_twist_01_l, lowerarm_twist_02_l, thigh_twist_01_l, thigh_twist_02_l … +48 more——
ue4_mannequinUE4 Mannequin (legacy)yesroot, pelvis, spine_01, spine_02, spine_03, neck_01, head, clavicle_l, upperarm_l, lowerarm_l, hand_l, clavicle_r … +18 more; optional upperarm_twist_01_l, lowerarm_twist_01_l, thigh_twist_01_l, calf_twist_01_l, thumb_01_l, thumb_02_l … +32 more——

Signed in, that is your table — the built-ins with your organization's own definitions over them, which is what a job with no project resolves against. A project's contracts replace these again, so the table a given job sees is the one on Forge ▸ Rig presets, where you create, edit and delete your own. Over the API the same list is GET /api/v1/models/presets?projectId=, and every catalog response carries it with a source on each entry.

vehicle is the Proteus submarine

The built-in vehicle demands rudders, laser cannons, missile launchers and ducted fans: it is one particular submarine rather than vehicles in general, and the tanks, rovers and jets built to it were all held to parts they do not have. It stays resolvable — finished models were built to it — but it is deprecated, and a vehicle rig of your own belongs in a project contract instead.

Tiers

QuickDetailed
Typical agent spend (reported, never a ceiling)≈ $0.15≈ $0.60
Triangles≤ 20,000≤ 80,000
Textures1024 px1024 or 2048 px
Animation clips—as the preset allows
Typical duration (no time limit)≈ 5–15 min≈ 15–60 min
Credits reserved (generate / refine)25 / 2090 / 70

The quick tier is for blocking out and iterating; the detailed tier gives the agent a larger budget, more geometry, bigger textures, and clips. Both tiers can run on any model in the catalog.

Models

The agent that writes the build runs on an OpenRouter model you pick per job. Models that can see look at their own render previews as they work; text-only models iterate on scene statistics and the validation gates instead, which is cheaper but blinder.

KeyModelVisionNotes
anvilAnvilyesThe only agent since 2026-09-17; model choice fields are accepted and ignored.

GET /api/v1/models/catalog returns the live list with indicative prices, plus the rig presets and styles the build agent chooses between — the dashboard form and the Unreal plugin read it rather than hard-coding the model list.

Forge

Forge is the dashboard section for 3D models: /dashboard/forge lists every model as a card with its thumbnail, preset, tier and model badges and version count, shows the jobs that are running, and has the New model form. A model's page is where you view it in 3D, read its metadata, download files, switch the active version, refine it into a new version, edit its name, tags and character, or delete it. Models also stay listed under Saved Content's Models tab, which links into Forge.

Two ways to build: a job or a conversation

A job is fire-and-forget: you write the brief, submit, and come back to a finished model. It is the right choice when you know what you want and the prompt says it.

A conversation is the other way. Your first message is the brief, and from then on each message is one step: the agent builds, renders or researches, shows you the result, and asks where to go next. You steer — "the nose is too blunt", "give it a second turret", "show me it from below" — instead of rewriting a prompt and starting over. Start one from Forge → New conversation, or open one on a model you already have to work from its active version.

  • •Nothing is saved until you export. Turns build and render freely; asking the agent to export (or pressing Export) writes a version onto the model, and earlier versions stay.
  • •Paid steps are proposed, not taken. When the agent wants a vendor call — a seed mesh, retopology, a paint pass, reference pictures — it tells you what it costs and waits for a yes, unless your message already asked for it.
  • •One turn at a time. A message sent while the previous turn is still running is refused rather than queued; wait for the turn to finish.
  • •Billed to what it actually cost, like every other Forge operation — a turn that only looks at the model costs little.

By API: POST /api/v1/models/sessions to start, /messages to say something, GET the session to read the reply, and /export to save a version. The MCP tools are start_model_session, send_model_message, get_model_session and export_model_session; scope models:write.

Generating a Model

  1. 1Open Forge in the dashboard and choose New model.
  2. 2Write the prompt: the silhouette, the parts, the materials and the finish. The prompt is the whole specification — the build agent reads it and decides the asset's name, its rig, how stylized or realistic the surface is, how weathered, which clips to author and which maps to bake. Optionally attach reference images, pick a project, and choose which language model builds it.
  3. 3Submit. The reservation is taken and the job is queued; you land on the job page, which shows the stage, the round, and every preview render as it arrives — the model taking shape.
  4. 4When the job succeeds the model appears in Forge (and in Saved Content's Models tab) with its thumbnail; its page has the interactive viewer, the file list, the rig/metadata table, versions, and the Refine and Edit details controls.

Writing good prompts

  • •Lead with the class of object and its silhouette: "stubby twin-hull patrol drone", "long, low interceptor with swept wings".
  • •List the parts the rig needs: engines, control surfaces, cannons, missile pods, sensor masts, lamps.
  • •Describe the finish and palette: "matte olive hull with orange trim and worn edges, blue emissive engine vents".
  • •Say how used it looks and how real it should be — "factory-fresh, showroom clean" or "salt-eaten, paint chipped back to steel", "photoreal" or "flat blockout". Those used to be dials; they are words now.
  • •Keep it generic. Prompts that name a trademarked character, vehicle, or franchise are refused (prompt_rejected); "in the style of …" descriptors are fine.

Validation gates

The agent cannot finish until the model passes the acceptance gates: a single joined mesh, a triangle count inside the tier's floor and cap, few non-manifold edges, bounds and forward axis per the preset, every contract bone present with every vertex weighted, non-overlapping UVs with good atlas coverage, at least three materials, and at least two keys per animated bone per clip. The results are recorded in meta.json and shown on the detail page.

Art Direction: System, Organization, Project

Three editable layers sit in front of every asset prompt, so you describe your world once instead of repeating it in each prompt — and the agent stops defaulting to its own generic look. Later layers override earlier ones; the asset prompt wins over all of them.

LayerWho edits itWhereWhat it is
SystemThe Tonetta operatorAdmin ▸ 3D Modeling GuidanceHouse-wide modeling guidance inserted into the agent's system prompt (quality bar, general do/don't). Not on the API.
OrganizationThe organization ownerOrganization page; GET/PATCH /api/v1/organization (organization:read/write); MCP get_organization_modeling / set_organization_modelingFree-text art direction every model in the organization inherits.
ProjectProject membersProject page; artDirection on the projects API; MCP create_project / update_projectThe same, for one project; overrides the organization layer.

Each layer is one block of free text — say it the way you would say it to an artist. Shape language, era and mood; the materials and finishes; the colours, by name and hex; real-world sizes; and what to avoid. There are no fields to fill in and nothing to encode: "Retro-futurist 1960s submarine tech: rounded hulls with riveted band seams, brass trim, bulbous portholes. Brushed steel #8a9199, copper trim #b87333, cyan weapon glow #3fd6ff. Player sub 6 m; enemies 4–12 m. No organic shapes, no readable text." Up to 8,000 characters per layer.

When a job is submitted, every layer is snapshotted onto the job: the system guidance goes into the agent's system prompt, and the organization and project text are written in as two consecutive "art direction" blocks right after your asset prompt, verbatim — organization first, project second, your prompt winning on any conflict. Refine jobs take the layers as they are at that moment, and a one-off exception needs nothing more than saying so in the prompt (or switching a layer off for that job). The job page and the model's detail page show which art direction a version was built against.

Art direction says what your world looks like, not how one asset should be built: an asset's own prompt decides its style, its weathering and its detail, and wins over every layer. A project whose text describes a flat mock-up look still builds whatever the prompt in front of it asks for.

Which Models Are Offered

The list of language models the generate form, the API catalog, MCP and the Unreal plugin offer is maintained by the Tonetta operator under Admin ▸ 3D Modeling ▸ Models available for 3D modeling: models can be enabled or disabled, one is marked as the default used when a request omits model, and new ones can be added by searching OpenRouter (the model must support tool calling; whether it can see render previews and its context size are read from OpenRouter). Read GET /api/v1/models/catalog or call get_model_catalog for the current keys rather than assuming them; a key that is not offered is refused with validation_error, and jobs already queued keep the model they were submitted with.

Refining

The Refine box on a model's detail page takes plain instructions and starts a job from the active version's build.py and .blend. The result is appended as the next version and becomes active; older versions stay downloadable and can be pinned back, exactly like audio versions. One job per model at a time — Refine is unavailable while a job is running.

Jobs, Credits, and Cancelling

Model generation is asynchronous — the only Tonetta operation that is. Submitting returns a job id immediately; poll it (or long-poll with ?wait=) until the status is terminal.

StatusMeaning
QUEUEDWaiting for a worker.
RUNNINGThe agent is building; stage, progress.iteration, and previews update after every round.
FINISHINGJoining, skinning, baking, exporting, uploading.
SUCCEEDEDThe version exists; contentId / versionNumber point at it.
FAILEDSomething went wrong (error.code says what); the reservation is refunded in full.
CANCELLEDYou cancelled it; only the cost incurred so far is charged.
  • •Reserved, then settled. Submitting holds a reservation — at least the tier's base (25 quick / 90 detailed), more for premium models — and on completion the job settles to the actual LLM + compute cost times the usual surcharge; the difference is returned. Every model in the catalog and on the generate form carries ≈ credits per tier: what a job on it typically settles to, in Tonetta credits (never the provider's own prices). See Credits & Pricing.
  • •Limits. Two active jobs per organization by default (409 too_many_active_jobs, no credits held) — your organization page shows the allowance in force and we can raise it; one active job per model; a job that stops reporting is failed and refunded automatically.
  • •Cancel from the job page, the dashboard's active-jobs strip, or the API. A queued job is refunded in full; a running job stops after its current step.

Engine Targets

TargetWhat changesImport
unrealFBX in centimetres, +X forward, +Z up; bone names double as socketsThe Unreal plugin imports a version in one call: skeletal/static mesh, textures, a material instance, physics asset, and clips.
unityGLB and FBX with Unity's axis conventionsDrop the GLB or FBX and textures into Assets/.
godotGLB with Godot's conventionsImport the GLB as a scene.
genericMetres, +X forward, +Z up, no engine-specific fixesAny DCC or engine.

API Access

Models are scoped with models:read / models:write. Content routes treat a model like any other item; the generation routes are below. Full details in the REST API reference.

GET/api/v1/models/catalog?projectId={'{id}'}models:read

Models (vision flag, estimatedCredits and reserveCredits per tier), tiers, targets, texture maps, and the presets you may actually build to — the effective list for your organization, or for the project you name, each entry carrying its source.

GET/api/v1/models/presets?projectId={'{id}'}models:read

The same effective list on its own, plus a sources map and, for the contracts you own, the id the write routes address.

POST/api/v1/models/presetsmodels:write

A whole contract, plus projectId to scope it to one project (omit it for the whole organization). Names are unique within a scope. A rejected contract answers 400 invalid_preset naming the rule it broke and the field that broke it, not just "invalid".

PUT/api/v1/models/presets/{'{id}'}models:write

Fields you send are written over the stored contract and the whole thing is re-validated. Built-ins have no id and cannot be edited — define one of the same name in your own scope instead.

DELETE/api/v1/models/presets/{'{id}'}models:write

Models already built to it are untouched: a running job carries its own copy of the contract, and a finished one recorded the contract it was built to.

POST/api/v1/models/generatemodels:write
FieldTypeDescription
prompt*stringThe whole specification (≤ 2000 characters) — the agent decides the name, the rig, the style, the wear, the clips and the maps from it
projectIdstringProject the model belongs to; its art direction then applies
characterIdstringCharacter the model belongs to (optional). The model is saved into that character’s project, so omit projectId or pass the same one
modelstringCatalog key (omit for the default)
presetstringRig preset to build to (a name from the catalog or /v1/models/presets); omit it and the agent chooses
seedFirstbooleanDefault true: a generated mesh is imported before the agent builds. false builds from primitives
referenceImagesstring[]Up to 4 URLs from POST /v1/models/references
budgetUsdnumberSpend ceiling in USD of provider cost, capped at 50

Returns 202 with jobId, contentId, creditsReserved. Send an Idempotency-Key header to make retries safe.

GET/api/v1/models/jobs/{'{jobId}'}?wait={'{seconds}'}models:read

Status, stage, progress, previews, cost. With wait (≤ 240) the call long-polls until the job changes or the time is up.

GET/api/v1/models/jobs?status=&projectId=&contentId=models:read
POST/api/v1/models/jobs/{'{jobId}'}/cancelmodels:write
POST/api/v1/content/{'{id}'}/refinemodels:write
FieldTypeDescription
instructions*stringWhat should change — the whole specification, as the prompt is for generate
modelstringDefaults to the version’s own model
referenceImagesstring[]Up to 4 URLs from POST /v1/models/references
budgetUsdnumberSpend ceiling in USD of provider cost, capped at 50

Generate, wait, download:

# 1. submit
curl -s https://<host>/api/v1/models/generate \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{ "prompt": "twin-engine attack submarine, angular riveted hull, forward laser cannons, missile pods under the stub wings, salt-worn navy paint over bare steel" }'
# -> { "success": true, "result": { "jobId": "…", "contentId": "…", "status": "queued", "creditsReserved": 25 } }

# 2. long-poll until done
curl -s "https://<host>/api/v1/models/jobs/<jobId>?wait=240" -H "Authorization: Bearer $API_KEY"

# 3. the finished item lists every file with a URL
curl -s https://<host>/api/v1/content/<contentId> -H "Authorization: Bearer $API_KEY"

MCP and Unreal

AI agents get the same operations as the generate_model, wait_for_model_job, refine_model … tools on the MCP server; inside the Unreal Editor the plugin adds import_model and generate_and_import_model.