Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
860ef87
adapting camera to new ultra
vim-sroberge Jan 20, 2026
4301fa7
checkpoint, screenshot works
vim-sroberge Feb 2, 2026
3bc38da
red geometry
vim-sroberge Feb 2, 2026
6e8403d
position shader
vim-sroberge Feb 2, 2026
a98cb09
working readback
vim-sroberge Feb 2, 2026
af7206a
works
vim-sroberge Feb 2, 2026
1144c35
gpu picking
vim-sroberge Feb 2, 2026
167c84e
gpu picker
vim-sroberge Feb 3, 2026
36e1c23
gpu picking integration
vim-sroberge Feb 3, 2026
8201e81
back to normal main
vim-sroberge Feb 3, 2026
b65b644
multivim support
vim-sroberge Feb 3, 2026
59fce71
claude md update
vim-sroberge Feb 3, 2026
9255879
working with normals
vim-sroberge Feb 3, 2026
f944531
int packing as float
vim-sroberge Feb 3, 2026
61aa9e4
clean up
vim-sroberge Feb 3, 2026
db2ca2e
packing at build time
vim-sroberge Feb 3, 2026
2d36c48
claude md
vim-sroberge Feb 3, 2026
ccbe3dd
updated and unified vim collection
vim-sroberge Feb 3, 2026
3462d88
vim index provided by loading pipeline
vim-sroberge Feb 3, 2026
2155f23
open vs load
vim-sroberge Feb 3, 2026
7099990
async queue instead of promise loop
vim-sroberge Feb 4, 2026
b48f44e
simplifying load
vim-sroberge Feb 4, 2026
2b2be76
removed open
vim-sroberge Feb 4, 2026
f240d09
cleaning up load result
vim-sroberge Feb 4, 2026
6c9c64d
load cleanup
vim-sroberge Feb 4, 2026
7cacb80
common progress
vim-sroberge Feb 4, 2026
53189e0
gizmo to match ultra
vim-sroberge Feb 5, 2026
74b0fa5
almost good camera detached orbit
vim-sroberge Feb 5, 2026
89391cb
zoom resets orbit target
vim-sroberge Feb 5, 2026
3156bd8
claude md
vim-sroberge Feb 5, 2026
6c2c0c8
type fix
vim-sroberge Feb 5, 2026
83b9c6b
fixed bb not beeing computed
vim-sroberge Feb 5, 2026
75d1dc4
fixed raycast result
vim-sroberge Feb 5, 2026
3a6c3c2
gpu pickable markers
vim-sroberge Feb 5, 2026
137bf0f
reemomved more vimx
vim-sroberge Feb 6, 2026
2ddcf00
removing more vimx
vim-sroberge Feb 6, 2026
1dbce29
cleaning up loading
vim-sroberge Feb 6, 2026
f635a27
fixd method call
vim-sroberge Feb 9, 2026
7d3b8b3
fixed delta time
vim-sroberge Feb 9, 2026
f8fb92b
removed debug for picking
vim-sroberge Feb 9, 2026
72c9acf
comments
vim-sroberge Feb 9, 2026
6c09fdf
documentation
vim-sroberge Feb 9, 2026
417f453
restoring free orbit mode
vim-sroberge Feb 9, 2026
bdf75fb
kinda works
vim-sroberge Feb 9, 2026
2b2d0f7
working
vim-sroberge Feb 10, 2026
4a1a59b
working orbit gizmo
vim-sroberge Feb 10, 2026
046471b
refactored extracted sphere coord
vim-sroberge Feb 10, 2026
9218a36
rotation
vim-sroberge Feb 11, 2026
6ab0472
camera api cleanup
vim-sroberge Feb 11, 2026
67ab06b
typo frustrum -> frustum
vim-sroberge Feb 11, 2026
e210c86
unified move
vim-sroberge Feb 11, 2026
625ab45
Ste distanc private
vim-sroberge Feb 11, 2026
1598449
rmoved lookat parametr
vim-sroberge Feb 11, 2026
f700225
reuse veectors
vim-sroberge Feb 11, 2026
ff5a30b
docs
vim-sroberge Feb 11, 2026
6643b29
made rotation x horizontal, y vertical
vim-sroberge Feb 11, 2026
862a6cc
refactor
vim-sroberge Feb 11, 2026
3146516
missing lock
vim-sroberge Feb 11, 2026
1e1aa1e
reset orbit outside screen
vim-sroberge Feb 11, 2026
003fd3c
orbit target on slect
vim-sroberge Feb 11, 2026
a423247
floating target after reset
vim-sroberge Feb 11, 2026
42ebb7b
keep last speed upon reset
vim-sroberge Feb 11, 2026
c6e5b31
fixed framing
vim-sroberge Feb 11, 2026
42225b3
faster scroll
vim-sroberge Feb 11, 2026
56fa0e3
restored touch
vim-sroberge Feb 11, 2026
4af8690
working touch
vim-sroberge Feb 11, 2026
9fe1a16
send bothh pinch and pan
vim-sroberge Feb 11, 2026
0bbda33
better touch
vim-sroberge Feb 12, 2026
7480d25
input constants
vim-sroberge Feb 12, 2026
068e36e
rmovd input allocations
vim-sroberge Feb 12, 2026
b0b8316
dev docs
vim-sroberge Feb 12, 2026
20fd93a
removed spacebar bindings
vim-sroberge Feb 12, 2026
3173d53
input folder and refactors
vim-sroberge Feb 12, 2026
8314178
small fixes
vim-sroberge Feb 12, 2026
e6f0321
some tmp vctors
vim-sroberge Feb 12, 2026
8255601
polish
vim-sroberge Feb 12, 2026
0ac49ed
moved code in the if
vim-sroberge Feb 12, 2026
9b64dec
return progress on signal
vim-sroberge Feb 12, 2026
f2c061f
documentation
vim-sroberge Feb 12, 2026
3a449e8
dont create empty meshes
vim-sroberge Feb 12, 2026
0f7b028
cleaning up g3dsubset
vim-sroberge Feb 12, 2026
854e288
array maps
vim-sroberge Feb 12, 2026
b88da18
working colors
vim-sroberge Feb 12, 2026
b51a92c
color in a teexture
vim-sroberge Feb 13, 2026
6fdddb3
faster eelement mapping
vim-sroberge Feb 13, 2026
67ca0e9
fasteer geomry
vim-sroberge Feb 13, 2026
9ed766d
fastr bb
vim-sroberge Feb 13, 2026
f601bea
bb inverted
vim-sroberge Feb 13, 2026
1f53b93
optims
vim-sroberge Feb 13, 2026
2ce41e9
numeric color key
vim-sroberge Feb 13, 2026
a3debbe
g3dsubset and offseet
vim-sroberge Feb 13, 2026
d33b08c
optims
vim-sroberge Feb 13, 2026
8c27098
optims
vim-sroberge Feb 13, 2026
f90ea34
simple matertial updat
vim-sroberge Feb 13, 2026
08fb496
rename transparency to qualiry
vim-sroberge Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
738 changes: 738 additions & 0 deletions CLAUDE.md

