Squash of 25 work commits (Sep 1–12):237da90render: the sprite lane hands the screen draw back the way it found it895b9a7particles: an emitter can ride a body's own frame914471fai-hub: a feed session whose last socket left ends on its idle timeout; skin: parent, skinned centroid and a nodes-only rig for retargets3fcccf3sim: the whole world is implicitly editable, and one seam says where the ground is5692fabsim: the landform world proves itself — walker through the tunnel includedf4af6dfsim: terrain knows who changed it — a plan layer over player historyadbb078render: a water volume can be physics without a picturec17480frender: a non-rigid body may carry its own orientationacad401sim: an agent with no route holds and retries instead of walking into the wall22b2bf9sim + chat: the composed world surface takes a map floor; the chat gets plan toolsfaf8112web path: the tessellator's lap timer, the trace span and the fusion cycle timer have no clock on the webd3472ebtsdf: the clock-taking XR helpers are native-only — the browser has no depth camera and no Instant4946c9esim + render: a repaint is not a world edit — colour and glow restyles never rebake the lightmap4317f58sim + render + chat: walk decks as a surface, the filmed body is no obstruction, the brief never asks9791279render: support rigged models and custom materials across viewers3ce2792sim: use deck geometry for collision and sensing c8b79ff Add portable PBR, rig and soft-body authoring support 108d423 Add transactional polygon modeling and editable asset documents 38f4d3b Refine editable modeling and firm yarn character behavior 08a2637 sim: add entity-owned lights and vehicle headlights 00d96a7 render: add clustered lights, local shadows and incremental GI cf916af render: import glTF asset extensions and wire clustered GI c6d2cca model: cut transaction memory and raise capacity limits 41af47a raytrace: add a CPU probe-ray BVH budget example c963d0a libs: the game sim splits into makepad-scene and makepad-soft-body; render, model, fab and the asset importer retarget Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
158 lines
10 KiB
Markdown
158 lines
10 KiB
Markdown
# Editable model worker API
|
||
|
||
`makepad-model` owns its state on one worker. The sandbox host handles bounded
|
||
jobs, verified asset fetch and publication through nonblocking queues.
|
||
|
||
Use metres, Y-up, local f64 authoring coordinates. Render export validates f32
|
||
range. Flat polygon faces/corners are authoritative; derived edge/radial queries
|
||
provide topology traversal. Stable element IDs and revision generations are
|
||
**decimal strings** in JSON. Material and joint ordinals are ordinary integers.
|
||
|
||
1. `model.open {"document":"robot"}` creates an empty document. The host can
|
||
also open a stored binary source by alias. It must never replace an already
|
||
open document without closing it explicitly.
|
||
2. Read `head: {"generation":"0","content":"<64 lowercase hex digits>"}`.
|
||
Pass that exact head to every mutation. Generation always advances on
|
||
edits/undo/redo; undo can restore a content hash but never an old head.
|
||
3. `model.apply {"document":"robot","request_id":"create-body",
|
||
"expected":<head>,"operations":[{"op":"cube","object":"body",
|
||
"size":[0.7,1.0,0.4]}]}` applies the entire batch or nothing. Results contain
|
||
stable selections for subsequent edits. Repeating the same request ID and
|
||
payload returns the original result; a reused ID with different payload fails.
|
||
Result receipts retain at most 128 successful requests and 2 MiB by default;
|
||
oldest receipts, including an oversized newest receipt, may be evicted;
|
||
a persisted bounded request-ID ledger refuses reuse after receipt eviction.
|
||
Exhausting the ledger is an explicit admission error, never silent reuse. Query the job when the host
|
||
returns an accepted job ID: accepted does not mean completed or published.
|
||
4. `model.inspect` accepts `document`, optional `object`, `domain`, `offset`,
|
||
and `limit` (1–128). Without `object`, use `overview`, `objects`, `materials`,
|
||
`joints`, `clips`, or `clip_keys`. With `object`, use `overview`, `vertices`,
|
||
`faces`, `corners`, `edges`, or `weights`. Face rows expose corner offsets/counts;
|
||
page `corners` for their ordered vertex IDs, UVs and normals. Every reply is
|
||
capped at 12 KiB of serialized JSON; follow the returned cursors described below.
|
||
The `solid` domain performs bounded global intersection and orientation checks;
|
||
ordinary local mesh validation explicitly leaves global solidity unchecked.
|
||
5. `model.history {"document":"robot","expected":<head>,"action":"undo"}`
|
||
also supports redo and checkpoint. Checkpoint explicitly discards undo/redo
|
||
history, advances generation, and preserves content and retry receipts.
|
||
6. `model.cancel {"job":"<accepted job id>"}` requests cancellation. Queued jobs
|
||
are removed; running jobs cancel at checkpoints. Once publication commit
|
||
begins, cancellation is too late and the result remains queryable.
|
||
7. `model.close {"document":"robot","expected":<head>}` releases the document.
|
||
|
||
Inspection pages return `items,total,offset,limit,count,omitted,next_offset,
|
||
byte_limited`. Follow the actual `next_offset` until null; restart if `head`
|
||
changes. Limits may stop pages early. `overview.inventories` supplies each
|
||
inventory's totals and preview cursor; object validation supplies
|
||
`issue_offset,issues_returned,issues_omitted,next_issue_offset`.
|
||
|
||
Vertex rows inline only a bounded weight prefix. Use `weight_offset` to page
|
||
`weights` (vertex, weight_index, joint, weight), ordered by vertex then joint.
|
||
Clip rows expose `keyframes,key_offset`; page `clip_keys` for clip, channel,
|
||
joint, path, key, time and value, ordered by clip name/channel/time. Offsets
|
||
refer to the entire domain; filter identities when crossing rows.
|
||
|
||
Apply replies retain current `head`, original `committed`, and `replayed`.
|
||
A shared 256-ID budget limits selections. `results_total,results_returned,
|
||
results_omitted,results_truncated` describe result rows. Rows contain
|
||
`result_index,object,face_count,vertex_count,selections_truncated`; full counts
|
||
include omitted IDs. `selection_face_total,selection_vertex_total,
|
||
selection_ids_returned,selection_ids_omitted` account for all results.
|
||
Selections refer to `committed`; inspection recovers surviving elements at
|
||
the current head, not intermediate elements deleted later in a batch.
|
||
Large replies never turn a successful commit into an error.
|
||
|
||
Supported operation objects (all include `op`; mesh edits also include `object`):
|
||
|
||
| op | Additional fields |
|
||
|---|---|
|
||
| cube | size: XYZ |
|
||
| plane | size: XZ |
|
||
| sphere | radius: metres, segments: 3–128, rings: 2–128, smooth?: boolean (default true); analytic radial normals, UV seam supplied |
|
||
| cylinder | radius, height: metres, segments: 3–128, smooth?: boolean (default true); centered along Y, smooth radial sides and hard caps |
|
||
| polygon_mesh | positions: XYZ arrays; polygons: [{vertices: zero-based input indices, uvs?: UV arrays, material?: integer}] |
|
||
| transform | vertices: ID strings, matrix: four row-major affine rows |
|
||
| extrude | face: ID string, offset: XYZ |
|
||
| inset | face: ID string, distance: metres; conservative planar convex inset |
|
||
| mirror | axis: 0/1/2, offset: reflection-plane coordinate; duplicates geometry |
|
||
| weld | vertices: ID strings, distance: metres |
|
||
| delete_faces | faces: ID strings |
|
||
| delete_object | none |
|
||
| uv | corner: ID string, uv: UV |
|
||
| corner_normal | corner: ID string, normal: XYZ or null to derive |
|
||
| edge_attributes | vertices: two ID strings, seam: boolean, crease: number |
|
||
| weights | vertex: ID string, weights: [{joint,weight}] |
|
||
| assign_material | faces: ID strings, material: integer |
|
||
| material | material: integer, color: linear RGB 0–1; replaces material/texture |
|
||
| texture_solid | material, width, height, color: RGB byte triple |
|
||
| paint_texture | material, center: normalized UV with top-left origin, radius: normalized distance, color: RGB byte triple |
|
||
| skeleton | joints: [{name,parent:null or earlier joint ordinal,translation: parent-local XYZ}] |
|
||
| auto_weights | object; initial rigid nearest-bone binding, editable afterward |
|
||
| subdivide | levels: 1–3; Catmull–Clark cage subdivision; preserves UV and marked edge seams; refuses creases and explicit loose-edge data |
|
||
| smooth | vertices: ID strings, iterations: 1–64, factor: 0–1, preserve_boundary: boolean |
|
||
| project_uv | faces: ID strings, axis: dropped 0/1/2 (YZ/ZX/XY), scale: UV, offset: UV |
|
||
| brush | vertices: ID strings, center: XYZ, radius: metres, delta: XYZ, max_displacement: metres; smooth grab falloff |
|
||
| clip | name, channels: [{joint,path,keys:[{time,value}]}] |
|
||
| delete_clip | name |
|
||
|
||
Skeletons have one root and parents precede children. Use `rig_rest` for arbitrary local rest translation, rotation and scale;
|
||
animation supports all three paths, FK/IK controls and portable baking.
|
||
Clip paths are `translation`, `rotation`, or `scale`. Key values have four lanes:
|
||
XYZ plus zero for translation/scale; normalized XYZW quaternion for rotation.
|
||
Times are increasing seconds. Skin export requires at most four known normalized
|
||
influences per rendered vertex and preserves each material/texture primitive.
|
||
|
||
Materials support layered PBR channels, masks, RGBA textures, alpha modes,
|
||
vertex color, emissive strength and bounded procedural/paint/bake operations.
|
||
PNG decoding and mip construction run on workers. Shape keys export real
|
||
position/normal targets and animated weights. Arbitrary shader graphs are
|
||
outside this portable material contract. Topology edits preserve corner
|
||
UV seams and vertex weights where the operation defines a mapping. Simple
|
||
nonplanar cage polygons use deterministic projected triangulation; nonplanarity
|
||
is reported, and planar inset refuses those faces. Selectors are scoped to the
|
||
expected document head and object name: an undone/recreated branch may reuse a
|
||
numeric element ID, so a selector must never be replayed against an unrelated head.
|
||
|
||
`Document::compile` produces GLB, bounds, counts and face provenance.
|
||
`Document::compile_preview` produces a static draft at the same source head,
|
||
including textures, current shape-key weights and rest-position lights while
|
||
wheel or skin binding is unfinished. The derived draft omits animation, skin,
|
||
wheel driving connections, sockets, collision and delivery LODs. It does not
|
||
modify source or relax the completion checks used for publication.
|
||
`to_bytes` stores versioned checkpoint, undo log and receipts; `from_bytes`
|
||
verifies canonical content. Publication uses `to_snapshot_bytes` to store
|
||
current editable state without cross-platform floating-point replay.
|
||
The working document retains its undo history. Transaction admission also bounds
|
||
aggregate replay work, including checkpoint decode, every retained transaction,
|
||
the most expensive undo cursor, and canonical source re-encoding. If another
|
||
edit would exceed that bound, it fails atomically with a checkpoint-required
|
||
error; call `checkpoint` explicitly to discard undo/redo before retrying. Undo
|
||
history is never silently truncated, and hostile source input keeps the same
|
||
aggregate work cap. Replay costs are measured from execution, not trusted fields
|
||
in serialized input.
|
||
|
||
The asset host publishes source and GLB in one existing `Prop` (static) or
|
||
`Character` (skinned) asset revision
|
||
(`Source/Bin`, `RenderGlb/Glb`). Alias publication requires an expected alias head
|
||
or explicit absence and a persisted asset identity. A separate expected document
|
||
head pins the intended edited content. New game clients fetch the compiled GLB;
|
||
they do not replay modeling operations. Old CSG `ModelProgram` source remains text.
|
||
|
||
Limits are provisional resource guards, not measured Quest 3 performance claims.
|
||
The default document admits 2048 objects and 512 materials, with at most 256
|
||
operations per batch. Working memory is 2 GiB, with 10 billion work units,
|
||
4,000,000 compiled triangles, 256 MiB source and 64 MiB transactions.
|
||
Undo history retains up to 4096 batches before an explicit checkpoint.
|
||
Sixteen open documents, one admitted authoring operation per host, bounded queues,
|
||
cancellation checkpoints and prepared render products prevent UI-side modeling
|
||
work. Global geometry operations have explicit resource and attribute admission rules.
|
||
|
||
The complete operation families and inspection domains are described in
|
||
[MESH_API.md](MESH_API.md), [CONSTRUCTION_API.md](CONSTRUCTION_API.md),
|
||
[SCENE_API.md](SCENE_API.md), [SURFACE_API.md](SURFACE_API.md),
|
||
[RIG_API.md](RIG_API.md), and [SELECTION_API.md](SELECTION_API.md).
|
||
`world.api` exposes these contracts to the AI. Use `surface_material` to modify
|
||
rich materials: legacy `material` refuses to discard an existing layer stack.
|
||
Deleting a clip removes its event/interpolation/morph options; deleting a morph
|
||
removes that morph's keys from all clips. Delete inbound attachments/references
|
||
in the same transaction before deleting an object they target.
|