grid-apps-cmms/docs/agents.md
2026-02-14 19:00:48 -05:00

39 KiB

AI Agent TL;DR - gs-apps

Quick reference for AI agents working on this project.

What Is This?

gs-apps is a monorepo containing three Grid.Space web applications:

App Purpose Status Entry Point
kiri:moto Multi-axis CNC/FDM/SLA slicer Production src/main/kiri.js
mesh:tool 3D mesh editor & repair Active dev src/main/mesh.js
void:form Parametric CAD modeler Phase 1 src/main/void.js

All three share common infrastructure in src/moto/, src/geo/, src/load/, and src/ext/.


1. KIRI:MOTO - CNC/FDM/SLA Slicer

Purpose

Multi-mode manufacturing tool for slicing 3D models for CNC milling, 3D printing, laser cutting, SLA, wire EDM, and waterjet.

Architecture

src/
├── main/kiri.js           # Bootstrap entry point (2.3KB)
├── kiri/
│   ├── app/              # Application layer (45 modules)
│   │   ├── api.js        # Main API surface (~10KB)
│   │   ├── platform.js   # Platform/printer setup (~40KB)
│   │   ├── inputs.js     # UI input handling (~30KB)
│   │   ├── paint.js      # Viewport rendering (~23KB)
│   │   ├── widget.js     # Core slicing widget (~12KB)
│   │   ├── devices.js    # Machine definitions
│   │   └── conf/         # Device/process configs
│   ├── core/             # Engine core (7 modules)
│   │   ├── codec.js      # Data encoding/decoding
│   │   ├── print.js      # Print/slice object (~30KB)
│   │   ├── slice.js      # Slicing logic
│   │   └── widget.js     # Widget manipulation (~30KB)
│   ├── mode/             # Machine implementations (7 types)
│   │   ├── cam/          # CNC/CAM milling
│   │   ├── fdm/          # 3D printing (FDM/FFF)
│   │   ├── laser/        # Laser cutting/engraving
│   │   ├── sla/          # Resin printing (SLA)
│   │   ├── drag/         # Drag operations
│   │   ├── wedm/         # Wire EDM cutting
│   │   └── wjet/         # Water jet cutting
│   └── run/              # Worker/threading (5 modules)
│       ├── worker.js     # Worker orchestration (~25KB)
│       ├── engine.js     # Engine execution (~6KB)
│       └── minion.js     # Worker pool (~10KB)

Key Features

  • Multi-threaded slicing: Web Worker pool (up to 4 minions)
  • Multiple modes: CAM, FDM, LASER, SLA, WEDM, WJET
  • Device profiles: JSON-based machine configs (src/cli/)
  • Widget-based: Objects as "widgets" for slicing operations
  • Tabs interface: Multi-document workspace

Routes

  • /kiri/ - Main slicer interface
  • /lib/pack/kiri-main.js - Main bundle (~28KB minified)
  • /lib/pack/kiri-work.js - Worker bundle
  • /lib/pack/kiri-eng.js - Engine bundle

Documentation

  • Full docs: /Users/stewart/Code/gs-apps/docs/kiri-moto/
  • API reference: /Users/stewart/Code/gs-apps/docs/kiri-moto/apis.md

Database (IndexedDB)

  • Device profiles, process settings, print history
  • Workspace restoration

2. MESH:TOOL - 3D Mesh Editor

Purpose

Direct 3D mesh editing, boolean operations, mesh repair, face/edge selection, and 2D sketch system.

Architecture

src/
├── main/mesh.js          # Bootstrap entry point (29KB)
└── mesh/
    ├── api.js            # Main API surface (~1,730 lines)
    ├── build.js          # UI builder (~42KB)
    ├── model.js          # Mesh model class (~26KB)
    ├── group.js          # Group/assembly (~4KB)
    ├── tool.js           # Tool operations (~35KB)
    ├── work.js           # Worker communication (~19KB)
    ├── sketch.js         # 2D sketch mode (~22KB)
    ├── handles.js        # Manipulation handles (~9KB)
    ├── edges.js          # Edge visualization (~6KB)
    ├── history.js        # Undo/redo system
    └── util.js           # Utilities (~9KB)

Key Features

  • Mode-based UI: Object, Tool, Face, Surface, Edge, Sketch modes
  • Boolean operations: Union, intersect, difference (Manifold WASM)
  • Mesh repair: Heal, clean, triangulate
  • Face/edge selection: Direct geometry manipulation
  • 2D sketching: Sketch on 3D planes
  • Group management: Assemblies and hierarchy
  • Undo/redo: Full history system

UI Components

  • Feature tree (left panel)
  • Mode buttons (object/tool/face/surface/edge/sketch)
  • Object properties panel
  • Wireframe/normals visualization