Large diffs are not rendered by default.

147 changes: 147 additions & 0 deletions IMPROVEMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# WebGL Viewer Improvement Suggestions

## Context

After a thorough exploration of the codebase, this document captures concrete improvement suggestions for the WebGL viewer across two axes: **API quality** (internal and external) and **performance**. Each item references specific files and line numbers.

---

## API IMPROVEMENTS

### External API

#### 4. Camera getters expose mutable internal state
**File:** `camera.ts:220-221`
```typescript
get position () { return this.camPerspective.camera.position }
```
Consumers can accidentally corrupt camera state by mutating the returned `Vector3`. Same for `target` and `matrix`. Should return clones or readonly views.

#### 5. Element3D.visible setter has unconditional side effect
**File:** `element3d.ts:106-117`
The setter always iterates meshes to set `mesh.visible = true` even when the attribute didn't change. The `if(value)` block runs outside the change-detection `if`. Should be inside it.

#### 6. onLoadingUpdate carries no payload
**File:** `vim.ts:236-237`
```typescript
this._factory.add(subset)
this._onUpdate.dispatch() // no progress info, no "started"/"finished" distinction
```
Consumers can't track loading progress or know what was loaded. Consider dispatching `{ loaded: number, total: number }` or at minimum the subset that was just loaded.

#### 7. Selection.enabled has no change event
**File:** `selection.ts:27`
```typescript
public enabled = true; // plain boolean, no signal
```
Unlike all other state which uses signals, toggling selection enabled/disabled is invisible to listeners. Should be a `StateRef<boolean>` or at minimum fire an event.

#### 8. Missing batch element queries on Vim
**File:** `vim.ts:135-184`
Only single-element lookups exist (`getElement`, `getElementFromIndex`). No `getElementsFromIndices(indices[])` for batch lookups. Common pattern is looping `getElementFromIndex` hundreds of times.

