mattercontrol/research/web-port-feasibility.md
2026-01-28 14:36:34 -08:00

17 KiB

Feasibility Analysis: Porting MatterControl Design Features to Web

Goal: Evaluate porting the design-only features of MatterControl to a web application using JavaScript, WebAssembly, and WebGL.

Executive Summary

Component Porting Difficulty Recommended Approach
3D Rendering Medium WebGL 2.0 + three.js
UI Framework High React/Vue + custom Canvas widgets
Mesh Operations Medium-High WASM (C# via Blazor or manual port)
File Formats Medium JS parsers + pako for compression
Persistence Low IndexedDB + File API

Overall Assessment: Feasible but substantial effort (4-6 months for MVP)


Technology Stack Comparison

Desktop (Current) Web Equivalent
.NET 6.0 (C#) TypeScript + WASM
OpenGL 3.3 WebGL 2.0
agg-sharp (2D) Canvas 2D API
GuiWidget (UI) React/Vue components
SQLite IndexedDB
File System File API + virtual FS
Typography module Web Fonts + Canvas text

1. 3D Rendering (WebGL)

Current Implementation

  • OpenGL 3.3 with VAO/VBO/EBO
  • GLSL 330 shaders (simple vertex → fragment)
  • Custom IOpenGL abstraction layer
  • Features: textures, lighting (2 directional), depth testing, face culling

Web Porting Options

Option A: three.js (Recommended)

  • Mature WebGL abstraction
  • Built-in: cameras, raycasting, materials, scene graph
  • Large ecosystem and documentation
  • Handles WebGL 1.0/2.0 fallback

Option B: Custom WebGL 2.0

  • More control, smaller bundle
  • Requires implementing: shader management, buffer handling, picking
  • Similar to current IOpenGL abstraction

Option C: Babylon.js

  • Full game engine, heavier than three.js
  • Excellent tooling and inspector
  • May be overkill for CAD-style app

Porting Complexity

Feature Desktop Web Equivalent Effort
Mesh rendering GLMeshTrianglePlugin three.js BufferGeometry Low
Camera control TrackballTumbleWidget three.js OrbitControls Low
Picking/selection Ray + BVH three.js Raycaster Low
Transform gizmos Custom implementation three.js TransformControls Low
Wireframe overlay GLMeshWirePlugin three.js EdgesGeometry Low
Texture mapping ImageGlPlugin three.js Texture Low
Total 3D rendering 2-3 weeks

2. UI Framework

Current Implementation

  • GuiWidget: Custom widget system with 2500+ line base class
  • Layout: HAnchor/VAnchor enum-based positioning, FlowLayout
  • Widgets: Button, TextEdit, Slider, Menu, ScrollableWidget, TreeView, etc.
  • Theming: JSON-based ThemeConfig
  • Rendering: agg-sharp software rasterization to ImageBuffer

Web Porting Options

Option A: React + CSS (Recommended)

GuiWidget hierarchy → React component tree
HAnchor/VAnchor → CSS Flexbox
FlowLayoutWidget → flex-direction
ThemeConfig → CSS Custom Properties
Events → React synthetic events

Option B: Vue + CSS

  • Similar mapping to React
  • Reactive state management built-in

Option C: Canvas-based (like current)

  • Port GuiWidget directly to Canvas 2D
  • High effort, poor accessibility
  • Not recommended

Widget Mapping

MatterControl Widget Web Equivalent
GuiWidget React.Component + div
FlowLayoutWidget Flexbox container
Button <button> + CSS
TextEditWidget <input> / <textarea>
Slider <input type="range"> + custom
ScrollableWidget overflow: auto
Menu/DropDownList Headless UI / Radix
TreeView react-arborist or custom
TabControl Headless Tabs
ColorPicker react-colorful

Special Widgets (Canvas-based)

Some widgets need Canvas 2D rendering:

  • View3DWidget → WebGL canvas
  • GCode2DWidget → Canvas 2D (if keeping G-code preview)
  • Custom sliders → SVG or Canvas

Estimated effort: 4-6 weeks (most time-consuming component)


3. Mesh & Geometry Operations

Current Implementation

  • PolygonMesh: Mesh data structure (Vector3Float vertices, faces)
  • geometry3Sharp: Comprehensive geometry library (DMesh3, CSG, smoothing)
  • Clipper: 2D polygon clipping (64-bit integers)
  • All pure C# - no native dependencies

Porting Options

Option A: WebAssembly (C# via Blazor)

  • Compile existing C# to WASM
  • Minimal code changes
  • ~2-3MB WASM bundle (includes .NET runtime)
  • Full geometry3Sharp available

Option B: WebAssembly (Rust) - Recommended for Performance

  • Native WASM target via wasm-bindgen + wasm-pack
  • No garbage collection = smaller bundles (~100KB-500KB)
  • Excellent performance (comparable to native)
  • Strong ecosystem for geometry (see below)
  • Steeper learning curve, requires rewrite

Option C: WebAssembly (Emscripten/C++)

  • Translate C# → C++ → WASM
  • Good performance, medium bundle size
  • Significant translation effort
  • Can wrap existing C++ libraries (CGAL, OpenCascade)

Option D: JavaScript/TypeScript port

  • Manual translation to TypeScript
  • Use existing JS libraries where possible
  • Best for simple operations, slow for complex

Option E: Hybrid (Practical Choice)

  • Simple ops in JS (transforms, normals)
  • Complex ops in WASM (CSG, smoothing)
  • Use existing JS libraries (jscad, csg.js)

Rust → WASM Deep Dive

Why Rust is compelling:

Factor Rust C# (Blazor) C++ (Emscripten)
Bundle size ~100-500KB ~2-3MB ~500KB-2MB
Runtime overhead None (no GC) .NET runtime Minimal
Performance Excellent Good Excellent
Memory safety Compile-time Runtime Manual
WASM tooling First-class Mature Mature
Learning curve Steep Low (existing code) Medium

Rust geometry ecosystem:

Library Purpose Maturity
nalgebra Linear algebra (vectors, matrices, transforms) Excellent
parry3d Collision detection, ray casting, BVH Excellent
ncollide3d Older collision library Good
rstar R-tree spatial indexing Good
geo 2D geometry operations Excellent
meshopt Mesh optimization (simplification) Good
lyon 2D path tessellation Excellent
truck B-rep CAD kernel (experimental) Early

What's missing in Rust (would need implementation):

  • Full mesh boolean/CSG (partial in parry3d)
  • Marching cubes
  • Laplacian smoothing
  • Mesh repair algorithms
  • AMF/3MF file parsers

Rust WASM workflow:

# Setup
cargo install wasm-pack

# Build
wasm-pack build --target web

# Output: pkg/
#   - mesh_ops.js      (JS bindings)
#   - mesh_ops_bg.wasm (WASM binary)
#   - mesh_ops.d.ts    (TypeScript types)

Example Rust mesh module:

use wasm_bindgen::prelude::*;
use nalgebra::{Point3, Vector3};

#[wasm_bindgen]
pub struct Mesh {
    vertices: Vec<Point3<f32>>,
    indices: Vec<u32>,
}

#[wasm_bindgen]
impl Mesh {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Mesh {
        Mesh { vertices: vec![], indices: vec![] }
    }

    pub fn add_vertex(&mut self, x: f32, y: f32, z: f32) {
        self.vertices.push(Point3::new(x, y, z));
    }

    pub fn compute_normals(&self) -> Vec<f32> {
        // Fast normal computation
    }

    pub fn simplify(&mut self, target_ratio: f32) {
        // Mesh decimation using meshopt
    }
}

Feasibility assessment for Rust:

Task Effort Notes
Basic mesh ops (transforms, normals) 1-2 weeks Use nalgebra
Spatial queries (BVH, ray casting) 1 week Use parry3d
Mesh simplification 1 week Use meshopt
CSG boolean operations 3-4 weeks Partial parry3d, or port
Marching cubes 1-2 weeks Port from geometry3Sharp
Laplacian smoothing 1 week Port algorithm
File I/O (STL, OBJ) 1 week Existing crates available
Total 10-14 weeks For full geometry3Sharp equivalent

Recommendation:

For a new web CAD project, Rust → WASM is the better long-term choice:

  • Smaller bundles, better performance
  • No runtime overhead
  • Growing ecosystem

For porting MatterControl specifically, the hybrid approach is more practical:

  • Use existing JS/TS for UI and simple geometry
  • Use Rust WASM for performance-critical operations (CSG, simplification)
  • Consider wrapping existing Rust libraries rather than porting C#

Existing Rust WASM CAD projects to reference:

  • truck - B-rep CAD kernel (early stage)
  • opencascade-rs - OpenCascade Rust bindings (can compile to WASM)
  • manifold - Google's CSG library has Rust bindings

Performance Tiers

Operation JS Performance WASM Needed?
Primitive generation Fast No
Transforms (rotate, scale) Fast No
Normal calculation Fast No
Vertex merging Medium Recommended
BVH construction Medium Recommended
CSG boolean ops Slow Yes
Mesh smoothing Slow Yes
Marching cubes Very slow Yes
Mesh simplification Slow Yes

Existing JS Libraries

Operation Library Notes
CSG csg.js, jscad Reasonable performance
Mesh simplification simplify-js Basic implementation
Clipper polygons js-clipper Port of Clipper
STL parsing three.js STLLoader Built-in
OBJ parsing three.js OBJLoader Built-in

Estimated effort: 3-4 weeks (using existing libraries + selective WASM)


4. File Format Support

Current Formats

  • STL: Binary/ASCII (three.js has loader)
  • OBJ: With MTL materials (three.js has loader)
  • AMF: XML + ZIP compression
  • 3MF: XML + ZIP archive
  • MCX: Custom JSON/ZIP format

Web Implementation

Format Parser Compression Effort
STL three.js STLLoader None Trivial
OBJ three.js OBJLoader None Trivial
AMF Custom XML parser pako (zlib) Medium
3MF Custom XML parser JSZip Medium
MCX JSON.parse JSZip Low

File API Usage

// File input
<input type="file" accept=".stl,.obj,.amf,.3mf,.mcx" />

// Drag and drop
element.addEventListener('drop', handleFiles);

// File System Access API (modern browsers)
const handle = await window.showOpenFilePicker();
const file = await handle.getFile();

Large File Handling

  • Use FileReader with chunked reading
  • Stream parsing for STL (avoid loading entire file)
  • Web Workers for parsing (non-blocking UI)

Estimated effort: 1-2 weeks


5. Persistence Layer

Current Implementation

  • SQLite: Tables for library, settings, history
  • File System: Direct file access for library items
  • JSON: Settings and scene serialization

Web Implementation

IndexedDB (replaces SQLite):

// Library structure
const db = await openDB('MatterControl', 1, {
  upgrade(db) {
    db.createObjectStore('library', { keyPath: 'id' });
    db.createObjectStore('settings', { keyPath: 'key' });
    db.createObjectStore('meshCache', { keyPath: 'hash' });
  }
});

LocalStorage (for simple settings):

localStorage.setItem('theme', 'dark');
localStorage.setItem('recentFiles', JSON.stringify([...]));

Cache API (for thumbnails and assets):

const cache = await caches.open('thumbnails');
await cache.put(url, response);

Migration Path

Desktop Web
PrintItemCollection table IndexedDB library store
PrintItem table IndexedDB items store
SystemSetting table localStorage
UserSetting table localStorage
File system paths IndexedDB blob storage
Thumbnails Cache API

Estimated effort: 1 week


6. Design Tools (DesignTools/)

What Needs Porting

The DesignTools module is independent of printing and includes:

Primitives:

  • Box, Sphere, Cylinder, Cone, Torus
  • Text (3D text generation)
  • Image to 3D (heightmap, lithophane)

Operations:

  • Boolean (Union, Subtract, Intersect)
  • Transform (Rotate, Scale, Mirror, Array)
  • Mesh (Repair, Decimate, Hollow, Twist, Pinch)
  • Path (Extrude, Revolve, Offset)

Porting Strategy

Most primitives are simple geometry generation:

// Example: Box primitive in TypeScript
function createBox(width: number, height: number, depth: number): BufferGeometry {
  return new THREE.BoxGeometry(width, height, depth);
}

For complex operations, use existing libraries or WASM:

  • Boolean ops: csg.js or WASM port
  • Text: opentype.js for font parsing + three.js TextGeometry
  • Mesh repair: Custom or WASM

Estimated effort: 2-3 weeks (leveraging three.js primitives)


7. Architecture Recommendation

┌─────────────────────────────────────────┐
│           React + TypeScript            │
│         (UI Components, State)          │
├─────────────────────────────────────────┤
│              three.js                   │
│     (3D Rendering, Scene Graph)         │
├─────────────────────────────────────────┤
│         Web Workers + WASM              │
│   (Heavy computation: CSG, smoothing)   │
├─────────────────────────────────────────┤
│     IndexedDB + File API + Cache        │
│        (Persistence, Files)             │
└─────────────────────────────────────────┘

Key Libraries

Purpose Library
3D rendering three.js
UI framework React + Tailwind
State management Zustand or Jotai
File parsing three.js loaders + custom
CSG operations csg.js or manifold (WASM)
Compression pako + JSZip
Persistence idb (IndexedDB wrapper)

Project Structure

src/
├── components/          # React UI components
│   ├── Viewport/       # 3D view
│   ├── Library/        # File browser
│   ├── Properties/     # Object properties
│   └── Toolbar/        # Tools and actions
├── core/
│   ├── scene/          # Scene graph management
│   ├── mesh/           # Mesh operations
│   ├── primitives/     # Geometry generators
│   └── io/             # File import/export
├── workers/
│   ├── csg.worker.ts   # CSG operations
│   └── parse.worker.ts # File parsing
├── store/              # State management
└── utils/              # Helpers

8. Timeline Estimate

Phase Duration Deliverable
Phase 1: Core 4 weeks 3D viewport, basic UI, file loading
Phase 2: Primitives 2 weeks All primitive shapes
Phase 3: Operations 3 weeks Boolean, transforms, basic mesh ops
Phase 4: Polish 2 weeks Library, persistence, export
Phase 5: Advanced 3 weeks Complex mesh ops (WASM)
Buffer 2 weeks Testing, optimization
Total 16 weeks Full design-only web app

9. Risks & Mitigations

Risk Impact Mitigation
CSG performance High Use WASM (manifold library)
Large file handling Medium Streaming parsers, Web Workers
Browser compatibility Medium Target modern browsers, polyfills
Memory limits Medium Lazy loading, mesh LOD
UI complexity High Start with essential features

10. Alternative: Existing Web CAD Libraries

Before building from scratch, consider:

Library Pros Cons
OpenCascade.js Full CAD kernel, BREP Large (~30MB), complex
JSCAD CSG-focused, small Limited mesh operations
CadQuery (WASM) Python CAD in browser Experimental
three.js + csg.js Lightweight, flexible Basic CSG only
Manifold (WASM) Fast CSG, Google-backed New, limited docs

Recommendation: Start with three.js + manifold (WASM) for CSG, add features incrementally.


Conclusion

Porting MatterControl design features to web is feasible with these considerations:

  1. Use three.js for 3D rendering - don't reinvent the wheel
  2. Use React for UI - better than porting GuiWidget
  3. Use WASM selectively for CPU-intensive operations (CSG, mesh processing)
  4. Leverage existing parsers (three.js loaders, JSZip)
  5. Start minimal - viewport + primitives + basic transforms first

Estimated total effort: 4-6 months for a production-quality design-only web app.

The biggest challenges are:

  • UI complexity (4-6 weeks)
  • CSG/mesh operations (3-4 weeks with WASM)
  • Matching the feature richness of desktop app

A simpler approach would be using OpenCascade.js or similar existing web CAD framework as the foundation.