Skip to content

docs: add WebGPU compute support implementation plan#34

Merged
NewKrok merged 38 commits into
masterfrom
claude/webgpu-compute-support-3kCxi
Apr 16, 2026
Merged

docs: add WebGPU compute support implementation plan#34
NewKrok merged 38 commits into
masterfrom
claude/webgpu-compute-support-3kCxi

Conversation

@NewKrok
Copy link
Copy Markdown
Owner

@NewKrok NewKrok commented Apr 8, 2026

Add detailed phased plan for WebGPU compute shader integration covering
TSL shader migration, GPU compute for physics/modifiers/forces, benchmark
and example strategies. Non-breaking, additive feature with auto-fallback.

Co-Authored-By: Claude noreply@anthropic.com

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm

claude added 6 commits April 8, 2026 17:07
Add detailed phased plan for WebGPU compute shader integration covering
TSL shader migration, GPU compute for physics/modifiers/forces, benchmark
and example strategies. Non-breaking, additive feature with auto-fallback.

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
…se 0)

Add foundation for WebGPU compute support:
- SimulationBackend enum (AUTO/CPU/GPU) in enums
- simulationBackend optional field in ParticleSystemConfig
- Renderer detection utility (duck-type check for compute capability)
- resolveSimulationBackend() for automatic fallback logic
- Serialization support for the new config field
- 18 new tests for renderer detection and serialization round-trip

All 769 tests pass. No breaking changes — existing configs work unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
Create TSL (Three Shading Language) equivalents of all 8 GLSL shaders
for the four particle renderer types (POINTS, INSTANCED, MESH, TRAIL):

- tsl-point-sprite-material: PointsNodeMaterial with texture sheet
  animation, rotation, circle discard, and soft particles
- tsl-instanced-billboard-material: MeshBasicNodeMaterial with
  perspective size matching and billboard quad rendering
- tsl-mesh-particle-material: MeshBasicNodeMaterial with quaternion
  rotation, normal transformation, and directional lighting
- tsl-trail-ribbon-material: MeshBasicNodeMaterial with billboard
  ribbon geometry, edge-on fallback, and soft edge fade
- tsl-shared: Reusable TSL nodes for depth linearization, sprite
  sheet UV calculation, and soft particle fade
- tsl-materials: Factory that selects the right TSL material by type

Wire into core via registerTSLMaterialFactory() registration pattern:
- TSL materials used when factory is registered and backend != CPU
- Existing GLSL ShaderMaterial path completely unchanged
- No breaking changes to public API

29 new tests covering TSL material creation, factory registration,
backend branching, and uniform passing. All 798 tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
- tsl-shared: fix uBgColor using Vector2 constructor instead of Vector3,
  which caused the blue channel to always be 0 in background color discard
- tsl-mesh-particle: fix double-transform by using vertexNode with manual
  MVP (cameraProjectionMatrix * mvPos) instead of positionNode which
  applies MVP automatically
- tsl-trail-ribbon: fix viewDir computed in view-space while tangent is in
  world-space by using cameraPosition for world-space view direction;
  fix camRight extraction to use cameraViewMatrix instead of modelViewMatrix;
  fix fragment stage reading aTrailUV attribute instead of vUv varying
- tsl-materials: deduplicate TrailUniforms type (import from trail module)

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
Implement the GPU compute pipeline for particle simulation:

- compute-particle-update.ts: TSL compute shader that runs gravity,
  velocity integration, position update, world-space compensation,
  and lifetime tracking entirely on the GPU via storage buffers
- Storage buffer infrastructure: createParticleStorageBuffers() creates
  dual-purpose buffers (compute read/write + render attribute read)
- CPU→GPU sync: writeParticleToStorageBuffer() for emission,
  deactivateParticleInStorageBuffer() for death, updateComputeUniforms()
  for per-frame uniform updates
- Update loop branching: when useGPUCompute is true, the CPU per-particle
  physics loop is skipped; CPU still handles death detection for
  sub-emitter callbacks and emission logic
- ParticleSystemInstance extended with computePipeline and useGPUCompute

The compute dispatch (renderer.compute()) will be called from the
public update wrapper in a follow-up once the full integration with
storage buffer rendering is wired up.

