The exploder module offsets each SceneMesh
in a SceneModel away from the model centre.
The offset is controlled by a numeric factor and is written to
mesh.matrix; geometry and materials are not changed.
Shape
%%{init:{"theme":"dark"}}%%
classDiagram
direction TB
class SceneModelExploder {
+factor : number
+rebuild() this
+setFactor(f) this
+reset() this
+destroy()
}
class SceneModelExploderParams {
+scene : Scene
+sceneModel : SceneModel
+collisionIndex : SceneCollisionIndex
+minFactor? : number
+maxFactor? : number
+step? : number
+initialFactor? : number
}
class ExplodeState {
<<internal>>
+modelCenterInScene : number[]
+meshes : ExplodeMeshState[]
}
class ExplodeMeshState {
<<internal>>
+mesh : SceneMesh
+centerInScene : number[]
+baseMatrix : number[]
}
class Scene {
<<scene>>
}
class SceneModel {
<<scene>>
}
class SceneCollisionIndex {
<<collision>>
+getMeshAABB(mesh)
}
class HTMLSlider {
<<DOM>>
}
SceneModelExploder ..> SceneModelExploderParams : reads
SceneModelExploder o-- Scene : reads coord system
SceneModelExploder o-- SceneModel : displaces meshes
SceneModelExploder o-- SceneCollisionIndex : reads AABBs
SceneModelExploder "1" *-- "1" ExplodeState : cached rest pose
ExplodeState "1" *-- "*" ExplodeMeshState
SceneModelExploder ..> HTMLSlider : mounts on document.body
%%{init:{"theme":"default"}}%%
classDiagram
direction TB
class SceneModelExploder {
+factor : number
+rebuild() this
+setFactor(f) this
+reset() this
+destroy()
}
class SceneModelExploderParams {
+scene : Scene
+sceneModel : SceneModel
+collisionIndex : SceneCollisionIndex
+minFactor? : number
+maxFactor? : number
+step? : number
+initialFactor? : number
}
class ExplodeState {
<<internal>>
+modelCenterInScene : number[]
+meshes : ExplodeMeshState[]
}
class ExplodeMeshState {
<<internal>>
+mesh : SceneMesh
+centerInScene : number[]
+baseMatrix : number[]
}
class Scene {
<<scene>>
}
class SceneModel {
<<scene>>
}
class SceneCollisionIndex {
<<collision>>
+getMeshAABB(mesh)
}
class HTMLSlider {
<<DOM>>
}
SceneModelExploder ..> SceneModelExploderParams : reads
SceneModelExploder o-- Scene : reads coord system
SceneModelExploder o-- SceneModel : displaces meshes
SceneModelExploder o-- SceneCollisionIndex : reads AABBs
SceneModelExploder "1" *-- "1" ExplodeState : cached rest pose
ExplodeState "1" *-- "*" ExplodeMeshState
SceneModelExploder ..> HTMLSlider : mounts on document.body
classDiagram
direction TB
class SceneModelExploder {
+factor : number
+rebuild() this
+setFactor(f) this
+reset() this
+destroy()
}
class SceneModelExploderParams {
+scene : Scene
+sceneModel : SceneModel
+collisionIndex : SceneCollisionIndex
+minFactor? : number
+maxFactor? : number
+step? : number
+initialFactor? : number
}
class ExplodeState {
<<internal>>
+modelCenterInScene : number[]
+meshes : ExplodeMeshState[]
}
class ExplodeMeshState {
<<internal>>
+mesh : SceneMesh
+centerInScene : number[]
+baseMatrix : number[]
}
class Scene {
<<scene>>
}
class SceneModel {
<<scene>>
}
class SceneCollisionIndex {
<<collision>>
+getMeshAABB(mesh)
}
class HTMLSlider {
<<DOM>>
}
SceneModelExploder ..> SceneModelExploderParams : reads
SceneModelExploder o-- Scene : reads coord system
SceneModelExploder o-- SceneModel : displaces meshes
SceneModelExploder o-- SceneCollisionIndex : reads AABBs
SceneModelExploder "1" *-- "1" ExplodeState : cached rest pose
ExplodeState "1" *-- "*" ExplodeMeshState
SceneModelExploder ..> HTMLSlider : mounts on document.body
How it works
%%{init:{"theme":"dark"}}%%
flowchart TD
A[constructor] --> B[mount HTML slider]
B --> C{initialFactor != 0?}
C -- yes --> D[setFactor]
C -- no --> E[idle]
D --> F[rebuild — walk meshes, cache rest pose]
F --> G[per mesh: mesh.matrix = baseMatrix + dir × factor]
E -- user drags --> D
G --> H[viewer re-renders]
H -- factor = 0 --> I[reset — restore baseMatrix]
%%{init:{"theme":"default"}}%%
flowchart TD
A[constructor] --> B[mount HTML slider]
B --> C{initialFactor != 0?}
C -- yes --> D[setFactor]
C -- no --> E[idle]
D --> F[rebuild — walk meshes, cache rest pose]
F --> G[per mesh: mesh.matrix = baseMatrix + dir × factor]
E -- user drags --> D
G --> H[viewer re-renders]
H -- factor = 0 --> I[reset — restore baseMatrix]
flowchart TD
A[constructor] --> B[mount HTML slider]
B --> C{initialFactor != 0?}
C -- yes --> D[setFactor]
C -- no --> E[idle]
D --> F[rebuild — walk meshes, cache rest pose]
F --> G[per mesh: mesh.matrix = baseMatrix + dir × factor]
E -- user drags --> D
G --> H[viewer re-renders]
H -- factor = 0 --> I[reset — restore baseMatrix]
Behavior
One radial direction per mesh — the direction is from the model
centre to the mesh's world-AABB centre (read once via the supplied
SceneCollisionIndex).
Cross-coordinate-system aware — the displacement vector is
computed in the Scene's world frame and
transformed into the SceneModel's local frame before being
applied, so a SceneModel with its own non-trivial
CoordinateSystem explodes
correctly.
One-shot rebuild — the rest pose (per-mesh base matrix +
centre) is cached at first
setFactor (or explicit
rebuild), then reused on
subsequent slider ticks.
Pure transform displacement — touches only mesh.matrix;
geometry, materials, and bindings are untouched. reset()
restores the rest pose.
Built-in HTML slider — a floating control mounts on
document.body at construction; drag it to drive
factor live. Style and
placement are inline so the control is self-contained.
Rebuild on model swap — when the underlying SceneModel
changes meshes or materials at runtime (e.g. after
applyHeatMapMaterials swaps every mesh), call
rebuild to recapture the
new rest pose.
Other systems that destroy + recreate meshes on the SceneModel
(e.g. applyHeatMapMaterials) leave the exploder's cached
baseMatrix pointing at destroyed meshes. Call
rebuild after such a swap to
recapture the new rest pose.
destroy resets the factor to
0 (so the model lands at rest), unmounts the slider element,
and drops the cached state. Idempotent — call it whenever the
hosting UI hides or the SceneModel is destroyed.
Scene Model Exploder
The
explodermodule offsets each SceneMesh in a SceneModel away from the model centre. The offset is controlled by a numeric factor and is written tomesh.matrix; geometry and materials are not changed.Shape
How it works
Behavior
mesh.matrix; geometry, materials, and bindings are untouched.reset()restores the rest pose.document.bodyat construction; drag it to drive factor live. Style and placement are inline so the control is self-contained.applyHeatMapMaterialsswaps every mesh), call rebuild to recapture the new rest pose.Usage
1) Import the entry point
2) Mount the exploder on a SceneModel
Pass the Scene, the target SceneModel, and the SceneCollisionIndex used to read world AABBs. The HTML slider mounts on
document.body.3) Drive the factor programmatically
Set
factor(or call setFactor) to animate the offset in code. The slider's value follows so the UI stays in sync.4) Tune the slider range
Override
minFactor/maxFactor/stepon construction. The default range is[0, 2]with step0.05.5) Rebuild after a mesh swap
Other systems that destroy + recreate meshes on the SceneModel (e.g.
applyHeatMapMaterials) leave the exploder's cachedbaseMatrixpointing at destroyed meshes. Call rebuild after such a swap to recapture the new rest pose.6) Tearing down
destroy resets the factor to
0(so the model lands at rest), unmounts the slider element, and drops the cached state. Idempotent — call it whenever the hosting UI hides or the SceneModel is destroyed.