Edit a scene by applying a batch of operations ATOMICALLY (all-or-nothing; one undo step in the editor). Call this for any add / move / edit / delete / duplicate / group / reparent / re-material. Reference existing nodes ONLY by the id shown in get_scene — never guess ids. To create a node and then modify or parent it in the same batch, put a `tempId` on the add op and use that same string as the id/parentId of later ops. Coordinates: Y up, units ≈ meters, ground at y≈0 — place objects so they rest sensibly. Geometry size lives in `data` (box {width,height,depth}; sphere/cylinder/torus {radius}; torus {tube}); the default box is 1.5×1.5×1.5. MATERIALS: to color an object pass `color` (#rrggbb) on add/assignMaterial; to apply a GENERATED material pass `materialMaps` (the map urls from get_generation) on add/assignMaterial — both mint-or-reuse a material and assign it, no pre-existing library entry needed. WEB BLOCKS (responsive site building-blocks): add webText (data.role h1|h2|h3|body|caption + data.text; glyph outline via data.outline true|false + data.outlineColor + data.outlineWidth), webImage (data.src + data.alt), webLink (data.label + data.href or data.linkedPageId), webVideo (data.src + data.poster); any web block also accepts data.anchor = world|billboard|hud. PAGES & NEIGHBORHOODS: add a `webpage` node per page (set data.pageTitle, data.slug); place pages tens of meters apart and parent each area's content under its page to build a multi-area site. Link areas with a webLink (data.linkedPageId = target page, or data.linkedCameraId = a saved viewpoint); a tempId minted in the SAME batch works as linkedPageId, so a "sign in the park linking to the mall" can be built in one call. Set data.arrivalCameraId on a page (a camera node id, or a tempId from the same batch) to choose the viewpoint visitors ARRIVE at for it — otherwise the runtime auto-frames the page from a generic distance. It belongs on the PAGE, not on the signs: a sign that jumps to a camera skips the page change, so the URL and title would still name the previous room. TAP ACTIONS: object nodes (geometry, text3d, group, cable) take data.tap = {"action":"inspect"} (fullscreen orbit lightbox on tap — products/exhibits/hero models), {"action":"moveTo"} (camera flies to frame it — tap-to-travel on landmarks), or {"action":"link", href|linkedPageId|linkedCameraId} (navigate like a webLink). inspect/moveTo take an optional "distance" (meters) overriding the auto camera distance. Runs for visitors in the published scene. ANIMATION: object nodes (geometry, text3d, group, cable) take data.animation to move on a loop in the published scene: {"duration":4,"loop":"loop","easing":"easeInOut","tracks":{"position":[{"t":0,"v":[0,0,0]},{"t":0.5,"v":[0,0.6,0]},{"t":1,"v":[0,0,0]}]}} bobs the node half a meter. t is 0-1 across duration seconds; values are OFFSETS from the authored transform (position meters, rotation euler radians, scale a multiplier, 1 = authored size). tracks = position|rotation|scale; loop = loop|pingpong|once; optional delay seconds; max 16 keys per track. Animated nodes cost scene weight and cannot be GPU-instanced — animate a few focal objects, not everything. FAST PATH — make_page: for a page that is a heading + paragraph + some links, ONE `make_page` op builds the whole thing: pass name, data.pageTitle+data.slug, hero (h1 text), body (paragraph), and links [{label, to: a page id/tempId | href}], plus a tempId (which becomes the PAGE id so other signs can target it). Create link-target pages earlier in the batch so their tempIds resolve. It replaces ~6–12 primitive ops. SET-DRESSING: use the `scatter` op to make `count` jittered copies of a node across an {area:{x,z}} (random rotation + slight scale + optional per-copy `tint` for imported models) — efficient for many props, debris, foliage, a trashy parking lot. LARGE SCENES: build INCREMENTALLY across multiple apply_ops calls (~40–50 objects per batch) instead of one huge batch — each call is its own atomic Undo and stays well within limits; call get_scene between batches to stay aligned. Do not try to emit hundreds of operations in a single call. The result may carry `warnings` — advisory scene lint (floating content, orphan web blocks, unreadable text, crowded pages, scene WEIGHT over the perf red line). The ops APPLIED; act on warnings in your next batch unless they contradict what the user asked for. A weight warning names the heaviest categories — trim them (lower-poly models, fewer shadow lights/particles) or publish will warn and far heavier scenes are blocked.