Routes

  • /mesh/ - Main mesh editor
  • /lib/pack/mesh-main.js - Main bundle
  • /lib/pack/mesh-work.js - Worker bundle

Database (IndexedDB)

  • admin store - Metadata, preferences, cache
  • space store - Models, groups, sketches

Documentation

  • /Users/stewart/Code/gs-apps/docs/mesh-tool.md

3. VOID:FORM - Parametric CAD

Purpose

Onshape-inspired parametric CAD with constraint-based sketching, feature history, and BREP operations.

Architecture

src/
├── main/void.js          # Bootstrap entry point (210 lines)
└── void/
    ├── api.js            # API composition root
    ├── api/
    │   ├── document.js   # Document persistence + revisions/undo/redo
    │   ├── features.js   # Feature list mutations
    │   ├── origin.js     # Origin point visibility/state
    │   ├── sketch.js     # Sketch feature creation scaffold
    │   ├── sketch_runtime.js # Sketch runtime orchestrator/state
    │   ├── sketch_runtime_arc.js # Arc/line endpoint + arc sampling helpers
    │   ├── sketch_runtime_markers.js # Sketch point/arc-center marker builders
    │   ├── sketch_runtime_profiles.js # Closed-profile detection + fill loops
    │   └── sketch_runtime_ui.js # Sketch runtime style/preview/glyph UI helpers
    ├── toolbar.js        # Top toolbar UI
    ├── tree.js           # Tree composition root
    ├── tree/
    │   ├── model.js      # Tree data/section logic
    │   └── render.js     # Tree DOM builders
    ├── overlay.js        # 2D/3D tracking overlay
    ├── datum.js          # Datum planes (XY, XZ, YZ)
    ├── plane.js          # Plane primitive class
    ├── interact.js       # Interaction composition root + event wiring
    ├── interact/
    │   ├── sketch.js     # Sketch interaction orchestrator (event flow + mutations)
    │   ├── sketch_constraints_actions.js # Constraint apply/toggle/delete actions
    │   ├── sketch_marquee.js # Marquee selection + geometry hit rules
    │   ├── sketch_pointer.js # Pointer/hover/drag gesture handlers
    │   ├── sketch_tools.js # Sketch tool mode + keybinding behavior
    │   ├── sketch_geometry.js # Sketch hit-test/projection/drag geometry helpers
    │   ├── sketch_constants.js # Shared sketch interaction constants
    │   ├── planes.js     # Plane hover/select/resize + view-normal
    │   ├── points.js     # Point hover/select hit-testing
    │   ├── selection.js  # Shared selection state transitions
    │   └── targets.js    # Sketch target/frame resolution
    ├── sketch_constraints.js # Constraint orchestration (planegcs + post-solve hooks)
    ├── sketch_constraints_fallback.js # Legacy/incremental fallback solver
    ├── sketch_constraints_tangent.js # Tangent constraint solver helpers
    └── viewcube.js       # ViewCube navigation widget (NEW)

Key Features

  • Feature tree scaffold: Sidebar structure is present; full history dependency/update graph is not wired yet
  • Datum planes: XY, XZ, YZ reference planes
  • Constraint sketching: integrated (@salusoft89/planegcs + fallback solver path)
  • Manifold BREP: planned feature path (extrude/cut/revolve), early stubs today
  • Onshape camera: Left=select, Middle=pan/zoom, Right=rotate
  • ViewCube: 3D navigation widget (top-right corner)
  • 2D overlay: SVG overlay for 3D point tracking

Status

Very early development (Phase 1 foundation, early feature workflow in place)

  • 3D viewport with Onshape camera controls
  • Datum planes with interaction
  • Feature tree with default geometry visibility controls
  • ViewCube navigation widget
  • 2D/3D overlay system
  • Document persistence + revision history with undo/redo
  • Sketch feature creation scaffold (target plane/face -> sketch feature entry)