11 new tests covering storage buffers, emission sync, compute pipeline
creation, and uniform updates. All 809 tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
…e 3)

Implement all 7 particle lifetime modifiers as GPU compute operations:

Curve baking (curve-bake.ts):
- bakeCurve(): samples any (t)->number curve at 256 points into Float32Array
- bakeParticleSystemCurves(): extracts all active curves from config,
  bakes them sequentially, returns curve index map for GPU lookup
- Supports Bezier and Easing curve types via getCurveFunctionFromConfig

TSL simplex noise (tsl-noise.ts):
- 3D simplex noise implemented entirely in TSL (Ashima Arts algorithm)
- snoise3D: vec3 -> float noise value in [-1, 1]
- particleNoise3: convenience for 3-axis particle noise pattern

Modifier compute shader (compute-modifiers.ts):
- Unified kernel: core physics + all modifiers in single dispatch
- Curve lookup: linear-interpolated read from baked curve storage buffer
- Modifiers compiled conditionally via ModifierFlags (no dead code)
  1. Size over lifetime (curve * startSize)
  2. Opacity over lifetime (curve * startOpacity)
  3. Color over lifetime (3 curves * startColor RGB)
  4. Rotation over lifetime (rotationSpeed * delta * 0.02)
  5. Linear velocity (optional per-axis curves)
  6. Orbital velocity (Euler rotation around emission offset)
  7. Noise (simplex 3D affecting position, rotation, size)

40 new tests covering curve baking, modifier pipeline creation, and
TSL noise function construction. All 849 tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

Bundle Size Report

File Size
three-particles.min.js 78 KB (79991 bytes)

✅ Bundle size is within the 150 KB limit.

claude and others added 23 commits April 8, 2026 18:17
Implement force field calculations on the GPU:

compute-force-fields.ts:
- encodeForceFieldsForGPU(): packs up to 16 force fields into a flat
  Float32Array (12 floats/field) for GPU storage buffer upload
- createForceFieldComputeNodes(): creates TSL nodes with Loop-based
  iteration over encoded fields, supporting:
  - POINT forces: radial attract/repel with distance-based falloff
    (none, linear, quadratic) and range limiting
  - DIRECTIONAL forces: constant force along a direction vector
  - Branchless falloff selection via select()

Integration into compute-modifiers.ts:
- Added forceFields flag to ModifierFlags
- Force field nodes created conditionally and applied between gravity
  and velocity integration (matching CPU execution order)
- forceFieldNodes exposed in pipeline return for CPU-side buffer updates

14 new tests covering encoding (both field types, all falloff modes,
multi-field packing, max cap) and TSL node creation.
All 863 tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
Examples (examples-data.js):
- GPU Galaxy: 50K particle spiral galaxy with orbital velocity
- GPU Particle Storm: 100K particles with 3 force field attractors
- GPU Firefly Swarm: 25K particles with simplex noise-driven motion
- GPU Confetti Burst: 75K mesh particles with gravity and rotation

Documentation updates:
- README: add WebGPU compute support to features list
- ROADMAP: move WebGPU from planned to completed
- llms.txt: add WebGPU section with setup guide, SimulationBackend
  table, and CPU/GPU split explanation
- CLAUDE.md: update project structure with webgpu/ directory tree,
  update project status

Co-Authored-By: Claude <noreply@anthropic.com>

https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
- Pack 10 per-particle scalar attributes into a single InterleavedBuffer
  (stride 10) to stay within WebGPU's 8 vertex buffer limit:
  POINTS=2, INSTANCED=3, MESH=6 buffers
- Add WebGPU build pipeline: src/webgpu.ts entry point, dist/webgpu.js,
  package.json ./webgpu export, webpack WebGPU bundle for examples
- Fix TSL null texture crash: use dummy DataTexture fallback for null
  map/sceneDepthTexture uniforms
- Fix TSL texture uniform: pass raw Texture to texture() node instead
  of wrapping in uniform() which created incompatible UniformNode
- Fix TSL WGSL discard: replace If(cond, Discard()) pattern with
  Discard(cond) for WGSL compatibility in all 4 TSL materials
- Force INSTANCED renderer for WebGPU examples (WebGPU has no
  gl_PointCoord/gl_PointSize support for POINTS)
- Examples page uses three.webgpu.js importmap for unified Three.js
  instance, WebGPURenderer with auto WebGL fallback
- GPU-tagged examples get TSL NodeMaterials; others use GLSL
  ShaderMaterial via simulationBackend: "CPU"
- Update all 23 test files for InterleavedBufferAttribute access patterns

Co-Authored-By: Claude <noreply@anthropic.com>
Connect the existing GPU compute shader infrastructure (Phases 2-4) to the
particle system so physics and modifiers run on the GPU when WebGPU is active.

Key changes:
- Create compute pipeline via factory pattern (keeps three/webgpu imports
  out of the main module)
- Pack storage buffers into 8 vec4 bindings to stay within WebGPU limits
  (position, velocity, color, particleState, startValues, startColorsExt,
  orbitalIsActive, curveData)
- Use vec4 for position/velocity buffers to avoid WebGPU vec3→vec4 alignment
  conversion that breaks TSL type resolution
- Pack RGBA color into single vec4 attribute (reduces vertex buffer count)
- TSL materials accept gpuCompute flag to read packed or individual attributes
- Compute dispatch via ParticleSystem.computeNode public API
- Always use TSL materials when factory is registered (WebGPU renderer compat)
- Bake constant/random velocity values as flat curves for GPU lookup
- Fix snoise3D parameter name bug ({position} → {v})
- Fix Fn() invocation (computeKernel → computeKernel())
- Fix vec4()/vec3() parameter overflow for Three.js r182 TSL compatibility
- Add vec2/vec3 imports to TSL files that were missing them

Compute shader generates valid WGSL and dispatches successfully.
Compute writeback to render buffers still needs verification.

Co-Authored-By: Claude <noreply@anthropic.com>
Allow any example to run with either GPU (WebGPU compute) or CPU (GLSL
ShaderMaterial) backend via a toggle button on each card and in the
expand modal. WebGPU-tagged examples default to GPU, others to CPU.
Also fixes missing compute dispatch in the ExpandedDemo and removes
leftover debug code from the WebGPU bundle.

Co-Authored-By: Claude <noreply@anthropic.com>
…dd FPS

Remove the PTS/INST/MESH/TRAIL renderer type selector from both card
and expand modal controls — the renderer type is now determined solely
by each example's config. Default all examples to GPU backend when
WebGPU is available. Add a live FPS counter overlay on card canvases
(bottom-left, visible during playback). Clean up dead CSS for
renderer-toggle, trail-badge, and webgpu-badge.

Co-Authored-By: Claude <noreply@anthropic.com>
…n, color

Three fixes for the WebGPU-based example viewer:

1. WGSL shader error in CPU mode: POINTS renderer used `pointUV` (which
   emits `gl_PointCoord` — GLSL only). Now force POINTS → INSTANCED
   whenever WebGPU is available, not just when GPU compute is active.

2. GPU compute particle vibration: the modifier compute shader calculated
   `lifePct` after incrementing lifetime, causing a one-frame temporal
   offset vs the CPU path. Swap the order so noise seeding matches.

3. Double-gamma / opaque appearance: WebGPURenderer's output pass applies
   linear→sRGB conversion, but particle textures (NoColorSpace) already
   contain sRGB values — resulting in double encoding. Set
   `outputColorSpace = LinearSRGBColorSpace` to match the old
   WebGLRenderer behaviour where raw sRGB values went straight to the
   framebuffer.

Co-Authored-By: Claude <noreply@anthropic.com>
Particle flickering in GPU compute mode was caused by
writeParticleToModifierBuffers setting needsUpdate on all storage
buffers on every emit, uploading stale CPU-side arrays that overwrote
GPU-computed state for all active particles.

Replace direct buffer writes with an emit queue appended to the
curveData buffer tail (no extra storage binding). The compute shader
scatter-copies queued entries into main buffers before simulation.
deactivateParticleInModifierBuffers is now a no-op since the GPU
death check handles deactivation.

Co-Authored-By: Claude <noreply@anthropic.com>
Three fixes for GPU compute particle simulation:

1. TSL simplex noise gradient extraction was broken — unbounded gradient
   components (up to ~5.7 instead of [-1,1]) caused noise output of ±88,
   resulting in rapid left-right particle rotation. Replaced with the
   standard Ashima/Gustavson octahedral gradient extraction (p mod 49).

