mesh-tool: mesht - create/inspect/edit OBJ+STL with ASCII multi-view rendering

- OBJ read/write (multi-object, ngon fan-triangulation, negative indices),
  STL binary+ascii with auto-detect and vertex welding
- info: bbox/size/area/volume + watertightness via edge manifold stats
- view: z-buffered orthographic ASCII renders (front/side/top/iso/back)
- transform: center/mirror/scale/rotate/translate/fit, per-object filter,
  winding auto-flip on negative determinant
- create: box/sphere/cylinder/cone/plane/torus; merge; convert
- go tests: primitive volumes vs analytic values, roundtrips, topology

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmdG9GqfSWCzts7AkDwRDh
This commit is contained in:
2026-07-14 02:33:37 +02:00
parent 581e37acd8
commit 62065f237b
13 changed files with 1759 additions and 0 deletions

101
mesh-tool/README.md Normal file
View File

@@ -0,0 +1,101 @@
# mesh-tool (`mesht`)
Create, inspect and edit **3D models** from the command line — built so an
agent can *see* a model (ASCII multi-view rendering + measurements),
reason about it, and edit it step by step. Written in Go, zero
dependencies, single static binary.
## Formats
| Format | Read | Write | Notes |
|--------|------|-------|-------|
| OBJ | ✔ | ✔ | multiple named objects, quads/ngons triangulated |
| STL | ✔ | ✔ | binary + ASCII, auto-detected; vertices re-welded on load |
OBJ and STL cover the vast majority of simple editing/printing/game
pipelines and are plain enough to survive round-trips. glTF/GLB is out of
scope for now (a full JSON+buffer+material model; use Blender for that).
Normals, UVs and materials are ignored on read — this tool edits
*geometry*. Viewers recompute normals; STL export writes correct face
normals from the winding.
## Build
```bash
# Arch/Garuda: sudo pacman -S go
cd mesh-tool
go build -o build/mesht . # or the VS Code task "build mesh-tool"
go test ./...
```
## Commands
```bash
mesht info model.obj # verts/tris, bbox, size, area, volume, watertight?
mesht view model.obj # ASCII render: front, side, top (default)
mesht view model.obj --views iso --width 100 --object wheel
# creation — box|sphere|cylinder|cone|plane|torus
mesht create box --size 2,1,1 --name crate -o crate.obj
mesht create sphere --radius 1 --segments 32 --rings 16 -o ball.stl
# editing (applied in the listed order)
mesht transform m.obj --center # bbox center -> origin
mesht transform m.obj --mirror x # winding auto-corrected
mesht transform m.obj --scale 2 # or --scale 1,2,1
mesht transform m.obj --rotate 0,45,0 # degrees, X then Y then Z
mesht transform m.obj --translate 0,2,0
mesht transform m.obj --fit 10 # largest dimension -> 10 units
mesht transform m.obj --object wheel --scale 1.2 -o out.obj # edit one part
mesht merge body.obj wheels.obj -o car.obj # keeps objects, renames dups
mesht merge a.stl b.stl --flatten -o one.obj # single combined object
mesht convert model.obj -o model.stl # --ascii for text STL
```
`-o` picks the output format from the extension. `transform` overwrites
the input when `-o` is omitted.
## Conventions
- **Axes:** right-handed, **+Y up**, +X right, +Z toward the "front" viewer.
- Primitives are centered on the origin.
- Mirroring / negative scaling automatically flips triangle winding so
surfaces keep facing outward.
- `info` reports **volume only for watertight meshes** — otherwise it
tells you how many boundary/non-manifold edges the mesh has.
## How an agent should edit a model
1. `mesht info m.obj` — learn size, orientation and object names.
2. `mesht view m.obj` — see the shape (front/side/top; add `iso` for depth).
3. Apply **one small transform**, write to a new file.
4. `mesht view` again and compare — verify before continuing.
The ASCII views are z-buffered orthographic renders; brightness = how
much the surface faces the light over the viewer's shoulder, so shape
and curvature read directly from the text. Each view header repeats the
axis legend and model dimensions.
Example (a 32-segment sphere, front view, width 48):
```
front view — X→right Y↑up (seen from +Z)
model 2 x 2 x 2 (XYZ)
==++**####%%%%%%%%%%%%###*
-==++**######%%%%%%%%%%%%%%####*
:-=+++**#######%%%%%%%%%%%%%%%%%%#**
-==++***#######%%%%%%%%%%%%%%%%%%%%##*
.:--+++***########%%%%%%%%%%%%%%%%%%%%%%##*+
```
## Viewing the results as a human
Any of these (Arch/Garuda):
```bash
sudo pacman -S f3d # fast minimal viewer: f3d model.obj
sudo pacman -S blender # full editor
flatpak install org.prusa3d.PrusaSlicer # if you also want to print
```