Current implementation notes (important for agents)

  • Direct-call architecture in void:form (no broker event bus in current runtime path)
  • toolbar wires real actions for docs, camera modes, undo/redo, and sketch creation
  • toolbar now includes a Preferences dialog () with persisted runtime tuning:
    • solid edge loop-promotion threshold (segment count)
    • solid edge hover/select Line2 widths
    • fit padding (perspective + orthographic)
  • tree.render() is still caller-driven for feature mutations; refresh explicitly after non-tree-originated changes
  • src/main/void.js currently enables overlay test primitives with a hardcoded if (true) block (debug scaffolding)
  • Origin in void is an overlay point (not space.platform origin)
  • IndexedDB revision store name is versions (older notes may still mention features)
  • Feature tree now includes early history controls:
    • per-feature suppress/unsuppress
    • feature reorder (up/down)
    • timeline slider (0..N) controlling active rebuild prefix
    • all above are revisioned + undo/redoable
    • feature creation now inserts at the active timeline marker (index + 1) instead of always appending to the end
  • Sketch runtime currently renders from the active rebuild set (features.listBuilt()), not raw full feature list
  • Open TODO: stabilise dual-tangent sketch behavior (line tangent to two circles/arcs with endpoint-on-arc constraints)
  • Min/max distance constraints are now wired (circle/arc vs point/line/circle-arc) but still need stability tuning under drag:
    • current known issue: circle-in-box (min to two orthogonal lines) can feel jerky while drag-resizing radius
    • current implementation favors deterministic branching for line targets; revisit with solver-side branch lock per drag gesture if needed
  • Known regression history: commit 5093eec4 introduced an overly permissive derived-edge proximity gate (segLen * 0.35) in resolveDerivedEdgeCandidate; this causes incorrect face/edge picks in sketch derive hover. Keep tight gate (2.5) unless replaced with a screen-space metric.
  • Geometry graph refactor plan is tracked in docs/void/plan-geomgraph.md (surfaces + boundaries as canonical entities; solids as derived artifacts).
  • Derived sketch entity rearchitecture plan is tracked in docs/void/plan-derived.md (immutable, rebuild-driven references to upstream geometry).
  • Terminology (use consistently in code/docs/issues):
    • segment: one boundary edge between two 3D points
    • chain: ordered open polyline of connected segments
    • loop: ordered closed polyline of connected segments
    • surface: bounded face patch on a solid (planar or curved)
    • region: selectable enclosed 2D sketch profile area
  • TODO (open): de-dup overlapping boundary projections/derives in sketch Use (u) flow.
    • Symptom: side faces on cubes/cylinders/arc-cutouts can project/derive overlapping duplicate lines.
    • Requirement: de-dup identical segments/chains by geometric equivalence (endpoint tolerance + chain shape/length), not by source face id.
  • Phase 0 scaffolding status:
    • new GeometryStore API is wired as the single active path (no rollout flags)
  • Phase 1 in-progress status:
    • surface/profile/edge hover ranking logic has been extracted into src/void/interact/selection_resolver.js
    • src/void/interact/planes.js#getPrimarySurfaceHitFromIntersections() is now a thin delegate to the resolver
    • current behavior is parity-focused (same thresholds and tie-break order), giving a stable seam for future boundary/surface entity routing
    • resolver now accepts explicit mode + intents context (SELECTION_MODES, SELECTION_INTENTS) while preserving current behavior
    • resolver candidates now carry passive canonical entity descriptors:
      • profile -> region
      • solid-face -> surface
      • solid-edge -> boundary-segment
    • resolver now sources canonical face/edge entity ids from solids runtime mappings when available:
      • face key -> surface:* (stable)
      • edge key -> segment:* (stable)
      • loop edge key -> boundary:* (stable)
      • canonical ids are now primary for selection entity payloads
    • solids runtime now publishes a passive geometry snapshot into document.geometry_store on sync:
      • surfaces, boundaries, segments, points, regions, topology maps
      • still read-only; selection and ops remain on legacy paths for parity
    • sketch profile/area selection now toggles multi by default (no cmd/meta required); clear remains on space/esc
    • derive (u) path now carries canonical entity metadata for segment-backed sources:
      • source.entity.kind = boundary-segment
      • source.entity.id = segment:faceedge:<faceKey>:<segIndex>
      • plus source.face_key and source.boundary_segment_id for migration bridging
    • extrude profile targets now use region_id (canonical key) only in selection + rebuild paths
    • chamfer edge refs now carry canonical boundary metadata:
      • boundary_segment_id and entity: { kind: 'boundary-segment', id: 'segment:...' }
      • chamfer selection sync/remove resolves through canonical boundary refs
      • chamfer apply consumes canonical refs (legacy parse path removed)
    • boolean/solid-op editing paths removed input.solids compatibility branches (use targets/tools only)
    • TODO (tracked): during sketch editing, allow Use (u) derive from other visible sketch entities

