Skip to content

xpayn3/MeshOptimiser

Repository files navigation

███╗   ███╗███████╗███████╗██╗  ██╗
████╗ ████║██╔════╝██╔════╝██║  ██║
██╔████╔██║█████╗  ███████╗███████║
██║╚██╔╝██║██╔══╝  ╚════██║██╔══██║
██║ ╚═╝ ██║███████╗███████║██║  ██║
╚═╝     ╚═╝╚══════╝╚══════╝╚═╝  ╚═╝
  O P T I M I S E R   ·   v 0 . 8 . 0

From bloated CAD to browser-ready, locally.

Drop a STEP file in. Get a Meshopt-compressed GLB and an interactive viewer out. A self-hosted take on the Pixyz preprocessor. Python + your browser, no licence server.

Python OCCT WebGPU Draco License Platform Status


Why

CAD assemblies are big. A real-world STEP file might contain 400 identical bolts, 80 duplicate brackets, and half a million degenerate triangles, and still expect your GPU to render it.

The pipeline collapses what it can:

   400 bolts × 50 KB        →     1 mesh × 50 KB + 400 transforms
   80 brackets × 12 KB      →     1 mesh × 12 KB + 80  transforms
   500K bad triangles       →     adaptive retess, size-culled
   ───────────────────────────────────────────────────────────
   320 MB STEP              →     11 MB Meshopt-compressed GLB

What's in the box

A CAD preprocessor, viewer, hierarchy editor, and exporter, in one local app.

  • Pose-normalized instancing — PCA-based hashing detects duplicate geometry regardless of position or rotation. One GPU mesh, N transforms.
  • Editable assembly tree — search, isolate, recolour, batch-rename, flatten, dissolve, ungroup. All undoable.
  • Two renderers — WebGPU (default, with TSL nodes and discardNode clipping) and WebGL2. Hot-swap from the toolbar, no reload.
  • GPU section planes — real discardNode-based clipping, not a placeholder mesh.
  • Resumable sessions — FS Access API + IndexedDB persist file handles across reloads. Saved scenes for view/selection/recolour state.
  • Keyboard-first UX — command palette (⌘K), shortcuts overlay, batch rename (F2), context menus, undo/redo.
  • No build step — vanilla JS, native ES modules, CSS design tokens. Edit a file, refresh, done.
  • Non-destructive — original geometry is never mutated until you export.

✨ Features

🛠 Pipeline (STEP → GLB)

🌳 XCAF reader Per-solid colours, names, and the full assembly tree pulled straight out of OCCT
🧬 PCA pose-normalized hash Same shape at any rotation/translation → one GPU mesh + N transforms
🔷 Adaptive tessellation Absolute or relative to bbox diagonal · size culling for the tiny stuff
📦 Meshopt + Draco Optional EXT_meshopt_compression via gltfpack~10× smaller GLBs
One-click launch start.bat / start.command bootstraps the venv and opens the browser
🔁 Background jobs Long conversions run as server jobs with live progress streamed to the UI

🖥 Viewer & rendering

🌐 Dual renderer WebGPU (default) with hot-swap to WebGL2 — pick from the toolbar
🔪 Section / Clip planes Live cross-section via TSL discardNode — true GPU clipping, not fake plane meshes
💡 PBR + AO + envmap Studio lighting, ambient occlusion, screen-space reflections, fog
🎯 Pixel-perfect picking Hover, click, marquee-select; works on instanced meshes
👁 Hide / Isolate / Solo One key per mode — flatten the noise, focus on what matters
🎨 Recolor by group Per-instance and per-material recolouring with reset baked-in
📐 Wireframe / Shaded / Matcap Three viewport modes, switchable mid-flight
📊 FPS pill Tabular-numeric FPS readout, colour-coded for stutter detection

🧬 Hierarchy editing

🌳 Live tree 10 K+ nodes, virtualized, sticky right column, content-visibility tuned
🔎 Search + filters Fuzzy name search, "highlight small parts" tinting
✂️ Flatten / Dissolve Collapse single-child chains, dissolve groups, ungroup scopes — all undoable
✏️ Batch rename (F2) Token templates ({name}, {idx}, {depth}) + regex find/replace + presets
🔄 Undo / Redo Tree edits, recolours, renames, flattens — all on a single timeline
📌 Right-click menu Hide / isolate / recolour / rename / focus camera, all in one click

📤 Export

📦 GLB / GLTF Draco + Meshopt compression toggles, optional embedded textures
🎬 FBX / USDZ / OBJ / STL Common DCC + AR formats, scale presets (mm/cm/m/in) or custom
🧷 Save Scene Snapshot view + selection + recolours into a sidecar .scene.json

🧰 UX & polish

👋 Welcome modal Drag-drop, browse, recent files (IndexedDB-persisted handles)
Command palette (⌘K) Searchable action registry — every menu item, one keystroke away
⌨️ Shortcuts overlay Discoverable cheatsheet with live key bindings
⚙️ Settings modal Persistent prefs (renderer, perf mode, background, toggles)
🎨 Design-token system Centralised CSS variables — surfaces, radii, type scale, easings
📋 Copy log / Cancel load Every long operation is observable and abortable