#### 9. Missing Selection utility methods
**File:** `selection.ts`
No `first()`, `filter(predicate)`, or `forEach(callback)`. Every consumer does `selection.getAll().filter(...)` which allocates a new array.

### Internal API

#### 10. VimMeshFactory creates empty transparent meshes unconditionally
**File:** `vimMeshFactory.ts:52-55`
```typescript
scene.addMesh(this._insertableFactory.createOpaqueFromVim(this.g3d, subset))
scene.addMesh(this._insertableFactory.createTransparentFromVim(this.g3d, subset))
```
Both are always created even if the subset has zero transparent geometry. Creates empty GPU buffers and draw calls.

#### 11. G3dSubset constructor rebuilds Maps on every creation
**File:** `g3dSubset.ts:44-61`
Every `new G3dSubset()` builds a `Map<mesh, instances[]>` and iterates all instances. This constructor runs multiple times during loading: once for the full set, then for `filterByCount` (x2), then for `chunks` (xN), then for `except`. Each time rebuilds the map.

#### 12. InstancedMesh eagerly computes ALL per-instance bounding boxes
**File:** `instancedMesh.ts:31-33`
```typescript
this.boxes = this.computeBoundingBoxes() // N Box3.clone().applyMatrix4()
```
For a mesh with 1000 instances, this allocates 1000 `Box3` objects upfront. Many are never needed (e.g., if only a few are selected).

#### 13. Scene uses Map for instance->submesh lookup
**File:** `scene.ts:46`
```typescript
private _instanceToMeshes: Map<number, Submesh[]> = new Map()
```
If instance indices are dense (0..N), a flat array would give O(1) lookups vs Map's hash overhead. Worth profiling on large models.

---

## PERFORMANCE IMPROVEMENTS

### Loading / Mesh Building

#### 14. G3dSubset.chunks() uses spread operator in loop
**File:** `g3dSubset.ts:78`
```typescript
currentInstances.push(...instances) // spread creates temp array each iteration
```
For 100 meshes with 10 instances each, allocates 100 temporary arrays. Use a regular loop or `Array.prototype.push.apply`.

#### 15. InsertableGeometry recomputes full bounding box on every update
**File:** `insertableGeometry.ts:263-267`
```typescript
this.geometry.computeBoundingBox() // iterates ALL vertices
this.geometry.computeBoundingSphere() // iterates ALL vertices again
```
During progressive loading, each update iterates the entire 4M-vertex buffer even though only a subset was added. Should use incremental bounds (expand existing box with new submesh boxes).

### GPU / Rendering

#### 16. GPU picker creates DataView on every pick
**File:** `gpuPicker.ts:247`
```typescript
const dataView = new DataView(this._readBuffer.buffer)
```
Should be pre-allocated as an instance field since `_readBuffer` never changes.

#### 17. GPU picker allocates Vector3s in reconstructWorldPosition
**File:** `gpuPicker.ts:312-334`
```typescript
const rayEnd = new THREE.Vector3(ndcX, ndcY, 1).unproject(camera)
const cameraDir = new THREE.Vector3()
const worldPos = camera.position.clone().add(rayDir.clone().multiplyScalar(t))
```
Multiple temporary Vector3 allocations per pick. Should use pre-allocated scratch vectors.

#### 18. Element3D._addMesh uses findIndex for duplicate check
**File:** `element3d.ts:253`
```typescript
if (this._meshes.findIndex((m) => m.equals(mesh)) < 0)
```
O(n) linear scan. For elements with many submeshes this adds up. A Set or early-exit would be cheaper.

---

## SUGGESTED PRIORITY ORDER

**Immediate (bugs):**
1. Fix `removeOutline` missing parentheses (element3d.ts:82)
2. Set `debug = false` in gpuPicker (gpuPicker.ts:126)
3. Fix double `getDelta()` in renderingComposer (renderingComposer.ts:230,235)

**High (tangible user/developer impact):**
4. Camera getters return clones
5. Skip empty transparent mesh creation in VimMeshFactory
6. Lazy bounding boxes in InstancedMesh
7. Incremental bounding box in InsertableGeometry.update()
8. Add payload to onLoadingUpdate signal

**Medium (API polish):**
9. Fix visible setter side effect scoping
10. Add batch element queries to Vim
11. Add Selection utility methods (first, filter)
12. Selection.enabled change events

**Lower (micro-optimizations, profile first):**
13. Pre-allocate DataView and scratch Vector3s in gpuPicker
14. Replace spread operator in G3dSubset.chunks()
15. Reduce G3dSubset constructor overhead
16. Array-based instance->submesh lookup in Scene
Loading