Phase 2: Sketch System (Current Workstream)

  • planegcs constraint solver integration is active
  • sketch runtime supports point/line/arc/circle/rectangle workflows
  • sketch mirror mode is now Onshape-style:
    • select exactly one line as mirror axis, then press M (or use Constraints -> Mirror)
    • while mirror mode is active, clicking sketch entities mirrors them immediately and keeps the axis highlighted
  • sketch circular pattern mode (new, WIP):
    • enter from Pattern -> Circular with exactly one selected center point (point/origin/arc-center)
    • while active, clicking sketch entities creates linked circular copies around that center
    • pattern constraint glyph stays visible, supports drag offset, and double-click edits copy count
    • deleting the pattern glyph removes the driving pattern constraint and leaves copied geometry unbound
    • known regression (open): after certain circular-pattern drag operations, some entities become effectively locked/non-movable
      • observed after moving patterned elements with additional constraints in sketch
      • likely in drag ownership propagation / fallback solver interaction for circular_pattern
      • status: unresolved, needs focused repro + solver trace
  • sketch grid pattern mode (new, WIP):
    • entered via Pattern -> Grid, requires exactly one selected sketch point as anchor
    • creates two construction guide lines (U/V) from anchor with default horizontal/vertical constraints
    • renders two always-visible count glyphs (Hn, Vn) near guide endpoints (double-click to edit counts)
    • copies are regenerated from source using guide-line vectors (guide constraints can be removed for skewed grids)
    • known issues (open):
      • dragging the grid anchor can invert U/V construction line direction unexpectedly
      • patterned circle dimension behavior is inconsistent between source and clone circles (dimension propagation/ownership)
    • mirror axis is highlighted purple while mode is active
    • each subsequently selected sketch entity is mirrored immediately across that axis
    • Esc or Space exits mirror mode
  • constraints currently wired: coincident, point-on-line, fixed, horizontal, vertical, perpendicular, equal, collinear, tangent, arc-center coincident, midpoint, min-distance, max-distance
  • deferred: Onshape-like under/fully constrained coloring for sketch entities needs a custom per-entity DoF analysis layer on top of planegcs (not directly exposed as per-entity status by solver)
  • horizontal/vertical can target line entities or a selected point pair
  • rectangle tools are implemented as constrained line sets:
    • corner rectangle
    • center rectangle

Phase 3: Feature History Scaffold (in progress)

  • extrude can now be created as a history feature from a selected sketch (tree + document/history plumbing)
  • 3D solid generation/rebuild is active via Manifold replay (extrude + boolean paths)
  • timeline/reorder/suppress semantics are active at the feature-history layer before full BREP ops
  • chamfer scaffolding (phase-1 UI only) is active:
    • solid-mode edge hover/select now parallels face hover/select
    • Chamfer feature can be created from selected edges (toolbar button + properties dialog with edge list)
    • geometry mutation/rebuild for chamfer edges is not yet applied (selection/dialog/history plumbing only)

Solid Pipeline (new scaffold)

  • void now has a dedicated solid path (separate from kiri/mesh CSG wrappers):
    • src/void/api/solids.js (rebuild scheduling + orchestration)
    • src/void/solid/kernel.js (direct Manifold JS initialization/extrude entrypoint)
    • src/void/solid/rebuild.js (feature replay -> generated solids artifacts)
    • src/void/solid/provenance.js (seed provenance model for feature/profile->body mapping)
    • src/void/worker/solids_worker.js (phase-1 compute worker for rebuild replay)
  • Solids tree should read generated artifacts (doc.generated.solids) rather than mirroring feature rows.
  • Phase-1 worker behavior (current):
    • main thread builds a compact rebuild snapshot (builtFeatures, sketch planes, profile loops)
    • worker runs feature replay + manifold ops off-main-thread
    • mesh payload returns as transferable typed arrays (zero-copy ArrayBuffer transfer)
    • if worker fails, runtime falls back to existing main-thread rebuild path
  • Path forward:
    • phase-2: incremental suffix replay + cancellation preemption
    • phase-3: cached per-feature artifacts keyed by input hash
    • phase-4: worker pool for independent heavy ops (exports/tessellation), keeping deterministic rebuild order

Sketch MVP Contract (checkpointed, 2026-02-06)

  • Primitive rollout:
    • v1: point + line
    • arc implemented
    • circle implemented (internal circle-mode arc representation)
    • Rectangle is not a primitive; model as constrained lines (corner/center patterns)
  • Input behavior:
    • Click+drag creation for points and lines
    • No snapping/inference in v1; rely on explicit constraints
  • View behavior:
    • No auto camera orientation on sketch edit entry (user uses n manually)
    • Non-edit sketch display remains gray when visible, hidden when invisible
    • While editing a sketch, disable hover-highlight behavior for that sketch
  • Coordinate model:
    • Store sketch geometry in sketch-local 2D coordinates
    • Plane/frame transform maps sketch-local geometry into 3D scene
    • This is required for future derived geometry from non-datum faces/parts
    • When rendering world-space derived previews inside sketch runtime, convert world coords to parent-local before drawing (avoid double-transform rotation/offset artifacts)
    • For solid feature ops that derive cutters from selected edges (ex: chamfer), preserve mesh-topology edges (indices adjacency) instead of position-welding vertices for adjacency lookup. Position welding can pair non-adjacent triangles and rotate/offset generated cutters.
    • Chamfer cutter prism winding matters: keep end-cap triangle winding outward/consistent with side faces. Reversed cap winding can make Manifold subtraction fail (NotManifold) even when cutter placement is correct.
  • Constraint rollout (checkpoint):
    • Solver-backed enforcement is active (planegcs + fallback)
    • Implemented:
      • Lines: horizontal, vertical, perpendicular
      • Points: coincident, fixed
      • Arc/Circle: arc_center_coincident
    • Next target set:
      • equal (line length), collinear, tangent
  • Dimensions:
    • Support both driven and derived dimensions (for later variable system)
  • Selection roadmap:
    • v1: click selection
    • later: rectangle selection parity with Onshape semantics:
      • right-drag = must fully enclose
      • left-drag = crossing/touch selects
    • TODO later: bring rectangle/marquee selection parity to non-sketch (global 3D) mode
  • Construction geometry:
    • Required early
    • Toggle selected entity construction state with q
    • Construction lines render dashed
  • Undo/redo granularity:
    • One undo unit per mutation (entity create/complete move/change, dimension change)
    • Not per low-level pointer gesture frame