🛠 Pipeline

   ┌──────────────┐    ┌────────────────────┐    ┌────────────────┐
   │  .step / .stp│ ─▶ │ step2glb.py (OCCT) │ ─▶ │   .glb (Draco) │
   └──────────────┘    │ • XCAF tree        │    └────────┬───────┘
                       │ • PCA instancing   │             │
                       │ • Tessellation     │             ▼
                       │ • gltfpack/Meshopt │    ┌────────────────┐
                       └────────────────────┘    │ WebGPU viewer  │
                                                 │  index.html    │
                                                 └────────────────┘

🧰 Tech Stack

cadquery-ocp · trimesh · numpy · Draco · Assimp (WASM) · WebGPU · vanilla JS

No framework. No bundler. No npm install. Just open and run.


🚀 Quick Start

# Windows
start.bat

# macOS
./start.command

First run bootstraps .venv, pulls deps, opens the viewer. Subsequent runs are ~1 second.

🧪 Direct CLI

python step2glb.py input.step
python step2glb.py input.step --quality 0.2 --min-size 0.5
python step2glb.py input.step --no-instance       # disable instancing
python step2glb.py input.step --meshopt           # shell out to gltfpack
python step2glb.py input.step --relative          # quality as fraction of diag

📋 Requirements

  • 🐍 Python 3.10 / 3.11 / 3.12 (3.13 blocked on cadquery-ocp)
  • 🌐 A WebGPU-capable browser (recent Chrome, Edge, Firefox, Safari)
  • 💾 ~2 GB free for the venv on first install

🗂 Layout

step2glb.py        STEP → GLB converter (OCCT + instancing)
serve.py           local HTTP server + /api/convert endpoint
index.html         WebGPU viewer shell
app-v2.js          viewer logic (scene graph, picking, colour groups)
vendor/
 ├── draco/        Draco encoder + decoder (WASM)
 └── assimp/       Assimp.js (WASM)
fbx_*.py           FBX inspection / diff utilities
start.{bat,command}    one-click launchers
step2glb.{bat,command} headless converters

🩹 Troubleshooting

🪟 "python is not on PATH" on Windows
Re-run the Python installer and tick Add Python to PATH, or close + reopen your terminal so the new PATH is picked up.
🍎 "Operation not permitted" on macOS
Right-click start.commandOpen. Gatekeeper blocks double-clicking freshly-unzipped scripts the first time.
📦 "ModuleNotFoundError: cadquery"
Delete .venv/ and re-run start.bat / start.command to rebuild from scratch.

🗒 What's New

v0.8.0 — the plumbing feels modern: an industry-standard ray-marched floor grid (no plane mesh, no Z-fight), a unified keycap chip across every shortcut surface, the undo system rebuilt as a flat command registry, and all runtime-injected CSS lifted into the stylesheet.

  • new Ray-marched ground grid — fullscreen NDC quad, eye-ray + plane intersect, analytic depth write. No vertex precision loss at distance, no sub-pixel jitter under orbit, no coplanar Z-fight.
  • new Redesigned Shortcuts modal — sticky search input, category headers with lucide icons, 2-column grid, multi-key combos rendered as separate keycap chips joined by +. Opens via ?.
  • polish .kbd-chip shared primitive — single class on the hint strip, tooltips, command palette, brand menu, Shortcuts modal — consistent combo splitting everywhere.
  • polish Smart fit + caret merged + Smart-fit popover sliders now use the same .scrub-range style as the sidebar's Threshold scrubber.
  • refactor Big internal cleanups — 8 runtime <style> injections (~490 lines) lifted into index.html; undo monkey-patches (11 of them) collapsed into a single _UndoOps registry covering 21 op types; renderer + popover dismissal helpers extracted.
  • fix Tree summary stuck at "1 parts in hierarchy" after delete · stranded group origin dot after deleting all members · group-selection button popping a name dialog · path tracer error spam on empty scene · materials panel duplicate / add / merge each had their own confusing toast or selection requirement.

Pre-1.0 — breaking changes expected. The CLI flags, in-app APIs, and on-disk formats may shift between minor versions. v1.0.0 will mark the first commitment to backward compatibility.

Earlier

  • v0.7.0 — GPU path tracer aperture button + sample-accumulating modal, contextual hint strip, long-hold add-primitive picker, standalone Cloner you can drag parts into, Revert-to-source escape hatch.
  • v0.6.0 — C4D-style live Cloner, Ctrl-click measure tool, per-group origin markers, Spline-style two-panel Export modal, --simplify + meshopt-by-default pipeline, CAD-correct mouse mapping.
  • v0.5.0 — scene management (New scene, Import-merge, Scene settings modal), parametric-primitive polish with editable mm-snapped inputs, unit-aware transforms, banding-free dithered backgrounds, /api/quit clean shutdown.
  • v0.4.0 — HDRI environment lighting, infinite floor grid + fog, parametric primitive insertion, top-center camera-view pill with Ctrl/⌘+1..4, borderless popup language, IBM-blue accent refresh.
  • v0.3.0 — full material editor with shader-ball previews, scale gizmo + Shift-snap + live HUD, screenshot capture with custom resolutions, ortho Top/Front/Side viewport toggles, FBX legacy rescue.

Full changelog → · Releases →


📜 License

MIT. Do whatever — just don't blame me when your assembly tessellates into a black hole.

✦ ✦ ✦

Built for engineers who want their CAD to load before their coffee.

About

From bloated CAD to browser-ready, locally. STEP -> Meshopt-compressed GLB + WebGPU viewer. Pre-1.0, breaking changes expected.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors