Skip to content

What is Fabric

Fabric renders raymarched SDF shapes, glTF meshes, GPU particles and SDF text — sharing one frame and one depth buffer, driven by JSX components and signals.

It exists because the alternative did not fit. A general 3D library’s smallest sensible build is larger than fabric’s largest.

src/lib/fabric/
├── index.ts Public API barrel — named exports only, no side effects
├── sdf.wgsl SDF shader: proxy-cube vs + fs / fs_fast / fs_fast_effect / fs_fast_effect_depth / fs_refract
├── primitives/ 25 distance functions, one file each — #included by sdf.wgsl
├── materials/ phong, cell, fresnel, matcap, anisotropic — #included into both fs and fs_fast
├── noise.wgsl Hash + value-noise for roughness / grain — #included by sdf.wgsl
├── text.wgsl Direct-Bezier glyph shader, no atlas — loaded by textEngine
├── Camera/
│ ├── index.tsx Camera component — props, bridge switches, CameraRig forwarding
│ └── CameraRig.tsx Pointer/touch/gyro listeners → camPosRef damping
├── Composers.ts Re-exports Effect, Fast
├── Effect.tsx Composition-stack frame for outline/glow effects
├── Fast.tsx Composition-stack frame for the fast path
├── Mesh.tsx GLB mesh component — dynamic-imports loadGLB + meshEngine
├── Scene.tsx Global scene params: world transform, axes, raymarch tuning, stats HUD
├── Text.tsx Flat 2D text component — dynamic-imports textEngine
├── View.tsx Registers a tracked DOM rect + camera as a view (per-view scissor/viewport)
├── Visible.tsx DOM-driven culling scope — off-screen descendants skip the record write
├── _materialDeps.ts The one list of material fields a shape subscribes to
├── components/
│ ├── Grid.tsx Particle / point-cloud component — the primary particle pass
│ ├── Wave.tsx A numeric signal drawn as a waveform in its own particle layer
│ ├── Rig.tsx Drag-handle wrapper — dynamic-imports rigGizmo
│ └── StatsHUD.tsx Debug overlay — dynamic-imported by Scene
├── core/
│ ├── types.ts All shared TS types
│ ├── fabricState.ts Module signals + refs + useFabric() + initState
│ ├── scope.ts Dynamic scope stacks (Effect/Fast/Modifier/Visible/Rig)
│ ├── helpers.ts toVec3, toRad, subscribeToSignals
│ ├── init.ts startFabricEngine (engine + interaction bootstrap)
│ ├── engine.ts WebGPU lifecycle + RAF
│ ├── interact.ts Canvas pointer events → ray pick
│ └── gpuState.ts GPUState type + mat4 helpers
├── hooks/
│ └── useGraviton.ts Bootstrap orchestrator: cursor seed + engine start + publish RAF
├── modifiers/ Bend, Displace, Twist, Onion, Symmetry, Elongate, Extrude, Revolve (+ barrel)
├── render/
│ ├── renderer.ts submitFrame — the passes, per-view scissor, glass pre-passes, blit
│ ├── pipelines.ts Particle sim + render pipelines (static imports of src/wgsl)
│ ├── uniforms.ts Uniform layout, hex colour parsing
│ ├── particles.ts Grid particle buffers — dynamic-imports loadGeometry for a geometryUrl
│ ├── particleLayer.ts Extra particle layers (Wave), drawn after the Grid pass
│ ├── loadGeometry.ts PLY point-cloud loader
│ ├── sdfEngine.ts SDF shapes: the record write, pipelines, spatial grid — dynamic-imported by each shape
│ ├── meshEngine.ts Mesh buffers, bind groups, pipelines — dynamic-imported by Mesh
│ ├── loadGLB.ts glTF 2.0 reader + CPU skinning — dynamic-imported by Mesh
│ ├── textEngine.ts Glyph instancing over text.wgsl — dynamic-imported by Text
│ ├── textLayout.ts Glyph layout in em-space
│ ├── axes.ts <Scene showAxes> origin gizmo — dynamic-imported by renderer
│ ├── rigGizmo.ts Per-shape translate handles — dynamic-imported by Rig
│ ├── bgmip.ts Background mip chain for glass roughness — dynamic-imported by renderer
│ └── blit.ts Offscreen → swapchain copy for adaptive resize — dynamic-imported by engine
├── shapes/ 22 SDF primitives (+ barrel)
└── shapes2d/ Circle2D, Rect2D, RoundedRect2D (+ barrel)
src/wgsl/ Outside the lib, imported by it
├── grid.wgsl Spatial-grid compute (clear + assign) — dynamic-imported by sdfEngine
├── particles.wgsl Particle render shader — pipelines.ts
└── simulate.wgsl Particle sim compute — pipelines.ts

The fabric-shake plugin first strips the regions the app’s source never uses — primitives, material and modifier branches, glass features — then vite-plugin-glsl inlines the surviving #include lines and minifies. Both run in dev as well as in a build — see Lazy subsystems.