2. GPU noise path was missing frequency scaling and FBM output
   normalization. Added noiseFrequency uniform and noisePower/fbmMax
   divisor to match CPU FBM behavior.

3. Position buffer overwrite: activateParticle wrote to the position
   storage buffer and set needsUpdate=true even in GPU compute mode,
   triggering a full CPU→GPU upload every emit that overwrote all
   GPU-computed positions. Particles appeared frozen/vibrating instead
   of moving. Now skipped when useGPUCompute is active.

Co-Authored-By: Claude <noreply@anthropic.com>
…ge bursts

Replace the O(N×M) emit queue scatter with an O(1) per-particle indexed
init approach. Each particle now has a fixed slot in the curveData buffer
tail; the compute shader checks a single initFlag per particle instead of
scanning the entire emit queue. This fixes the severe FPS drop with 75K
particle bursts (GPU Confetti Burst demo).

Also fixes:
- Mesh particle quaternion in GPU compute mode: derive from particleState.z
  in the vertex shader instead of reading a stale instanceQuat attribute
- InitFlag stale data causing flickering on continuous emitters (Smoke demo):
  flushEmitQueue now clears previous frame's initFlags in the CPU array
  before the next upload

Co-Authored-By: Claude <noreply@anthropic.com>
The ground plane in the soft particles demo appeared much darker after
the WebGPU migration because WebGPURenderer uses LinearSRGBColorSpace
output. Set the color in linear space directly to preserve intended
brightness.

Co-Authored-By: Claude <noreply@anthropic.com>
…bility

POINTS renderer guarantees at least 1px per particle, but INSTANCED
billboards can shrink to subpixel size and become invisible. Bump
startSize for Galaxy (~7x), Storm (~6x), and Firefly (~3x) so they
render visibly on the small example card canvases.

Co-Authored-By: Claude <noreply@anthropic.com>
…limit

Three bugs prevented force fields from working in WebGPU compute mode:

1. The applyForceFieldsTSL Fn lacked a 'void' return type, so the
   entire force field computation was silently dropped from the
   generated WGSL shader (non-void Fn calls are not added to the
   shader stack by three.js TSL).

2. Bare `return` inside TSL If() callbacks within a Loop has no effect
   on the shader — replaced with Continue() for proper loop control.

3. Force fields used a separate StorageBufferAttribute (9th binding),
   exceeding WebGPU's default 8-storage-buffer per-stage limit. Packed
   force field data into the existing curveData buffer tail instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Three related fixes for GPU compute particle systems:

1. Orbital velocity rotation order: The GPU used extrinsic X→Z→Y rotation
   but the CPU uses Euler(speedX, speedZ, speedY, 'XYZ') which is intrinsic
   XYZ = extrinsic Z→Y→X. Fixed the GPU to match. Also corrected the
   speed→Euler axis mapping (Y↔Z swap) that the CPU applies.

2. Inactive particle guard: TSL `return` inside an If() callback only exits
   the JS callback — it does NOT generate a WGSL `return` statement. The
   generated shader had an empty if-block, so inactive particles ran through
   the entire physics+modifier pipeline every frame. Wrapped all active
   particle logic inside a positive If(isActive >= 0.5) guard instead.

3. Sub-emitter death position: GPU-computed positions are not readable from
   the CPU without async readback. Added a CPU-side shadow simulation
   (velocity, gravity, force fields, orbital velocity) that tracks particle
   positions for death sub-emitter spawning. Critically, this avoids calling
   applyModifiers() which sets needsUpdate=true on the position buffer,
   triggering a full CPU→GPU upload that overwrites all GPU-computed positions.

Also adds 26 unit tests for orbital rotation CPU/GPU parity and exports a
pure-JS applyOrbitalRotation() that mirrors the GPU TSL logic for testability.

Co-Authored-By: Claude <noreply@anthropic.com>
…e particles

When WebGPU is available and registerTSLMaterialFactory is called, sub-emitter
configs defaulted to simulationBackend: AUTO, causing them to use GPU compute.
Since sub-emitter compute nodes are never dispatched (only the parent system's
computeNode gets renderer.compute()), StorageBuffer attributes were never
updated and particles remained invisible — in both CPU and GPU parent modes.

