[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7CS5ZHNF2JQVTSPTDKCTMRE":3,"skill-same:01M7CS5ZHNF2JQVTSPTDKCTMRE":50},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":30,"repositoryHtmlUrl":31,"repositoryHomepageUrl":32,"ownerHtmlUrl":33,"ownerBlogUrl":6,"ownerDescription":34,"updatedAt":35,"install":36,"resources":49},"01M7CS5ZHNF2JQVTSPTDKCTMRE","web-3d-threejs-babylon",null,"Use when building a 3D web game with three.js, Babylon.js or PlayCanvas - render loop and delta per library, fixed-step physics with Rapier or Havok, explicit dispose of GPU resources, instancing and draw-call budgets, glTF with Draco\u002Fmeshopt\u002FKTX2, pixel ratio and resize, WebGPU opt-in, React Three Fiber notes, and headless testing.","makifbaysal\u002Ftasktrooper","makifbaysal","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F25031940?v=4","01M7CRG3ZCSYZSSEVDMW3DEYC8","Mehmet Akif Baysal","01M7CRG401FJ8YAXH5ER730XYV",122,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fgame-developer\u002Fskills\u002Fweb-3d-threejs-babylon\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: web-3d-threejs-babylon\ncategory: engine\ndescription: Use when building a 3D web game with three.js, Babylon.js or PlayCanvas - render loop and delta per library, fixed-step physics with Rapier or Havok, explicit dispose of GPU resources, instancing and draw-call budgets, glTF with Draco\u002Fmeshopt\u002FKTX2, pixel ratio and resize, WebGPU opt-in, React Three Fiber notes, and headless testing.\ntech_stack: Web 3D\nsource: informed by the three.js, Babylon.js, PlayCanvas and Rapier documentation; own wording\n---\n# Web 3D: three.js, Babylon.js, PlayCanvas\n\n## Overview\n\nthree.js is a rendering library with a huge ecosystem; Babylon.js is a full engine (physics plugin, GUI, inspector, a `NullEngine` for headless tests); PlayCanvas is an engine built around its hosted editor, also usable engine-only. All three hand you the GPU directly — and with it the job of freeing what you allocate, keeping draw calls low, and staying inside a mobile browser's memory.\n\n**Core principle:** Simulate on a fixed step, render every frame, dispose every GPU resource you create, and count draw calls.\n\n## The loop and delta\n\n```ts\n\u002F\u002F three.js — Timer replaces the deprecated Clock (r183+); setAnimationLoop also drives WebXR\nconst timer = new THREE.Timer();\ntimer.connect(document);                         \u002F\u002F ignores the huge delta after a hidden tab\nrenderer.setAnimationLoop((t) => {\n  timer.update(t);\n  const dt = Math.min(timer.getDelta(), 0.25);   \u002F\u002F seconds\n  stepFixed(dt);                                 \u002F\u002F accumulator: physics + rules at 1\u002F60 (game-loop-and-time)\n  renderer.render(scene, camera);\n});\n```\n\n```ts\n\u002F\u002F Babylon.js — getDeltaTime() is milliseconds\nscene.onBeforeRenderObservable.add(() => stepFixed(Math.min(engine.getDeltaTime() \u002F 1000, 0.25)));\nengine.runRenderLoop(() => scene.render());\nwindow.addEventListener(\"resize\", () => engine.resize());\n```\n\n```ts\n\u002F\u002F PlayCanvas (engine API \u002F ESM scripts) — dt in seconds\nexport class Spin extends Script {\n  static scriptName = \"spin\";\n  speed = 90;\n  update(dt: number) { this.entity.rotate(0, this.speed * dt, 0); }\n}\n```\n\n## Physics on a fixed step\n\n- **Rapier** (WASM, three.js or Babylon): `await RAPIER.init()`, `world.timestep = 1 \u002F 60`, call `world.step()` from the accumulator, copy body transforms to meshes with interpolation. The deterministic build exists for lockstep\u002Frollback.\n- **Babylon**: Havok via the physics V2 plugin (`new HavokPlugin(true, await HavokPhysics())`); keep its fixed timestep consistent across devices.\n- **PlayCanvas**: its rigidbody components (ammo.js) step with the app.\n- Never move a dynamic body by writing `mesh.position`; set velocities\u002Fimpulses or use kinematic bodies.\n\n## Dispose what you create\n\n```ts\n\u002F\u002F ❌ removing from the scene does not free GPU memory\nscene.remove(level);\n\n\u002F\u002F ✅ free geometry, materials and textures explicitly (unless shared with something still alive)\nlevel.traverse((o) => {\n  if (o instanceof THREE.Mesh) {\n    o.geometry.dispose();\n    for (const m of Array.isArray(o.material) ? o.material : [o.material]) {\n      for (const v of Object.values(m)) if (v instanceof THREE.Texture) v.dispose();\n      m.dispose();\n    }\n  }\n});\nscene.remove(level);\nconsole.assert(renderer.info.memory.geometries \u003C= baseline.geometries);\n```\n\n- three.js: also dispose render targets, `PMREMGenerator` outputs, and the renderer itself on teardown. `renderer.info.memory` before and after a level change is the leak test.\n- Babylon: `mesh.dispose(false, true)` frees materials and textures too; load levels into an `AssetContainer` and `dispose()` it on exit; `scene.dispose()` \u002F `engine.dispose()` on teardown.\n- PlayCanvas: `entity.destroy()`, and `asset.unload()` for assets no longer used.\n\n## Draw calls and instancing\n\n- Many copies of one mesh: `THREE.InstancedMesh` (`setMatrixAt` + `instanceMatrix.needsUpdate = true`, `count` for the live number) or Babylon thin instances (`mesh.thinInstanceAdd(matrix)`).\n- Merge static scenery (`BufferGeometryUtils.mergeGeometries`, Babylon `Mesh.MergeMeshes`) and share materials.\n- Budget draw calls per frame — a few hundred for mobile browsers, more on desktop — and read the actual number (`renderer.info.render.calls`, Babylon Inspector's statistics) before and after.\n- Shadows are expensive: one shadow-casting light, tight shadow camera bounds, `castShadow` only where it shows; bake lighting for static scenes.\n- Cap the pixel ratio: `renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))`; resize from the canvas size, not the window, with a `ResizeObserver`.\n\n## Assets\n\n- glTF\u002FGLB with Draco or meshopt geometry compression and KTX2 textures: three.js `GLTFLoader` + `DRACOLoader` \u002F `MeshoptDecoder` + `KTX2Loader` (decoder files served from the app's own path); Babylon's glTF loader with its Draco\u002FKTX2 support; `LoadAssetContainerAsync` to keep a level's assets disposable together.\n- Optimise models offline (`npx @gltf-transform\u002Fcli optimize`) and keep originals out of the shipped bundle (game-asset-pipeline).\n\n## WebGPU\n\nthree.js `WebGPURenderer` (from `three\u002Fwebgpu`, falling back to WebGL2) and Babylon `WebGPUEngine` are usable; adopt them only when the repository or task opts in — shader code, post-processing and some materials differ between the paths.\n\n## React Three Fiber (if the repo uses it)\n\n`useFrame((state, delta) => ...)` mutates refs; never `setState` per frame. Dispose is automatic for objects R3F created declaratively, not for ones you created imperatively. `\u003CInstances>` \u002F `\u003CinstancedMesh>` for repetition.\n\n## Testing\n\n- Rules and simulation: plain TS with Vitest, no renderer import.\n- Babylon: `new NullEngine()` + `new Scene(engine)` runs scene logic headless in Vitest (no pixels).\n- three.js: scene-graph logic can be tested without a renderer; rendering is checked with the seeded Playwright smoke run and screenshots (game-visual-self-review). Headless Chromium uses a software GL — correct images, meaningless frame rates.\n\n## Common Mistakes\n\n- `scene.remove` without `dispose` — memory grows every level.\n- Allocating `new THREE.Vector3()` in the frame loop instead of reusing module-level temporaries.\n- Full device pixel ratio on 3× phones.\n- One mesh per bullet or tree instead of instancing.\n- `THREE.Clock` in new code on a revision that deprecated it.\n\n## Red Flags\n\n- No `dispose()` call anywhere in a project that loads more than one level.\n- `renderer.info.render.calls` in the thousands on a mobile target.\n- Physics stepped with the raw render delta.\n","# Web 3D: three.js, Babylon.js, PlayCanvas\n\n## Overview\n\nthree.js is a rendering library with a huge ecosystem; Babylon.js is a full engine (physics plugin, GUI, inspector, a `NullEngine` for headless tests); PlayCanvas is an engine built around its hosted editor, also usable engine-only. All three hand you the GPU directly — and with it the job of freeing what you allocate, keeping draw calls low, and staying inside a mobile browser's memory.\n\n**Core principle:** Simulate on a fixed step, render every frame, dispose every GPU resource you create, and count draw calls.\n\n## The loop and delta\n\n```ts\n\u002F\u002F three.js — Timer replaces the deprecated Clock (r183+); setAnimationLoop also drives WebXR\nconst timer = new THREE.Timer();\ntimer.connect(document);                         \u002F\u002F ignores the huge delta after a hidden tab\nrenderer.setAnimationLoop((t) => {\n  timer.update(t);\n  const dt = Math.min(timer.getDelta(), 0.25);   \u002F\u002F seconds\n  stepFixed(dt);                                 \u002F\u002F accumulator: physics + rules at 1\u002F60 (game-loop-and-time)\n  renderer.render(scene, camera);\n});\n```\n\n```ts\n\u002F\u002F Babylon.js — getDeltaTime() is milliseconds\nscene.onBeforeRenderObservable.add(() => stepFixed(Math.min(engine.getDeltaTime() \u002F 1000, 0.25)));\nengine.runRenderLoop(() => scene.render());\nwindow.addEventListener(\"resize\", () => engine.resize());\n```\n\n```ts\n\u002F\u002F PlayCanvas (engine API \u002F ESM scripts) — dt in seconds\nexport class Spin extends Script {\n  static scriptName = \"spin\";\n  speed = 90;\n  update(dt: number) { this.entity.rotate(0, this.speed * dt, 0); }\n}\n```\n\n## Physics on a fixed step\n\n- **Rapier** (WASM, three.js or Babylon): `await RAPIER.init()`, `world.timestep = 1 \u002F 60`, call `world.step()` from the accumulator, copy body transforms to meshes with interpolation. The deterministic build exists for lockstep\u002Frollback.\n- **Babylon**: Havok via the physics V2 plugin (`new HavokPlugin(true, await HavokPhysics())`); keep its fixed timestep consistent across devices.\n- **PlayCanvas**: its rigidbody components (ammo.js) step with the app.\n- Never move a dynamic body by writing `mesh.position`; set velocities\u002Fimpulses or use kinematic bodies.\n\n## Dispose what you create\n\n```ts\n\u002F\u002F ❌ removing from the scene does not free GPU memory\nscene.remove(level);\n\n\u002F\u002F ✅ free geometry, materials and textures explicitly (unless shared with something still alive)\nlevel.traverse((o) => {\n  if (o instanceof THREE.Mesh) {\n    o.geometry.dispose();\n    for (const m of Array.isArray(o.material) ? o.material : [o.material]) {\n      for (const v of Object.values(m)) if (v instanceof THREE.Texture) v.dispose();\n      m.dispose();\n    }\n  }\n});\nscene.remove(level);\nconsole.assert(renderer.info.memory.geometries \u003C= baseline.geometries);\n```\n\n- three.js: also dispose render targets, `PMREMGenerator` outputs, and the renderer itself on teardown. `renderer.info.memory` before and after a level change is the leak test.\n- Babylon: `mesh.dispose(false, true)` frees materials and textures too; load levels into an `AssetContainer` and `dispose()` it on exit; `scene.dispose()` \u002F `engine.dispose()` on teardown.\n- PlayCanvas: `entity.destroy()`, and `asset.unload()` for assets no longer used.\n\n## Draw calls and instancing\n\n- Many copies of one mesh: `THREE.InstancedMesh` (`setMatrixAt` + `instanceMatrix.needsUpdate = true`, `count` for the live number) or Babylon thin instances (`mesh.thinInstanceAdd(matrix)`).\n- Merge static scenery (`BufferGeometryUtils.mergeGeometries`, Babylon `Mesh.MergeMeshes`) and share materials.\n- Budget draw calls per frame — a few hundred for mobile browsers, more on desktop — and read the actual number (`renderer.info.render.calls`, Babylon Inspector's statistics) before and after.\n- Shadows are expensive: one shadow-casting light, tight shadow camera bounds, `castShadow` only where it shows; bake lighting for static scenes.\n- Cap the pixel ratio: `renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))`; resize from the canvas size, not the window, with a `ResizeObserver`.\n\n## Assets\n\n- glTF\u002FGLB with Draco or meshopt geometry compression and KTX2 textures: three.js `GLTFLoader` + `DRACOLoader` \u002F `MeshoptDecoder` + `KTX2Loader` (decoder files served from the app's own path); Babylon's glTF loader with its Draco\u002FKTX2 support; `LoadAssetContainerAsync` to keep a level's assets disposable together.\n- Optimise models offline (`npx @gltf-transform\u002Fcli optimize`) and keep originals out of the shipped bundle (game-asset-pipeline).\n\n## WebGPU\n\nthree.js `WebGPURenderer` (from `three\u002Fwebgpu`, falling back to WebGL2) and Babylon `WebGPUEngine` are usable; adopt them only when the repository or task opts in — shader code, post-processing and some materials differ between the paths.\n\n## React Three Fiber (if the repo uses it)\n\n`useFrame((state, delta) => ...)` mutates refs; never `setState` per frame. Dispose is automatic for objects R3F created declaratively, not for ones you created imperatively. `\u003CInstances>` \u002F `\u003CinstancedMesh>` for repetition.\n\n## Testing\n\n- Rules and simulation: plain TS with Vitest, no renderer import.\n- Babylon: `new NullEngine()` + `new Scene(engine)` runs scene logic headless in Vitest (no pixels).\n- three.js: scene-graph logic can be tested without a renderer; rendering is checked with the seeded Playwright smoke run and screenshots (game-visual-self-review). Headless Chromium uses a software GL — correct images, meaningless frame rates.\n\n## Common Mistakes\n\n- `scene.remove` without `dispose` — memory grows every level.\n- Allocating `new THREE.Vector3()` in the frame loop instead of reusing module-level temporaries.\n- Full device pixel ratio on 3× phones.\n- One mesh per bullet or tree instead of instancing.\n- `THREE.Clock` in new code on a revision that deprecated it.\n\n## Red Flags\n\n- No `dispose()` call anywhere in a project that loads more than one level.\n- `renderer.info.render.calls` in the thousands on a mobile target.\n- Physics stepped with the raw render delta.\n",{"name":5,"source":24,"category":25,"tech_stack":26,"description":7},"informed by the three.js, Babylon.js, PlayCanvas and Rapier documentation; own wording","engine","Web 3D","main","910394a0b6db9fc8c9a8f36328ec421d3ebd8b38","catalog\u002Fagents\u002Fgame-developer\u002Fskills\u002Fweb-3d-threejs-babylon",18,"https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper","https:\u002F\u002Ftasktrooper.ai","https:\u002F\u002Fgithub.com\u002Fmakifbaysal","Senior Software Developer","2026-11-15 04:50:29",{"source":8,"skillName":5,"commands":37,"prompt":47,"zipAvailable":48},[38,41,44],{"tool":39,"command":40},"npx","npx skills add makifbaysal\u002Ftasktrooper --skill web-3d-threejs-babylon",{"tool":42,"command":43},"bunx","bunx skills add makifbaysal\u002Ftasktrooper --skill web-3d-threejs-babylon",{"tool":45,"command":46},"pnpm","pnpm dlx skills add makifbaysal\u002Ftasktrooper --skill web-3d-threejs-babylon","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fgame-developer\u002Fskills\u002Fweb-3d-threejs-babylon\u002FSKILL.md",true,[],[51,57,64,71,78,85],{"skillNo":52,"name":53,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":54,"categories":55,"keywords":56,"publishedAt":19},"01M7CSVEPQW6J6TD6CS2T5FPNZ","visual-craft","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fvisual-craft\u002FSKILL.md",[],[],{"skillNo":58,"name":59,"nameZh":6,"description":60,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":61,"categories":62,"keywords":63,"publishedAt":19},"01M7CSVAQG91ETHQ0HBNZDG5FR","ux-copy","Use when you write any words a user reads in a mockup or a hand-off - content language and voice, buttons, labels, errors, empty states, confirmations, numbers and dates, and the longest-string check","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fux-copy\u002FSKILL.md",[],[],{"skillNo":65,"name":66,"nameZh":6,"description":67,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":68,"categories":69,"keywords":70,"publishedAt":19},"01M7CSV6H0J38659NDXHJQ8396","screen-mockup-html","Use when you draw screens as the design task's HTML mockup - ONE canvas document holding every screen and every variant side by side, the sanitizer-safe recipe, phone and wide frames, the states grid, static control states, and the loopback self-check with screenshots at 375, 768 and 1440 attached to the task","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fscreen-mockup-html\u002FSKILL.md",[],[],{"skillNo":72,"name":73,"nameZh":6,"description":74,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":77,"publishedAt":19},"01M7CSV3JFRF3BM3XK52M7YEYR","performance-awareness","How the performance score moves for your role. Use when the score context shows a declining trend, or before handing off work you have not self-checked against every criterion.","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fperformance-awareness\u002FSKILL.md",[],[],{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":19},"01M7CSTZDH00YRF5SCT7BRT9QD","design-variants","Use when a screen design needs variants - how many, variants as side-by-side rows on the one canvas, what makes two variants genuinely different, recommending one, how the human's choice is read, and narrowing to the chosen one in revision","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fdesign-variants\u002FSKILL.md",[],[],{"skillNo":86,"name":87,"nameZh":6,"description":88,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":91,"publishedAt":19},"01M7CSTV6P3SM3PAE28DB0RF77","design-system-authoring","Use when you derive, change or extend a design system - where tokens live per stack, the DTCG token tree, role-based names for both themes, base vs layer vs drift, the DESIGN.md section order, the inventory format, the contrast check and the lint every proposal returns","https:\u002F\u002Fgithub.com\u002Fmakifbaysal\u002Ftasktrooper\u002Fblob\u002Fmain\u002Fcatalog\u002Fagents\u002Fui-designer\u002Fskills\u002Fdesign-system-authoring\u002FSKILL.md",[],[]]