960 lines
39 KiB
Markdown
960 lines
39 KiB
Markdown
# 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.
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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)
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
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.
|
|
|
|
```javascript
|
|
// 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 });
|
|
```
|
|
|
|
```javascript
|
|
// 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:
|
|
|
|
```javascript
|
|
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:
|
|
|
|
```javascript
|
|
// 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:
|
|
|
|
```javascript
|
|
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):
|
|
|
|
```javascript
|
|
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
|
|
|
|
```bash
|
|
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)
|