Sketch Point Rendering (current)

  • Sketch point and arc-center markers are now shader-based (THREE.Points + fragment rings) in WebGL:
    • camera-facing, circular, pixel-sized (zoom invariant)
    • avoids DOM overlay jitter at high entity counts
  • Legacy _markerParts compatibility shims are retained so existing hover/select styling code paths continue to work.
  • Centralized JS color tuning now starts in src/void/palette.js (current coverage: sketch + viewcube, expanding incrementally).
  • Sketch non-construction lines/arcs now use Line2/LineMaterial for visible hover/select thickness control (lineWidths in palette).
  • Arc/circle sketch dimensions now use diameter semantics (stored/edited/measured as diameter; solver applies radius = diameter / 2). Dimension decoration renders:
    • inside circle/arc: full diameter line with arrow end caps
    • outside circle/arc: leader line with arrow pointing to the circle
  • Known runtime refresh issue (open, under validation):
    • if pointer remains over tree/panels long enough, viewport updates can appear stalled (sketch hover/render). Keep space activity/refresh alive for UI-target mousemove paths.

Routes

  • /void/ - Primary URL
  • /form/ - Alias (same app)

Database (IndexedDB)

  • admin store - Metadata, camera position
  • documents store - Document data
  • versions store - Revision history (snapshots/deltas)

Documentation

  • /Users/stewart/Code/gs-apps/VOID-FORM.md - Full implementation notes

Dependencies (Unique to void:form)

  • @salusoft89/planegcs ^1.1.7 - 2D constraint solver (active)

Shared Infrastructure

All three apps build on common modules, but usage patterns differ by app:

Core Systems (moto/)

1. Event System (broker.js - 156 lines)

Used heavily by kiri:moto and mesh:tool. void:form currently does not use broker in its runtime path.

import { broker } from '../moto/broker.js';

// Publish
broker.publish('feature.selected', { id: 'plane-1' });

// Subscribe
broker.subscribe('feature.selected', (data) => { ... });

// Typed send interface
broker.send.feature_selected({ id: 'plane-1' });

2. 3D Viewport (space.js - 55KB)

Three.js wrapper with camera, scene, and interaction:

import { space } from '../moto/space.js';

// Initialize viewport
space.init(container, onMove, useKeys);

// Scene hierarchy
SCENE (Three.js Scene)
└── WORLD (THREE.Group, rotated -π/2 on X-axis)
    └── Your objects here

// Use space.world.add(), NOT space.scene.add()
space.world.add(group);

// Camera controls (Onshape-style for void, configurable for others)
space.view.top()           // Top view
space.view.front()         // Front view
space.view.right()         // Right view
space.view.left()          // Left view
space.view.back()          // Back view
space.view.bottom()        // Bottom view
space.view.fit()           // Fit all to view

// Camera state
space.view.save()          // Returns { left, up, panX, panY, panZ, scale }
space.view.load(state)     // Restore saved state
space.view.getFocus()      // Get orbit target
space.view.setFocus(vec3)  // Set orbit target

// Mouse bindings (configurable)
RIGHT = Orbit   // Rotate around target
MIDDLE = Pan    // Pan view
WHEEL = Zoom    // Zoom in/out

// Internals access
const { camera, renderer, raycaster, platform, container } = space.internals();

// Listen for camera changes
space.view.ctrl.addEventListener('change', callback);

// After-render callbacks (for ViewCube, etc.)
space.afterRender((renderer) => {
    // Custom render pass
    viewcube.render(renderer);
});

// Tracking plane for drag operations (void:form)
space.tracking.setMode('camera-aligned');  // 'platform', 'camera-aligned', 'world-xy'
space.tracking.setDistance(1000);          // Distance from camera
space.tracking.getMode();                  // Get current mode
space.tracking.getPlane();                 // Get THREE.Mesh for advanced use

