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>
89 lines
6.9 KiB
Markdown
89 lines
6.9 KiB
Markdown
# Mesh editing and evaluated modifiers
|
||
|
||
All commands run on the owning worker, use the normal expected document head,
|
||
and participate in atomic batches, undo, retry receipts, and source checkpoints.
|
||
Element selectors are decimal strings scoped to that head and object name.
|
||
An edge is `[lower_vertex_id, higher_vertex_id]`; edge factors measure from the
|
||
lower ID. Distances use local metres, angles use radians, and axes are 0/1/2.
|
||
|
||
Every command below includes `op` and `object`. Selections must be unique.
|
||
|
||
| op | Additional fields and supported neighborhood |
|
||
|---|---|
|
||
| extrude_region | `faces`, `offset: XYZ`; manifold patches with simple boundary cycles; shared interior edges stay shared |
|
||
| split_edges | `edges`, `factor: (0,1)`; shares each new edge vertex and interpolates UVs independently per face |
|
||
| collapse_edge | `edge`, `factor: (0,1)`; unmarked manifold neighborhoods; refuses face reversal and topology pinches |
|
||
| dissolve_edge | `edge`; two coplanar, same-material faces with continuous edge UVs and no edge marker |
|
||
| fill_boundary | `vertices`, `material`; one ordered simple boundary cycle |
|
||
| bridge_boundaries | `a`, `b`, `material`; ordered, disjoint, equal-length boundary cycles; starting vertices determine correspondence |
|
||
| loop_cut | `edge`, `factor: (0,1)`; maximal opposite-edge quad strip; stops at boundaries and refuses crossed/non-quad strips |
|
||
| slide_vertices | `vertices`, `towards`, `factor: [-1,1]`; equal-length pairs must share edges |
|
||
| bevel_edges | `edges`, `width`; convex, planar, closed neighborhoods with trivalent endpoints; selected neighborhoods cannot share faces; width consumes less than half a flank edge |
|
||
| solidify | `thickness > 0`; copied surface offset along averaged vertex normals, reversed inner surface, and boundary walls |
|
||
| array | `count: 1–128`, `offset: XYZ`; count includes the original |
|
||
| bend, twist | `vertices`, `axis`, `range: [low,high]`, `angle: [-2π,2π]` |
|
||
| taper | `vertices`, `axis`, `range`, `scales: [start,end]`; positive scales |
|
||
| lattice | `vertices`, `bounds: [minXYZ,maxXYZ]`, `divisions: [nx,ny,nz]`, `displacements: XYZ[]`; 2–8 controls per axis, X fastest, selected points inside bounds |
|
||
| shrinkwrap | `vertices`, `reference: object name`, `max_distance`, `offset`; nearest reference triangle plus signed normal offset; reference mapped through `inverse(owner_world) × reference_world`, result/distance/offset in owner-local units; every selected point must match |
|
||
| decimate | `target_faces`, `max_error`; triangulates and reduces unmarked manifold edges while preserving UV/material/pin boundaries; result metrics report `achieved_faces` and `collapses` |
|
||
| sculpt | `vertices`, `kind: inflate/flatten/crease`, `center`, `normal`, `radius`, `strength`, `max_displacement`, `masks: [{vertex,value}]`, `symmetry: 0–7`; mask 1 protects, XYZ symmetry bits reflect through origin, overlapping symmetry strokes do not double displacement |
|
||
| uv_box | `faces`, `scale: UV`, `offset: UV`; chooses each face's dominant normal axis |
|
||
| uv_cylindrical | `faces`, `axis`, `scale`, `offset`; unwraps angular seams per face; vertices on the cylinder axis are refused |
|
||
| uv_unwrap | `faces`; cuts at seams/60-degree dihedrals, projects planar charts, harmonically maps disk charts, splits other charts per face |
|
||
| uv_pack | `faces`, `padding`; deterministic nonoverlapping grid atlas using a common scale; pinned or collapsed islands are refused |
|
||
| uv_relax | `faces`, `iterations: 1–128`, `factor: 0–1`; fixes boundaries/pins and never averages across UV seams |
|
||
| uv_pin | `corners`, `pinned`; pins persist in source and propagate through mapped topology copies |
|
||
| normals | `smooth`, `angle: 0–π`; crease/dihedral split normals |
|
||
|
||
`subdivide` also respects crease strengths: fractional values blend the smooth
|
||
and sharp stencils; fully sharp corners remain fixed. Pins protect projected UVs.
|
||
Pinned unwrap retains the existing boundary layout and relaxes its interior;
|
||
it refuses a collapsed constrained layout. `Mesh::uv_islands` exposes face/corner
|
||
membership, bounds, area, and pin counts for editor inspection.
|
||
|
||
Construction commands create a new object and keep input objects intact:
|
||
|
||
| op | Additional fields |
|
||
|---|---|
|
||
| sweep | `profile: XY[]` (3–128), `path: XYZ[]` (2–128), `caps`, `material`; transported local frames |
|
||
| lathe | `profile: [radius,height][]` (2–128), `axis`, `segments: 3–128`, `caps`, `material`; zero-radius endpoint poles supported |
|
||
| loft | `profiles: XYZ[][]` (2–128 equal-size rings), `closed`, `caps`, `material` |
|
||
| quad_strip | `a: XYZ[]`, `b: XYZ[]` (equal length 2–4096), `closed`, `material` |
|
||
| boolean | `a`, `b`, `mode: union/difference/intersection`; closed manifold inputs, bounded candidate pairs, unambiguous source-triangle UV/material/normal transfer |
|
||
| voxel_remesh | `source`, `resolution: 8/16/32`; bounded FaithC reconstruction with nearest-surface UV/material/weight reprojection |
|
||
|
||
Boolean and voxel operations refuse seam/crease/pin constraints they cannot map.
|
||
Booleans also refuse weighted intersection geometry; new intersections do not
|
||
have a unique rigging interpretation. Existing CSG/FaithC phases run sequentially
|
||
on the worker; cancellation is checked before/after those bounded phases, and
|
||
CSG inherits an installed cancellation token. Topology-changing output receives
|
||
new identities in the new object's scope. Local manifold validation does not
|
||
certify that arbitrary inputs or deformed shells have no global intersections.
|
||
|
||
`modifier` sets or replaces a named ordered entry:
|
||
|
||
```json
|
||
{"op":"modifier","object":"body","name":"copies","enabled":true,
|
||
"operation":{"op":"array","count":3,"offset":[2,0,0]}}
|
||
```
|
||
|
||
`enabled` defaults to true. Inner `object` may be omitted; if supplied it must
|
||
match the outer object. Each object allows 16 entries and a document allows 128.
|
||
Supported entries are subdivision, mirror, array, solidify, decimate, normals,
|
||
and deform/lattice/shrinkwrap with `vertices: []`. For a modifier, that empty
|
||
selection resolves all current evaluated vertices; an ordinary edit still
|
||
treats an empty selection as empty. Fixed element selections cannot be stored
|
||
in a stack because earlier modifiers may change topology.
|
||
|
||
Use `modifier_order {object,names:[...]}` with an exact permutation to reorder,
|
||
`remove_modifier {object,name}` to remove, and `apply_modifiers {object}` to bake
|
||
the evaluated result and clear the stack/link. A linked instance starts from its
|
||
source's evaluated mesh, then applies its own entries. Parent/link/enabled
|
||
modifier dependencies form one acyclic graph. Shared references use one immutable
|
||
cache per evaluation, and source cage meshes remain unchanged until baked.
|
||
|
||
`join` copies evaluated objects through their world transforms and preserves
|
||
UVs, weights, material IDs, split normals, seam/crease markers, and pins.
|
||
`separate` preserves those attributes and the selected element IDs in the new
|
||
object scope. Linked geometry and stacks must be made unique/baked before a
|
||
face selection is separated.
|