Skip to content

feat(mesh-ops): semantic transforms and one-call arrange (T-A3) - #377

Merged
lightningpixel merged 1 commit into
devfrom
feat/297-semantic-transforms
Oct 19, 2026
Merged

lightningpixel merged 1 commit into
devfrom
feat/297-semantic-transforms

Conversation

@lightningpixel

Copy link
Copy Markdown
Owner

Closes #297

Summary

Adds high-level transforms on top of the raw 4×4 /transform endpoint, so "put it on the ground, center it and lay it flat" works in a single chat message — one tool call, one output file.

  • recenter — moves the centroid to the origin.
  • drop_to_ground — moves the lowest point to y = 0.
  • auto_orient — lays the mesh flat: the smallest rotation that turns its thinnest PCA axis vertical. No spin about the vertical axis, never flipped upside down, and meshes without a clear flat side (cube, sphere) are left alone.
  • normalize_scale — resizes to size in m / cm / mm (glTF metres), along the longest side or a chosen axis. Scales around the origin, so a centred, grounded mesh stays so.

Changes

  • api/services/mesh_ops/transforms.py — each step builds its matrix from the mesh as the previous steps left it. apply_transforms loads once, runs the steps in a fixed order (orient → scale → recenter → ground, whatever order they were requested in) and writes one file. The /transform gizmo endpoint now uses the same transform_file helper, unchanged in behaviour.
  • The 4 ops are registered under the transform category with flat params_schema, ready for the edit panel (T-C1).
  • POST /optimize/arrange — composes several steps into one file, validating each step's params through the registry (unknown step or bad param → 400).
  • Agent: arrange_mesh tool, with a prompt rule to pass every step in one call. Its result includes the new mesh path, so the model can chain another tool on it. MCP server: modly_arrange_mesh.
  • Refactor: world-space geometry helpers move to mesh_ops/geometry.py (shared with inspect_mesh); the registry exposes resolve_params.

Testing

  • npm run test:py — 257 tests pass (4 skipped). 17 new tests: canonical order on a tilted, offset plate; centroid to origin; vertical-only grounding; cube left alone; bowl not flipped; 20 cm / 5 mm; scaling keeps the mesh grounded; multi-node scenes in world space; textures preserved; input never modified; invalid steps rejected. Router (/arrange in a moved workspace) and agent tests added.
  • On Khronos sample models (Duck, Avocado, DamagedHelmet, BoxTextured): textures and UVs preserved, longest side exactly 20 cm, lowest point at 0.
  • ~1.6 s for all four steps on 1.3M faces.

Notes

  • The viewer already centres and grounds every mesh on display, so recenter and drop_to_ground change the exported file but nothing on screen.
  • auto_orient lays a standing figure down — that is what "lay flat" means.
  • Exports keep glTF metres, so a 20 cm mesh exported to STL reads as 0.2 mm in a slicer — that's T-D2 / T-H1.

…point

Four registry ops derive their 4x4 matrix from the mesh itself:
recenter (centroid to origin), drop_to_ground (lowest point to y = 0),
auto_orient (smallest rotation that turns the thinnest PCA axis
vertical; meshes without a clear flat side are left alone) and
normalize_scale (size in m/cm/mm along the longest side or one axis).

apply_transforms composes requested steps in a fixed order (orient,
scale, recenter, ground) on one load and writes a single file, so
grounding is never undone by a later step. POST /optimize/arrange
exposes it, validating each step's params through the registry, and
the raw /transform endpoint now shares the same bake helper.

The agent and MCP server get an arrange_mesh tool that takes every
step at once and reports the new mesh path for chaining.

The world-space geometry helpers move to mesh_ops/geometry.py, shared
with inspect_mesh, and the registry exposes resolve_params.

Closes #297
@lightningpixel lightningpixel added this to the Release 0.5 milestone Oct 19, 2026
@lightningpixel lightningpixel added the feature New feature label Oct 19, 2026
@lightningpixel lightningpixel self-assigned this Oct 19, 2026
@lightningpixel
lightningpixel merged commit f502eb9 into dev Oct 19, 2026
5 checks passed
@lightningpixel
lightningpixel deleted the feat/297-semantic-transforms branch October 19, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant