546 lines
17 KiB
Markdown
546 lines
17 KiB
Markdown
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```rust
|
|
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
|
|
|
|
```javascript
|
|
// 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):
|
|
```javascript
|
|
// 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):
|
|
```javascript
|
|
localStorage.setItem('theme', 'dark');
|
|
localStorage.setItem('recentFiles', JSON.stringify([...]));
|
|
```
|
|
|
|
**Cache API** (for thumbnails and assets):
|
|
```javascript
|
|
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:
|
|
```typescript
|
|
// 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:
|
|
|
|
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.
|