docs: add WebGPU compute support implementation plan#34
Merged
Conversation
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
Contributor
Bundle Size Report
✅ Bundle size is within the 150 KB limit. |
Co-Authored-By: Claude <noreply@anthropic.com> https://claude.ai/code/session_01Fdf59LrJU15yk6iFT157Lm
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>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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