Skip to content

feat(mesh): add unified mesh operations registry - #329

Open
DrHepa wants to merge 1 commit into
lightningpixel:devfrom
DrHepa:feat/295-mesh-ops-registry
Open

feat(mesh): add unified mesh operations registry#329
DrHepa wants to merge 1 commit into
lightningpixel:devfrom
DrHepa:feat/295-mesh-ops-registry

Conversation

@DrHepa

@DrHepa DrHepa commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR introduces the shared mesh-operations registry proposed in #295 and migrates the existing repair, decimation, and smoothing implementations into it.

The workflow nodes now act as thin adapters over the same operations exposed through the API, giving workflows, the Modly Agent, and future editing interfaces a single execution path without changing the current node behavior.

Included changes

  • Add "api/services/mesh_ops/" with:
    • shared operation types and execution context
    • operation metadata and parameter schemas
    • registry validation and dispatch
    • canonical "repair", "decimate", and "smooth" implementations
    • a shared NDJSON workflow processor adapter
  • Add:
    • "GET /optimize/ops"
    • "POST /optimize/op/{op_name}"
  • Migrate "mesh-repair", "mesh-optimizer", and "mesh-smoother" to thin Python adapters.
  • Preserve the existing "/optimize/mesh" and "/optimize/smooth" endpoints by delegating them to the new registry.
  • Keep the existing progress, log, completion, and error protocol used by workflow process nodes.
  • Add regression coverage for the registry, operation implementations, API routes, and workflow adapters.

Registry contract

Each operation declares:

{
"id",
"label",
"params_schema",
"fn",
"destructive",
"undoable",
"category",
}

The public registry description excludes the callable and returns serializable metadata suitable for the future edit panel and agent-tool generation.

The initial built-in operations are:

  • "repair"
    • duplicate vertex and face removal
    • degenerate and folded face removal
    • non-manifold edge and vertex repair
    • configurable hole filling
  • "decimate"
    • target triangle count
  • "smooth"
    • Taubin and Laplacian modes
    • configurable iterations and smoothing strength

Schema defaults are resolved centrally by the registry, while callers may override individual parameters.

Decimator decision

This PR keeps the existing glTF Transform + "meshoptimizer" implementation as the single decimation backend.

Replacing it with a PyMeshLab-based decimator would require flattening the glTF scene through an intermediate mesh format such as PLY or OBJ. That can discard or damage document-level information such as:

  • scene hierarchy
  • materials and textures
  • UV sets
  • skins
  • joint and weight attributes
  • animations
  • multi-primitive structure

The retained backend operates on the complete glTF document and preserves the behavior of the current "mesh-optimizer" node, including:

  • welding meshes below the existing 500,000-triangle threshold
  • the current simplification ratio and error calculation
  • progress and log events
  • the existing minimum target of 100 triangles

The JavaScript implementation is now invoked through a small NDJSON bridge owned by the shared Python operation. Its dependencies continue to be resolved from the built-in "mesh-optimizer" extension, avoiding a second copy of glTF Transform or "meshoptimizer".

Runtime and packaging

Built-in Python process nodes receive the paths required to import and execute the shared backend:

  • "MODLY_API_DIR"
  • "MODLY_NODE_EXECUTABLE"
  • "EXTENSION_DIR"
  • "WORKSPACE_DIR"
  • "TEMP_DIR"

Packaged builds use Electron itself with "ELECTRON_RUN_AS_NODE=1" for the "meshoptimizer" backend, so they do not depend on a separately installed system Node.js runtime.

The dependency lookup supports both source and packaged layouts.

Backward compatibility

The existing workflow-node contracts are preserved:

  • The manifests retain the same parameter schemas.
  • Repair and smoothing keep their original PyMeshLab filter order and arguments.
  • The optimizer keeps its existing glTF Transform and "meshoptimizer" algorithm.
  • Workflow processors continue to emit the same NDJSON progress, log, done, and error messages.
  • Existing output locations and names remain unchanged.
  • The legacy optimize and smooth API routes retain their existing parameter clamps and response shapes.
  • The legacy smooth endpoint keeps its previous Laplacian behavior and texture-preservation path.

Unknown operations return "404", invalid parameters or paths return "400", and unavailable runtime dependencies return "503".

Tests

Added regression tests covering:

  • registration metadata and serialization
  • default parameter resolution
  • duplicate, invalid, and unknown operation IDs
  • parity between workflow manifests and registry schemas
  • enforcement that workflow nodes remain thin adapters
  • exact repair filter order and arguments
  • Taubin and Laplacian parameter semantics
  • legacy smoothing behavior
  • "meshoptimizer" NDJSON progress, logging, and result forwarding
  • workflow processor delegation and error compatibility
  • generic list and execution endpoints
  • legacy endpoint delegation, output naming, and parameter clamps
  • unknown-operation API responses
  • JavaScript syntax validation for the meshoptimizer runner

Validation completed successfully:

  • "npm test"
    • 103 Python tests passed
    • 128 Node tests passed
  • "npm run lint"
  • "npm run build"
  • Production Electron and built-in-node packaging
  • Real GLB integration using the Node runtime
  • Real GLB integration using Electron as the packaged Node runtime
  • A non-rigged GLB was reduced from 1,280 to 100 triangles.
  • A rigged GLB retained all 41 scene nodes, its skin, and its "JOINTS_0" and "WEIGHTS_0" attributes after simplification. The backend produced 4,664 triangles from the original 4,711 because the rig discontinuities limit safe simplification, matching the behavior of the existing optimizer.

Scope

This PR establishes the shared execution foundation only. It does not add the future edit panel, generate agent tools, dynamically register extension-provided tools, or introduce new mesh algorithms beyond those already available in Modly.

Happy to make any naming, schema, packaging, or runtime adjustments that better fit the intended v0.5 direction.

Closes #295

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant