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
IOpenGLabstraction 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
IOpenGLabstraction
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
FileReaderwith 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
Recommended Stack
┌─────────────────────────────────────────┐
│ 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:
- Use three.js for 3D rendering - don't reinvent the wheel
- Use React for UI - better than porting GuiWidget
- Use WASM selectively for CPU-intensive operations (CSG, mesh processing)
- Leverage existing parsers (three.js loaders, JSZip)
- 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.