3. Camera Controls (orbit.js - 25KB)

Orbit control class for camera manipulation:

  • Spherical coordinates (theta/phi)
  • Pan, zoom, rotate operations
  • Tweening for smooth animations
  • Touch support

4. Web UI Helpers (webui.js - 4KB)

import { $, $C, h } from '../moto/webui.js';

$('element-id')           // Get element by ID
$C('ClassName')           // Get elements by class
h.div([...])              // Create DOM elements

5. Worker System (client.js, worker.js)

Web Worker abstraction with promise-based API:

import { client } from '../moto/client.js';

const worker = client.new('worker-url.js');
worker.send('method', data).then(result => { ... });

Geometry & Math (geo/)

Shared by all apps for 2D/3D operations:

  • base.js - Core math utilities (22KB)
  • polygon.js - 2D polygon operations (48KB)
  • polygons.js - Multi-polygon operations (39KB)
  • point.js - Point data structure (30KB)
  • paths.js - Path operations (27KB)
  • slicer.js - Slicing algorithms (31KB)
  • line.js, bounds.js, csg.js, etc.

File Loading (load/)

Format detection and parsing:

  • file.js - Auto-detect file type
  • stl.js - STL (binary & ASCII)
  • obj.js - Wavefront OBJ
  • 3mf.js - 3MF (Microsoft 3D)
  • step.js - STEP (CAD format)
  • svg.js - SVG (2D vector)
  • gbr.js - Gerber (PCB format)
  • png.js - PNG (height map)

External Libraries (ext/)

Pre-integrated WASM and libraries:

  • three.js - Three.js v0.182.0 (2.4MB)
  • manifold.js - 3D boolean operations (WASM)
  • quickjs.js - JavaScript VM (2.4MB WASM)
  • jszip.js - ZIP file handling
  • jspoly.js - Polygon library (240KB)
  • clip2.js - Polygon clipping (203KB)
  • pngjs.js - PNG reading
  • earcut.js - Polygon triangulation
  • tween.js - Animation tweening
  • md5.js - MD5 hashing

Data Storage (data/)

IndexedDB wrapper:

import { open as dataOpen } from '../data/index.js';

const stores = dataOpen('dbname', {
    stores: ['admin', 'documents'],
    version: 1
}).init();

const db = {
    admin: stores.promise('admin'),
    documents: stores.promise('documents')
};

db.admin.put('key', value);
db.admin.get('key').then(value => { ... });

Common Architectural Patterns

1. Three.js Native Objects

All 3D primitives are native Three.js objects:

import { THREE } from "../ext/three.js";

const { Group, Mesh, LineSegments, BoxGeometry, MeshBasicMaterial } = THREE;

// Create as Group with children
const group = new Group();
group.add(mesh);
group.add(outline);

// Add userData for back-references
group.userData.featureType = "plane";
group.userData.plane = this;

// Set renderOrder to control draw order (avoid z-fighting)
mesh.renderOrder = 1;
outline.renderOrder = 2;

// Transparent objects MUST have depthWrite: false
const material = new MeshBasicMaterial({
  transparent: true,
  opacity: 0.5,
  depthWrite: false, // CRITICAL for transparency
});

2. Event-Driven Communication

kiri:moto and mesh:tool use broker for loose coupling. void:form currently uses direct module calls/shared API state.

// Subscribe to events
broker.subscribe("model.updated", (data) => {
  updateUI(data);
});

// Publish events
broker.publish("model.updated", { model });

// Or use typed interface
broker.send.model_updated({ model });
// void:form pattern (current)
api.document.create();
api.features.add(feature);
tree.render();
datum.updateLabels(overlay);

2.1. Void Interaction Contract (Current)

void:form interaction is currently plane-centric and depends on userData back-references:

  • Raycast targets are returned from interact.getInteractiveObjects()
  • Selection/hover resolve via intersection.object.userData.plane
  • Drag-resize logic is implemented for plane corner handles (handleType = 'plane-resize')
  • space.mouse.*Select() callbacks are two-phase: first call with no event returns raycast targets, second call handles resolved intersections
  • For resize start, interact.downSelect should prioritize handle hits from full intersections (ints) so selected handles remain draggable when occluded by plane meshes
  • Non-plane feature types should extend src/void/interact/planes.js + src/void/interact/targets.js; registerPlane() alone is not sufficient for custom interactions
  • Plane labels should be bound to plane changes (size/position/rotation/label), not only camera movement

3. Mouse Interaction Pattern

Standard pattern across all apps:

