makepad/libs/model/API.md
Admin d2130e6550 libs: model, mesh_edit, csg, scene, sim, render, xr
Squash of 25 work commits (Sep 1–12):
  237da90  render: the sprite lane hands the screen draw back the way it found it
  895b9a7  particles: an emitter can ride a body's own frame
  914471f  ai-hub: a feed session whose last socket left ends on its idle timeout; skin: parent, skinned centroid and a nodes-only rig for retargets
  3fcccf3  sim: the whole world is implicitly editable, and one seam says where the ground is
  5692fab  sim: the landform world proves itself — walker through the tunnel included
  f4af6df  sim: terrain knows who changed it — a plan layer over player history
  adbb078  render: a water volume can be physics without a picture
  c17480f  render: a non-rigid body may carry its own orientation
  acad401  sim: an agent with no route holds and retries instead of walking into the wall
  22b2bf9  sim + chat: the composed world surface takes a map floor; the chat gets plan tools
  faf8112  web path: the tessellator's lap timer, the trace span and the fusion cycle timer have no clock on the web
  d3472eb  tsdf: the clock-taking XR helpers are native-only — the browser has no depth camera and no Instant
  4946c9e  sim + render: a repaint is not a world edit — colour and glow restyles never rebake the lightmap
  4317f58  sim + render + chat: walk decks as a surface, the filmed body is no obstruction, the brief never asks
  9791279  render: support rigged models and custom materials across viewers
  3ce2792  sim: 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>
2026-09-15 13:40:31 +02:00

10 KiB
Raw Permalink Blame History

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, CONSTRUCTION_API.md, SCENE_API.md, SURFACE_API.md, RIG_API.md, and 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.