Force simulationBackend: CPU on all sub-emitters in spawnSubEmitters(), as
their compute nodes cannot be dispatched independently by the parent system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The startValues and startColorsExt buffers were uploaded via full-buffer
CPU→GPU transfers (needsUpdate = true) every frame that had new emits.
When a particle slot was recycled on the CPU (death → freeList → re-emit)
while the old particle was still alive on the GPU, the full upload
overwrote the active particle's startValues with the new emit's data —
causing wrong lifetime percentage, opacity, size, and color calculations
that manifested as 1-2 flickering white/pale dots.

The fix moves startValues and startColorsExt initialization into the
per-particle curveData init slot (INIT_STRIDE 20 → 28) and scatters
them to GPU storage buffers in the compute shader's init block. This
ensures only the particle being initialized receives new values.

Also fixes a secondary bug where the flushEmitQueue scan could overflow
into force field data when force fields were enabled, by deriving
maxParticles from the position buffer instead of the curveData length.

Co-Authored-By: Claude <noreply@anthropic.com>
…rror

deepMerge strips the THREE.Vector2 prototype from textureSheetAnimation.tiles
when merging JSON configs (plain {x, y} objects), causing TSL's uniform() to
fail with "Uniform null not implemented" since it cannot infer the type.

Co-Authored-By: Claude <noreply@anthropic.com>
…PU compute

New showcase example pushing WebGPU compute to its limits:
- 350K STARBURST-textured particles at 70K/sec emission rate
- 4 force fields (central repulsion + off-center attractors)
- Orbital velocity, 3-octave noise turbulence, rotation over lifetime
- Rainbow color gradient over lifetime (magenta→cyan→green→yellow→orange→red→purple)
- Wide start color range (cyan-green to magenta) for per-particle color variation

Co-Authored-By: Claude <noreply@anthropic.com>
…interleaved buffer layout

The GPU compute refactor changed color attributes from four separate floats
(colorR/G/B/A) to a single packed vec4 in the interleaved buffer, but the
GLSL vertex shaders were not updated. This caused all particles to render
fully transparent (vColor = vec4(0,0,0,0)) on any WebGL fallback path.

Also fixes generate-previews.html: forces CPU backend, caps particle counts
for GPU demos, upgrades POINTS→INSTANCED, and respects previewTime.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- README: WebGPU setup guide, SimulationBackend, fallback
- llms-full.txt: full WebGPU reference, computeNode, R3F
- llms.txt: expanded WebGPU section, compute dispatch
- architecture.md: dual-path architecture, storage buffers
- CLAUDE.md: WebGPU development guide, design decisions
- webgpu-compute-plan.md: all 6 phases marked completed
- testing.md: updated counts (947 tests, 43 suites)
- three-particles.ts: updated registerTSLMaterialFactory JSDoc

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 10 new test files covering previously untested WebGPU compute paths:
- curve-bake: velocity axis baking, createCurveDataTexture (→100% stmt)
- compute-modifiers: all modifier flag combinations, force fields, partial velocity axes
- compute-force-fields: applyForceFieldsTSL node graph construction
- tsl-materials-factory: createComputePipeline, createTSLParticleMaterial dispatch
- tsl-trail-ribbon-material: material creation, DoubleSide, soft particles (new coverage)
- tsl-shared-fn-invocation: computeFrameIndex, linearizeDepth, soft particles Fn calls
- tsl-noise-fn-invocation: snoise3D/particleNoise3 full algorithm invocation
- webgpu-compute-integration: GPU pipeline creation with mocked factory
- three-particles-trail-edge-cases: vertical tangent, twist prevention, ribbon mode
- three-particles-gpu-misc: noise offset init via updateConfig, GPU noise uniforms, disposal

Coverage: statements 79.33%→81.25%, branches 85.11%→89.79%, lines 78.77%→80.43%

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
NewKrok and others added 9 commits April 14, 2026 20:58
The WebGPU renderer applies a full-screen linear→sRGB output pass that
the GLSL ShaderMaterial path does not have (it omits #include
<colorspace_fragment>). Additionally, WebGPU uses hardware sRGB→linear
texture sampling when the texture has SRGBColorSpace.