space.mouse.downSelect((intersection, event, allIntersections) => {
  if (!event) {
    // Return objects for raycasting
    return [mesh1, mesh2, mesh3];
  }
  // Handle click
  if (intersection) {
    const obj = intersection.object.userData.myObject;
    // ... do something
  }
});

space.mouse.onHover(
  (intersection, event, allIntersections) => {
    if (!event) return getInteractiveObjects();
    // Handle hover
  },
  () => {
    // Handle hover exit
  }
);

space.mouse.onDrag((delta) => {
  // Handle drag (delta = {x, y} in pixels)
});

4. Worker/Threading Pattern

  • Kiri: Multi-threaded minion pool for slicing (up to 4 workers)
  • Mesh: Single worker for heavy 3D operations
  • Void: Single worker for solid rebuild replay (active), constraint solve still on main thread

5. API Surface Pattern

Each app exports main api object:

// Kiri API - ~45 subsystems
api.widgets, api.function, api.mode, api.work, api.device, ...

// Mesh API - ~18 subsystems
api.selection, api.group, api.model, api.sketch, api.tool, ...

// Void API - ~6 subsystems (expanding)
api.document, api.features, api.sketch, api.origin, api.selection, api.datum, ...

6. Database Pattern

IndexedDB with named stores, per-app schema:

dataOpen("appname", { stores: ["admin", "data"], version: 1 });
api.db.admin.put(key, value);
api.db.data.get(id);

Key Differences Between Apps

Aspect Kiri:Moto Mesh:Tool Void:Form
Purpose Slicing for manufacturing Mesh editing & repair Parametric CAD design
Data Model Widget-based slicing Triangle mesh + sketches Early document/features scaffold + datum planes
UI Pattern Tabs + device/process panels Tree + mode buttons Toolbar + feature tree scaffold
3D System space.js + platform space.js + platform space.js + datum planes
Calculation Web Workers (minion pool) Web Worker Single rebuild worker (active)
Modes CAM/FDM/LASER/SLA/WEDM/WJET Object/Tool/Face/Surface/Edge/Sketch Sketch mode (phase 2)
Mouse Configurable bindings Standard bindings Onshape-style bindings
Database Profiles, settings, history Models, groups, sketches Documents + versions revision history
Status Production mature Actively developed Very early prototype / Phase 1 foundation
API Size ~10KB, 45 subsystems ~1,730 lines, 18 subsystems Split modules (document/features/origin/sketch)

Common Tasks

Adding a New Feature Type (void:form)

  1. Create class in src/void/yourfeature.js similar to Plane
  2. Return THREE.Group with children (mesh, outline, handles)
  3. Set userData.featureType = 'yourtype' and userData.yourfeature = this
  4. For plane-like behavior, register with interact.registerPlane(); for non-plane behavior, extend src/void/interact/planes.js hit-testing and/or src/void/interact/targets.js
  5. If the feature has labels/anchors, expose change notifications so overlays update on geometry/transform edits
  6. Update api.document/features and refresh dependent UI directly (no broker path today)

Adding a Tool Operation (mesh:tool)

  1. Add function to src/mesh/tool.js
  2. Register in api.tool.yourOperation()
  3. Send to worker if heavy operation (api.work.send())
  4. Update UI via broker events
  5. Add history entry for undo/redo

Adding a Slicing Mode (kiri:moto)

  1. Create mode directory in src/kiri/mode/yourmode/
  2. Implement slice, setup, export functions
  3. Register mode in api.mode
  4. Add device profiles in src/cli/
  5. Update worker bundles

Working with Transparent Objects

To avoid z-fighting with transparent planes/faces:

  • Set renderOrder (higher = rendered later)
  • Use depthWrite: false on transparent materials
  • Consider separate render passes for complex transparency
  • void:form ViewCube uses separate render pass to avoid z-fighting

Viewport Rendering (Multiple Passes)

For widgets needing separate rendering (ViewCube pattern):

space.afterRender((renderer) => {
  // Save current viewport
  const currentViewport = new THREE.Vector4();
  renderer.getViewport(currentViewport);

  // Set custom viewport (e.g., top-right corner)
  renderer.setViewport(x, y, width, height);
  renderer.setScissor(x, y, width, height);
  renderer.setScissorTest(true);
  renderer.autoClear = false;

  // Render your scene
  renderer.render(myScene, myCamera);

  // Restore
  renderer.setViewport(currentViewport);
  renderer.setScissorTest(false);
});

ViewCube caveat:

  • ViewCube renders in a separate pass via space.afterRender()
  • Preserve and restore renderer viewport/scissor/autoclear state when adding more overlays/widgets

Critical Rules

  1. ALWAYS read files before editing them
  2. NEVER use SCENE.add() - use space.world.add() instead
  3. NEVER forget depthWrite: false on transparent materials
  4. ALWAYS dispose of Three.js geometry/materials when removing objects
  5. ALWAYS use userData for back-references on Three.js objects
  6. PREFER repo-consistent tooling and keep edits minimal/reviewable
  7. ALWAYS test z-fighting issues with transparent overlapping geometry
  8. NEVER modify shared moto/ infrastructure without considering all three apps
  9. USE BROKER WHEN THE APP ALREADY FOLLOWS THAT PATTERN (kiri:moto, mesh:tool); void:form currently uses direct module calls
  10. NEVER block the main thread - use workers for heavy computation
  11. RESPECT SPACE MOUSE CALLBACK SHAPE: target-discovery and event handling are separate phases; use full intersection lists when interaction priority matters

Important File Paths

Entry Points

  • /Users/stewart/Code/gs-apps/src/main/kiri.js - Kiri:Moto bootstrap
  • /Users/stewart/Code/gs-apps/src/main/mesh.js - Mesh:Tool bootstrap
  • /Users/stewart/Code/gs-apps/src/main/void.js - Void:Form bootstrap

Core APIs

  • /Users/stewart/Code/gs-apps/src/kiri/app/api.js - Kiri API (~10KB)
  • /Users/stewart/Code/gs-apps/src/mesh/api.js - Mesh API (~1,730 lines)
  • /Users/stewart/Code/gs-apps/src/void/api.js - Void API composition root
  • /Users/stewart/Code/gs-apps/src/void/api/document.js - Void document + revisions/undo/redo
  • /Users/stewart/Code/gs-apps/src/void/interact.js - Void interaction composition root

Shared Infrastructure

  • /Users/stewart/Code/gs-apps/src/moto/space.js - 3D viewport (55KB)
  • /Users/stewart/Code/gs-apps/src/moto/broker.js - Event system (156 lines)
  • /Users/stewart/Code/gs-apps/src/moto/orbit.js - Camera controls (25KB)
  • /Users/stewart/Code/gs-apps/src/moto/webui.js - DOM helpers (4KB)

Geometry & Loading

  • /Users/stewart/Code/gs-apps/src/geo/ - Math & geometry (12 modules)
  • /Users/stewart/Code/gs-apps/src/load/ - File format loaders (9 formats)
  • /Users/stewart/Code/gs-apps/src/ext/ - External libraries (Three.js, Manifold, etc.)

Documentation

  • /Users/stewart/Code/gs-apps/docs/kiri-moto/ - Kiri:Moto docs (extensive)
  • /Users/stewart/Code/gs-apps/docs/mesh-tool.md - Mesh:Tool docs
  • /Users/stewart/Code/gs-apps/VOID-FORM.md - Void:Form implementation notes

Configuration

  • /Users/stewart/Code/gs-apps/app.js - Express server (routes at lines 135-166)
  • /Users/stewart/Code/gs-apps/package.json - Dependencies

Routes

Development URLs (http://localhost:8080)

  • /kiri/ - Kiri:Moto slicer
  • /mesh/ - Mesh:Tool editor
  • /void/ - Void:Form CAD (primary)
  • /form/ - Void:Form CAD (alias)

Static Assets

  • /lib/pack/kiri-main.js - Kiri main bundle (~28KB)
  • /lib/pack/kiri-work.js - Kiri worker bundle
  • /lib/pack/kiri-eng.js - Kiri engine bundle
  • /lib/pack/mesh-main.js - Mesh main bundle
  • /lib/pack/mesh-work.js - Mesh worker bundle
  • /lib/pack/void-main.js - Void main bundle

Commands

npm install          # Install dependencies
npm run dev          # Start dev server (port 8080)
npm run build        # Build for production

Dependencies

Shared (all apps)

  • three ^0.182.0 - 3D rendering
  • manifold-3d ^3.3.2 - BREP operations
  • jszip - ZIP file handling

Void-specific

  • @salusoft89/planegcs ^1.1.7 - 2D constraint solver

Git Status

  • Current branch: rel-4.6-void
  • Main branch: master (use for PRs)
  • Recent work: ViewCube widget, datum planes, plane primitives

Next Steps

Kiri:Moto

  • Mature product, maintenance mode
  • Device profile updates
  • Mode-specific improvements

Mesh:Tool

  • Active development
  • Face/edge selection enhancements
  • Boolean operation improvements
  • Sketch system refinements

Void:Form

Phase 2: Sketch System (Next)

  1. planegcs constraint solver integration
  2. 2D sketch canvas overlay
  3. Geometric primitives (line, circle, arc)
  4. Constraints (distance, angle, parallel, perpendicular)

Phase 3: Features

  1. Extrude feature using Manifold
  2. Feature history tree with parametric updates
  3. Cut, revolve, sweep operations

Last Updated: 2026-02-03 (ViewCube integration, comprehensive coverage)