These two transforms caused particle colors to appear brighter and less
transparent in the WebGPU/TSL path compared to the WebGL/GLSL path.

Fixes applied:
- Set texture colorSpace to NoColorSpace in TSL uniforms to disable
  hardware sRGB→linear conversion during sampling
- Apply sRGBTransferEOTF (sRGB→linear) on fragment output RGB to
  compensate for the renderer's linear→sRGB output pass
- Set toneMapped=false and fog=false on all TSL materials to match
  the GLSL ShaderMaterial behavior (no tone mapping, no fog)
- Set ClampToEdgeWrapping on particle textures to prevent sprite-sheet
  tile bleeding at boundaries

Co-Authored-By: Claude <noreply@anthropic.com>
…constraints

Add collision plane system inspired by Unity's Collision Module. Particles
can be killed, clamped, or bounced when they cross user-defined infinite
planes — enabling effects like underwater bubbles popping at a water surface.

- New CollisionPlaneMode enum (KILL, CLAMP, BOUNCE)
- CPU collision logic (three-particles-collision.ts)
- GPU compute TSL collision shader (compute-collision-planes.ts)
- Full dual-path support: CPU simulation + WebGPU compute
- Serialization/deserialization support
- 43 new tests (22 CPU + 21 GPU encoding)
- Underwater bubbles example demonstrating KILL mode
- Documentation updated (README, ROADMAP, llms.txt, llms-full.txt, CLAUDE.md)

Co-Authored-By: Claude <noreply@anthropic.com>
…ation mode

Sub-emitters spawned at the wrong position when the parent particle system
had a transform.position offset in LOCAL simulation space. The particle's
local position was passed directly as the sub-emitter's scene position,
ignoring the parent's world transform.

Now uses particleSystem.localToWorld() to convert the particle position
before spawning death/birth sub-emitters. Also refines the Bubble Surface
Pop example with transform offset, slower rise speed, and more particles.

Co-Authored-By: Claude <noreply@anthropic.com>
…enderers

Skip all vertex transforms for particles with alpha <= 0 by emitting a
degenerate clip-space position (vec4(0)) that produces zero-area triangles.
Applied to GLSL shaders and TSL materials for both instanced billboard and
mesh particle renderers.

Co-Authored-By: Claude <noreply@anthropic.com>
- Add enableWebGPU() convenience function for one-line setup
- Add hand-written TypeScript declarations for ./webgpu export
- Eliminate per-frame Float32Array allocations in force field/collision encoding
- Add dead particle early-out in POINTS TSL vertex shader
- Deduplicate TSL material fragment logic using tsl-shared.ts helpers
- Optimize flushEmitQueue from O(maxParticles) to O(emittedLastFrame)
- Extract magic numbers (POINT_SIZE_SCALE, ALPHA_DISCARD_THRESHOLD) into constants
- Add setUniformFloat/setUniformVec3 helpers to centralize type casts
- Pre-compute fbmMax at system creation time instead of per-frame
- Import CURVE_RESOLUTION from curve-bake.ts instead of redefining

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…tion

Replace verbose 9-import registerTSLMaterialFactory() setup with the
new 2-line enableWebGPU() approach in llms.txt, llms-full.txt, and
README.md. Keep registerTSLMaterialFactory as documented advanced
alternative.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… point

serializeParticleSystem, deserializeParticleSystem, isComputeCapableRenderer,
and resolveSimulationBackend were missing from the public API surface.

Co-Authored-By: Claude <noreply@anthropic.com>
The webgpu bundle's `enableWebGPU()` was producing an empty function body
because `registerTSLMaterialFactory` was imported via a relative path, causing
tsup to inline `three-particles.ts` into both bundles. This created duplicate
`_tslMaterialFactory` variables and Rollup correctly tree-shook the write as
dead code within the isolated webgpu bundle.

Switch the import to `@newkrok/three-particles` (self-referencing package
export) so the registration resolves to the same module instance at runtime.

Co-Authored-By: Claude <noreply@anthropic.com>
@NewKrok NewKrok merged commit 553d544 into master Apr 16, 2026
7 checks passed
@NewKrok NewKrok deleted the claude/webgpu-compute-support-3kCxi branch April 16, 2026 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants