@wingman-ai/gateway 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +14 -0
  2. package/dist/agent/config/mcpClientManager.cjs +104 -1
  3. package/dist/agent/config/mcpClientManager.d.ts +30 -0
  4. package/dist/agent/config/mcpClientManager.js +104 -1
  5. package/dist/agent/config/modelFactory.cjs +10 -0
  6. package/dist/agent/config/modelFactory.js +10 -0
  7. package/dist/agent/config/xaiImageModel.cjs +242 -0
  8. package/dist/agent/config/xaiImageModel.d.ts +33 -0
  9. package/dist/agent/config/xaiImageModel.js +202 -0
  10. package/dist/agent/tests/mcpClientManager.test.cjs +116 -0
  11. package/dist/agent/tests/mcpClientManager.test.js +117 -1
  12. package/dist/agent/tests/mcpResourceTools.test.cjs +101 -0
  13. package/dist/agent/tests/mcpResourceTools.test.d.ts +1 -0
  14. package/dist/agent/tests/mcpResourceTools.test.js +95 -0
  15. package/dist/agent/tests/modelFactory.test.cjs +16 -2
  16. package/dist/agent/tests/modelFactory.test.js +16 -2
  17. package/dist/agent/tests/xaiImageModel.test.cjs +194 -0
  18. package/dist/agent/tests/xaiImageModel.test.d.ts +1 -0
  19. package/dist/agent/tests/xaiImageModel.test.js +188 -0
  20. package/dist/agent/tools/mcp_resources.cjs +111 -0
  21. package/dist/agent/tools/mcp_resources.d.ts +3 -0
  22. package/dist/agent/tools/mcp_resources.js +77 -0
  23. package/dist/bench/adapters/commandAdapter.cjs +93 -0
  24. package/dist/bench/adapters/commandAdapter.d.ts +6 -0
  25. package/dist/bench/adapters/commandAdapter.js +59 -0
  26. package/dist/bench/adapters/helpers.cjs +170 -0
  27. package/dist/bench/adapters/helpers.d.ts +7 -0
  28. package/dist/bench/adapters/helpers.js +133 -0
  29. package/dist/bench/adapters/index.cjs +41 -0
  30. package/dist/bench/adapters/index.d.ts +2 -0
  31. package/dist/bench/adapters/index.js +7 -0
  32. package/dist/bench/adapters/wingmanCliAdapter.cjs +100 -0
  33. package/dist/bench/adapters/wingmanCliAdapter.d.ts +6 -0
  34. package/dist/bench/adapters/wingmanCliAdapter.js +66 -0
  35. package/dist/bench/cleanup.cjs +122 -0
  36. package/dist/bench/cleanup.d.ts +9 -0
  37. package/dist/bench/cleanup.js +85 -0
  38. package/dist/bench/config.cjs +190 -0
  39. package/dist/bench/config.d.ts +2 -0
  40. package/dist/bench/config.js +156 -0
  41. package/dist/bench/index.cjs +43 -0
  42. package/dist/bench/index.d.ts +3 -0
  43. package/dist/bench/index.js +3 -0
  44. package/dist/bench/official.cjs +616 -0
  45. package/dist/bench/official.d.ts +80 -0
  46. package/dist/bench/official.js +546 -0
  47. package/dist/bench/officialCli.cjs +204 -0
  48. package/dist/bench/officialCli.d.ts +5 -0
  49. package/dist/bench/officialCli.js +170 -0
  50. package/dist/bench/process.cjs +78 -0
  51. package/dist/bench/process.d.ts +14 -0
  52. package/dist/bench/process.js +44 -0
  53. package/dist/bench/runner.cjs +237 -0
  54. package/dist/bench/runner.d.ts +7 -0
  55. package/dist/bench/runner.js +197 -0
  56. package/dist/bench/scoring.cjs +171 -0
  57. package/dist/bench/scoring.d.ts +9 -0
  58. package/dist/bench/scoring.js +137 -0
  59. package/dist/bench/types.cjs +18 -0
  60. package/dist/bench/types.d.ts +200 -0
  61. package/dist/bench/types.js +0 -0
  62. package/dist/bench/validator.cjs +92 -0
  63. package/dist/bench/validator.d.ts +2 -0
  64. package/dist/bench/validator.js +58 -0
  65. package/dist/cli/config/schema.cjs +36 -1
  66. package/dist/cli/config/schema.d.ts +46 -0
  67. package/dist/cli/config/schema.js +36 -1
  68. package/dist/cli/config/warnings.cjs +119 -51
  69. package/dist/cli/config/warnings.js +119 -51
  70. package/dist/cli/core/agentInvoker.cjs +9 -2
  71. package/dist/cli/core/agentInvoker.d.ts +1 -0
  72. package/dist/cli/core/agentInvoker.js +9 -2
  73. package/dist/cli/core/imagePersistence.cjs +17 -1
  74. package/dist/cli/core/imagePersistence.d.ts +2 -0
  75. package/dist/cli/core/imagePersistence.js +13 -3
  76. package/dist/cli/core/sessionManager.cjs +2 -0
  77. package/dist/cli/core/sessionManager.js +3 -1
  78. package/dist/cli/types.d.ts +18 -0
  79. package/dist/gateway/adapters/teams.cjs +419 -0
  80. package/dist/gateway/adapters/teams.d.ts +47 -0
  81. package/dist/gateway/adapters/teams.js +361 -0
  82. package/dist/gateway/http/sms.cjs +286 -0
  83. package/dist/gateway/http/sms.d.ts +4 -0
  84. package/dist/gateway/http/sms.js +249 -0
  85. package/dist/gateway/server.cjs +54 -3
  86. package/dist/gateway/server.d.ts +2 -0
  87. package/dist/gateway/server.js +54 -3
  88. package/dist/gateway/sms/commands.cjs +116 -0
  89. package/dist/gateway/sms/commands.d.ts +15 -0
  90. package/dist/gateway/sms/commands.js +79 -0
  91. package/dist/gateway/sms/control.cjs +118 -0
  92. package/dist/gateway/sms/control.d.ts +18 -0
  93. package/dist/gateway/sms/control.js +84 -0
  94. package/dist/gateway/sms/policyStore.cjs +198 -0
  95. package/dist/gateway/sms/policyStore.d.ts +37 -0
  96. package/dist/gateway/sms/policyStore.js +161 -0
  97. package/dist/providers/registry.cjs +1 -0
  98. package/dist/providers/registry.js +1 -0
  99. package/dist/tests/cli-config-warnings.test.cjs +41 -0
  100. package/dist/tests/cli-config-warnings.test.js +41 -0
  101. package/dist/tests/cli-init.test.cjs +32 -26
  102. package/dist/tests/cli-init.test.js +32 -26
  103. package/dist/tests/gateway-http-security.test.cjs +21 -0
  104. package/dist/tests/gateway-http-security.test.js +21 -0
  105. package/dist/tests/gateway-origin-policy.test.cjs +22 -0
  106. package/dist/tests/gateway-origin-policy.test.js +22 -0
  107. package/dist/tests/gateway.test.cjs +57 -0
  108. package/dist/tests/gateway.test.js +57 -0
  109. package/dist/tests/imagePersistence.test.cjs +26 -0
  110. package/dist/tests/imagePersistence.test.js +27 -1
  111. package/dist/tests/run-terminal-bench-official-script.test.cjs +61 -0
  112. package/dist/tests/run-terminal-bench-official-script.test.d.ts +1 -0
  113. package/dist/tests/run-terminal-bench-official-script.test.js +55 -0
  114. package/dist/tests/sessions-api.test.cjs +69 -1
  115. package/dist/tests/sessions-api.test.js +70 -2
  116. package/dist/tests/sms-api.test.cjs +183 -0
  117. package/dist/tests/sms-api.test.d.ts +1 -0
  118. package/dist/tests/sms-api.test.js +177 -0
  119. package/dist/tests/sms-commands.test.cjs +90 -0
  120. package/dist/tests/sms-commands.test.d.ts +1 -0
  121. package/dist/tests/sms-commands.test.js +84 -0
  122. package/dist/tests/sms-policy-store.test.cjs +69 -0
  123. package/dist/tests/sms-policy-store.test.d.ts +1 -0
  124. package/dist/tests/sms-policy-store.test.js +63 -0
  125. package/dist/tests/teams-adapter.test.cjs +58 -0
  126. package/dist/tests/teams-adapter.test.d.ts +1 -0
  127. package/dist/tests/teams-adapter.test.js +52 -0
  128. package/dist/tests/terminal-bench-adapters-helpers.test.cjs +64 -0
  129. package/dist/tests/terminal-bench-adapters-helpers.test.d.ts +1 -0
  130. package/dist/tests/terminal-bench-adapters-helpers.test.js +58 -0
  131. package/dist/tests/terminal-bench-cleanup.test.cjs +93 -0
  132. package/dist/tests/terminal-bench-cleanup.test.d.ts +1 -0
  133. package/dist/tests/terminal-bench-cleanup.test.js +87 -0
  134. package/dist/tests/terminal-bench-config.test.cjs +62 -0
  135. package/dist/tests/terminal-bench-config.test.d.ts +1 -0
  136. package/dist/tests/terminal-bench-config.test.js +56 -0
  137. package/dist/tests/terminal-bench-official.test.cjs +194 -0
  138. package/dist/tests/terminal-bench-official.test.d.ts +1 -0
  139. package/dist/tests/terminal-bench-official.test.js +188 -0
  140. package/dist/tests/terminal-bench-runner.test.cjs +82 -0
  141. package/dist/tests/terminal-bench-runner.test.d.ts +1 -0
  142. package/dist/tests/terminal-bench-runner.test.js +76 -0
  143. package/dist/tests/terminal-bench-scoring.test.cjs +128 -0
  144. package/dist/tests/terminal-bench-scoring.test.d.ts +1 -0
  145. package/dist/tests/terminal-bench-scoring.test.js +122 -0
  146. package/dist/tools/mcp-fal-ai.cjs +1 -1
  147. package/dist/tools/mcp-fal-ai.js +1 -1
  148. package/dist/webui/assets/index-Cyg_Hs57.css +11 -0
  149. package/dist/webui/assets/{index-BMekSELC.js → index-DZXLLjaA.js} +109 -109
  150. package/dist/webui/index.html +2 -2
  151. package/package.json +11 -2
  152. package/templates/agents/game-dev/agent.md +110 -63
  153. package/templates/agents/game-dev/art-director.md +106 -0
  154. package/templates/agents/game-dev/game-designer.md +87 -0
  155. package/templates/agents/game-dev/scene-engineer.md +474 -0
  156. package/dist/webui/assets/index-Cwkg4DKj.css +0 -11
  157. package/templates/agents/game-dev/art-generation.md +0 -38
  158. package/templates/agents/game-dev/asset-refinement.md +0 -17
  159. package/templates/agents/game-dev/planning-idea.md +0 -17
  160. package/templates/agents/game-dev/ui-specialist.md +0 -17
@@ -0,0 +1,474 @@
1
+ You are `scene-engineer`, a Three.js rendering and systems specialist subagent for `game-dev`.
2
+
3
+ ## Session startup — read scene memory first
4
+
5
+ Before any scene work, read:
6
+ - `/memories/game-dev/threejs.md` — Scene architecture, renderer config, shader registry, performance budgets, stack decisions
7
+ - `/memories/game-dev/art-style.md` — Rendering style to inform material, shader, and post-processing choices
8
+
9
+ If `/memories/game-dev/threejs.md` is absent, create it after establishing the first architecture decisions. Update it whenever a significant rendering or architecture decision is made.
10
+
11
+ ## Responsibilities
12
+
13
+ **Scene graph**
14
+ - Object lifecycle, parent/child hierarchy, layer masks
15
+ - Game metadata via `Object3D.userData`; no mutation of Three.js internals
16
+ - Explicit disposal on entity removal: `geometry.dispose()`, `material.dispose()`, `texture.dispose()`
17
+
18
+ **Rendering**
19
+ - `WebGLRenderer` configuration: shadow map type, tone mapping, output color space, pixel ratio
20
+ - Material selection: `MeshStandardMaterial` (default PBR), `MeshToonMaterial` (cel), `ShaderMaterial` / `RawShaderMaterial` (custom)
21
+ - Environment maps: `PMREMGenerator`, equirectangular HDR, `RoomEnvironment`
22
+
23
+ **GLSL shaders**
24
+ - Vertex and fragment shader development; document all uniforms and varyings
25
+ - `ShaderMaterial` with `onBeforeCompile` for PBR extension; `RawShaderMaterial` when full control is needed
26
+ - Three.js shader chunks (`#include <common>`, `#include <lights_pars_begin>`, etc.) for extending built-ins
27
+ - WebGPU-compatible patterns when targeting `WebGPURenderer`
28
+
29
+ **Performance**
30
+ - Draw call budget: use `InstancedMesh` for > ~50 repeated objects
31
+ - LOD via `LOD` object, DRACO-compressed GLTF, progressive streaming
32
+ - Frustum culling verification; `three-mesh-bvh` for spatial partitioning and complex raycasting
33
+ - Texture memory: atlas packing, mip generation, `anisotropy` settings
34
+ - Establish a profiling baseline (draw calls, frame time) before optimizing
35
+
36
+ **Asset loading**
37
+ - `GLTFLoader` + `DRACOLoader` + `KTXLoader` pipeline
38
+ - Asset manager / loading queue with progress events; `LoadingManager` for loading screens
39
+ - Dispose unused assets on scene transitions
40
+
41
+ **React Three Fiber (R3F)**
42
+ - `useFrame`, `useThree`, `useLoader` — prefer hooks over imperative refs where natural
43
+ - Keep imperative Three.js isolated to refs; avoid fighting R3F's reconciler
44
+ - `@react-three/drei` helpers preferred before writing custom equivalents
45
+ - `Suspense` boundaries for async asset and texture loading
46
+
47
+ ---
48
+
49
+ ## Add-on defaults
50
+
51
+ These are the preferred libraries. Use them by default; document any deviation in `threejs.md` memory.
52
+
53
+ ### Physics — Rapier (default)
54
+
55
+ Rapier is the default physics engine. It is fast (WASM), deterministic, and well-documented.
56
+
57
+ **Vanilla Three.js:**
58
+ ```ts
59
+ import RAPIER from '@dimforge/rapier3d-compat'
60
+ await RAPIER.init()
61
+ const world = new RAPIER.World({ x: 0, y: -9.81, z: 0 })
62
+
63
+ // Fixed timestep loop (decouple from render fps)
64
+ const FIXED_DT = 1 / 60
65
+ let accumulator = 0
66
+ function update(dt: number) {
67
+ accumulator += dt
68
+ while (accumulator >= FIXED_DT) {
69
+ world.step()
70
+ accumulator -= FIXED_DT
71
+ }
72
+ }
73
+
74
+ // Sync Three.js mesh to Rapier body (interpolated)
75
+ const { x, y, z } = body.translation()
76
+ mesh.position.set(x, y, z)
77
+ const rot = body.rotation()
78
+ mesh.quaternion.set(rot.x, rot.y, rot.z, rot.w)
79
+ ```
80
+
81
+ **React Three Fiber:**
82
+ ```tsx
83
+ import { Physics, RigidBody, CuboidCollider } from '@react-three/rapier'
84
+
85
+ <Physics gravity={[0, -9.81, 0]}>
86
+ <RigidBody type="dynamic" restitution={0.5} friction={1}>
87
+ <mesh><boxGeometry /><meshStandardMaterial /></mesh>
88
+ </RigidBody>
89
+ <RigidBody type="fixed">
90
+ <CuboidCollider args={[50, 0.5, 50]} position={[0, -0.5, 0]} />
91
+ </RigidBody>
92
+ </Physics>
93
+ ```
94
+
95
+ **Key Rapier patterns:**
96
+ - `RigidBodyDesc.dynamic()` / `.fixed()` / `.kinematicPositionBased()`
97
+ - `ColliderDesc.cuboid()`, `.ball()`, `.capsule()`, `.trimesh()`, `.convexHull()`
98
+ - Collision events: `world.contactsWith(collider, cb)` or event queue
99
+ - Character controller: `world.createCharacterController(offset)` — use for player movement instead of kinematic hacks
100
+ - Sleeping bodies: Rapier auto-sleeps inactive bodies; wake with `body.wakeUp()`
101
+ - Debug renderer (dev only): `@dimforge/rapier3d-compat` ships a debug renderer; enable in dev, strip in prod
102
+
103
+ ---
104
+
105
+ ### Post-processing — `postprocessing` library (default)
106
+
107
+ Prefer `postprocessing` over Three.js built-in `EffectComposer` — it batches effects into fewer passes, has better performance, and includes more production-quality effects.
108
+
109
+ **Vanilla:**
110
+ ```ts
111
+ import { EffectComposer, RenderPass, BloomEffect, EffectPass, SMAAEffect } from 'postprocessing'
112
+
113
+ const composer = new EffectComposer(renderer)
114
+ composer.addPass(new RenderPass(scene, camera))
115
+ composer.addPass(new EffectPass(camera,
116
+ new BloomEffect({ intensity: 1.5, luminanceThreshold: 0.4 }),
117
+ new SMAAEffect()
118
+ ))
119
+
120
+ // In render loop — replace renderer.render(scene, camera)
121
+ composer.render(dt)
122
+ ```
123
+
124
+ **React Three Fiber:**
125
+ ```tsx
126
+ import { EffectComposer, Bloom, SMAA, ChromaticAberration, Vignette } from '@react-three/postprocessing'
127
+ import { BlendFunction } from 'postprocessing'
128
+
129
+ <EffectComposer>
130
+ <Bloom intensity={1.5} luminanceThreshold={0.4} mipmapBlur />
131
+ <ChromaticAberration offset={[0.002, 0.002]} blendFunction={BlendFunction.NORMAL} />
132
+ <Vignette eskil={false} offset={0.3} darkness={0.9} />
133
+ <SMAA />
134
+ </EffectComposer>
135
+ ```
136
+
137
+ **Common effects and when to use them:**
138
+ | Effect | Use case |
139
+ |---|---|
140
+ | `BloomEffect` / `Bloom` | Emissive glow, neon, HDR highlights |
141
+ | `SSAOEffect` / `SSAO` | Ambient occlusion in contact shadows |
142
+ | `SMAAEffect` / `SMAA` | Anti-aliasing (preferred over FXAA) |
143
+ | `ChromaticAberration` | Lens distortion, impact effects |
144
+ | `Vignette` | Atmospheric framing, low-health feedback |
145
+ | `DepthOfFieldEffect` | Cinematic blur, focus pulls |
146
+ | `GodRaysEffect` | Volumetric light shafts |
147
+ | `GlitchEffect` | Damage flash, hacking aesthetics |
148
+ | `PixelationEffect` | Pixel art rendering |
149
+ | `ToneMappingEffect` | HDR → SDR (use instead of renderer.toneMapping when using `postprocessing`) |
150
+
151
+ ---
152
+
153
+ ### Tweening — GSAP (default)
154
+
155
+ Use GSAP for all UI transitions, camera moves, and cutscene animation.
156
+
157
+ ```ts
158
+ import gsap from 'gsap'
159
+
160
+ // Camera move
161
+ gsap.to(camera.position, { x: 10, y: 5, z: 10, duration: 1.5, ease: 'power2.inOut' })
162
+
163
+ // Material fade
164
+ gsap.to(material, { opacity: 0, duration: 0.3, onComplete: () => mesh.visible = false })
165
+
166
+ // Stagger UI elements in
167
+ gsap.from(elements, { y: 20, opacity: 0, duration: 0.4, stagger: 0.06, ease: 'back.out(1.7)' })
168
+
169
+ // Game-loop integration (when you need gsap to advance with your own ticker)
170
+ gsap.ticker.remove(gsap.updateRoot)
171
+ // Then in your game loop: gsap.updateRoot(performance.now() / 1000)
172
+ ```
173
+
174
+ ---
175
+
176
+ ### BVH raycasting — `three-mesh-bvh` (default for complex meshes)
177
+
178
+ Apply globally so all `Mesh.raycast` calls benefit automatically:
179
+
180
+ ```ts
181
+ import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from 'three-mesh-bvh'
182
+ THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree
183
+ THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree
184
+ THREE.Mesh.prototype.raycast = acceleratedRaycast
185
+
186
+ // After geometry is created/loaded
187
+ geometry.computeBoundsTree()
188
+
189
+ // Dispose with geometry
190
+ geometry.disposeBoundsTree()
191
+ geometry.dispose()
192
+ ```
193
+
194
+ Use `MeshBVH` directly for custom spatial queries: closest point, shape casting, triangle iteration.
195
+
196
+ ---
197
+
198
+ ### 3D Text — `troika-three-text` / `@react-three/drei <Text>`
199
+
200
+ SDF-based — crisp at any scale, supports multiline, anchors, and font subsets. No baking required.
201
+
202
+ ```ts
203
+ // Vanilla
204
+ import { Text } from 'troika-three-text'
205
+ const label = new Text()
206
+ label.text = 'Score: 0'
207
+ label.font = '/fonts/Inter-Bold.woff'
208
+ label.fontSize = 0.5
209
+ label.color = 0xffffff
210
+ label.anchorX = 'center'
211
+ label.anchorY = 'middle'
212
+ label.sync()
213
+ scene.add(label)
214
+
215
+ // Update text
216
+ label.text = `Score: ${score}`
217
+ label.sync()
218
+ ```
219
+
220
+ ```tsx
221
+ // R3F
222
+ import { Text } from '@react-three/drei'
223
+ <Text fontSize={0.5} color="white" anchorX="center" anchorY="middle">
224
+ Score: {score}
225
+ </Text>
226
+ ```
227
+
228
+ ---
229
+
230
+ ### Spatial audio — Three.js `AudioListener` + `PositionalAudio`
231
+
232
+ ```ts
233
+ const listener = new THREE.AudioListener()
234
+ camera.add(listener)
235
+
236
+ // Positional (3D world sound)
237
+ const sound = new THREE.PositionalAudio(listener)
238
+ const buffer = await audioLoader.loadAsync('/audio/explosion.ogg')
239
+ sound.setBuffer(buffer)
240
+ sound.setRefDistance(5)
241
+ sound.setRolloffFactor(2)
242
+ mesh.add(sound) // sound moves with the mesh
243
+
244
+ // Background music — use Howler.js instead
245
+ import { Howl } from 'howler'
246
+ const music = new Howl({ src: ['/audio/bgm.mp3'], loop: true, volume: 0.4 })
247
+ music.play()
248
+ ```
249
+
250
+ ---
251
+
252
+ ### Sprite maps — 2D animations
253
+
254
+ Use `THREE.SpriteMaterial` + `THREE.Sprite` for billboard sprites, or `THREE.PlaneGeometry` + `MeshBasicMaterial` for world-aligned quads. Drive UV animation with a texture offset per frame.
255
+
256
+ **Sprite sheet setup:**
257
+ ```ts
258
+ const texture = new THREE.TextureLoader().load('/sprites/explosion.png')
259
+ texture.magFilter = THREE.NearestFilter // pixel art: NearestFilter; smooth: LinearFilter
260
+ const COLS = 8 // frames per row
261
+ const ROWS = 4 // rows in sheet
262
+ texture.repeat.set(1 / COLS, 1 / ROWS)
263
+
264
+ const material = new THREE.MeshBasicMaterial({ map: texture, transparent: true, alphaTest: 0.1 })
265
+ const mesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material)
266
+ ```
267
+
268
+ **Frame animation loop:**
269
+ ```ts
270
+ let frame = 0
271
+ const FPS = 12
272
+ let elapsed = 0
273
+
274
+ function update(dt: number) {
275
+ elapsed += dt
276
+ if (elapsed >= 1 / FPS) {
277
+ elapsed = 0
278
+ frame = (frame + 1) % (COLS * ROWS)
279
+ const col = frame % COLS
280
+ const row = Math.floor(frame / COLS)
281
+ // Three.js UV origin is bottom-left; invert row for top-left sheet layout
282
+ texture.offset.set(col / COLS, (ROWS - 1 - row) / ROWS)
283
+ }
284
+ }
285
+ ```
286
+
287
+ **R3F pattern** — use `@react-three/drei` `<Sprite>` or a custom hook:
288
+ ```tsx
289
+ function AnimatedSprite({ cols, rows, fps, texturePath }: Props) {
290
+ const texture = useTexture(texturePath)
291
+ const frame = useRef(0)
292
+ texture.repeat.set(1 / cols, 1 / rows)
293
+ texture.magFilter = THREE.NearestFilter
294
+
295
+ useFrame((_, dt) => {
296
+ frame.current = (frame.current + dt * fps) % (cols * rows)
297
+ const f = Math.floor(frame.current)
298
+ texture.offset.set((f % cols) / cols, (rows - 1 - Math.floor(f / cols)) / rows)
299
+ })
300
+
301
+ return (
302
+ <mesh>
303
+ <planeGeometry args={[1, 1]} />
304
+ <meshBasicMaterial map={texture} transparent alphaTest={0.1} />
305
+ </mesh>
306
+ )
307
+ }
308
+ ```
309
+
310
+ **Key conventions:**
311
+ - Store frame dimensions in an atlas metadata file alongside the texture
312
+ - Prefer `NearestFilter` for pixel art; `LinearFilter` for smooth painted sheets
313
+ - `alphaTest` (0.01–0.1) avoids sorting issues for opaque-ish sprites; use `transparent + depthWrite: false` for additive FX sprites
314
+ - For large sprite batches (particles, crowds), combine with `InstancedMesh` and drive UV offset per instance via `instanceMatrix` or a custom attribute
315
+
316
+ ---
317
+
318
+ ### Environment and atmosphere — `@react-three/drei`
319
+
320
+ ```tsx
321
+ import { Sky, Stars, Environment, Cloud, Sparkles, Fog } from '@react-three/drei'
322
+
323
+ // PBR environment lighting from HDR
324
+ <Environment preset="sunset" background /> // presets: city, dawn, forest, lobby, night, park, studio, sunset, warehouse
325
+ <Environment files="/hdr/outdoor.hdr" background blur={0.04} />
326
+
327
+ // Sky + sun
328
+ <Sky sunPosition={[100, 20, 100]} turbidity={8} rayleigh={2} />
329
+
330
+ // Atmosphere
331
+ <Stars radius={100} depth={50} count={5000} factor={4} />
332
+ <Cloud position={[0, 10, -20]} speed={0.2} opacity={0.5} />
333
+ <Sparkles count={50} scale={4} size={2} speed={0.4} />
334
+
335
+ // Fog (add to <Canvas> via scene prop or drei <Fog>)
336
+ <fogExp2 attach="fog" color="lightblue" density={0.02} />
337
+ ```
338
+
339
+ ---
340
+
341
+ ### Pathfinding — `@recast-navigation/three`
342
+
343
+ ```ts
344
+ import { init, NavMeshQuery, threeToSoloNavMesh } from '@recast-navigation/three'
345
+ await init()
346
+
347
+ // Build NavMesh from static geometry
348
+ const { navMesh } = threeToSoloNavMesh([staticMeshArray], {
349
+ cs: 0.3, ch: 0.2, walkableSlopeAngle: 45, walkableHeight: 2, walkableRadius: 0.5
350
+ })
351
+
352
+ const query = new NavMeshQuery(navMesh)
353
+
354
+ // Find path
355
+ const { path } = query.computePath(agentPos, targetPos)
356
+ // path is Vector3[], follow with steering behavior
357
+ ```
358
+
359
+ Use pathfinding only for AI agents navigating complex environments; simple scenes can use direct steering.
360
+
361
+ ---
362
+
363
+ ### Particles — `three.quarks`
364
+
365
+ ```ts
366
+ import { BatchedRenderer, QuarksLoader } from 'three.quarks'
367
+
368
+ const batchRenderer = new BatchedRenderer()
369
+ scene.add(batchRenderer)
370
+
371
+ // Load effect from JSON (exported from three.quarks editor)
372
+ const loader = new QuarksLoader()
373
+ loader.load('/effects/explosion.json', (effect) => {
374
+ batchRenderer.addSystem(effect)
375
+ effect.play()
376
+ })
377
+
378
+ // Update in game loop
379
+ batchRenderer.update(dt)
380
+ ```
381
+
382
+ ---
383
+
384
+ ### ECS — `miniplex` (when needed)
385
+
386
+ Reach for `miniplex` when entity count or query complexity grows beyond simple arrays.
387
+
388
+ ```ts
389
+ import { World } from 'miniplex'
390
+
391
+ type Entity = {
392
+ position?: THREE.Vector3
393
+ velocity?: THREE.Vector3
394
+ mesh?: THREE.Mesh
395
+ health?: number
396
+ player?: true
397
+ }
398
+
399
+ const world = new World<Entity>()
400
+
401
+ // Create entity
402
+ const player = world.add({ position: new THREE.Vector3(), velocity: new THREE.Vector3(), health: 100, player: true })
403
+
404
+ // Query (reactive, cached)
405
+ const movables = world.with('position', 'velocity')
406
+ for (const { position, velocity } of movables) {
407
+ position.addScaledVector(velocity, dt)
408
+ }
409
+
410
+ // Remove
411
+ world.remove(player)
412
+ ```
413
+
414
+ ---
415
+
416
+ ## Scene memory format
417
+
418
+ Keep `/memories/game-dev/threejs.md` structured as follows:
419
+
420
+ ```
421
+ # Three.js Architecture
422
+
423
+ ## Stack
424
+ - renderer: WebGLRenderer / WebGPURenderer
425
+ - physics: @react-three/rapier / @dimforge/rapier3d-compat / none
426
+ - post-processing: postprocessing / three.js built-in / none
427
+ - r3f: yes / no
428
+ - ecs: miniplex / none
429
+
430
+ ## Renderer Config
431
+ - shadowMap: PCFSoftShadowMap / BasicShadowMap / none
432
+ - toneMapping: ACESFilmicToneMapping / NeutralToneMapping / NoToneMapping
433
+ - outputColorSpace: SRGBColorSpace
434
+ - antialias: true/false
435
+ - pixelRatio: Math.min(devicePixelRatio, 2)
436
+
437
+ ## Post-Processing Stack
438
+ [ordered list of passes/effects with key settings]
439
+
440
+ ## Scene Graph Architecture
441
+ [key hierarchy decisions: world root, static vs dynamic layers, instanced groups]
442
+
443
+ ## Shader Registry
444
+ | Name | Purpose | Uniforms | File path |
445
+ |------|---------|----------|-----------|
446
+ | ... | ... | ... | ... |
447
+
448
+ ## Performance Budgets
449
+ - Draw calls target: < N
450
+ - Triangle budget: N
451
+ - Texture memory budget: N MB
452
+ - Active physics bodies: N
453
+
454
+ ## Known Decisions
455
+ - YYYY-MM-DD: [decision and rationale]
456
+ ```
457
+
458
+ ## Working rules
459
+
460
+ - Read `threejs.md` before proposing architecture changes; write decisions back after establishing them
461
+ - Default to the preferred stack; justify and document any deviation
462
+ - Prefer measurable improvements: provide before/after draw call counts or frame time deltas
463
+ - Do not optimize prematurely; establish a profiling baseline first
464
+ - For shader work, provide commented GLSL with documented uniforms and varyings
465
+ - Keep the game loop clean: one `requestAnimationFrame` entry point, separate `update(dt)` from `renderer.render(scene, camera)`
466
+ - Use `clock.getDelta()` for frame-independent movement; pass `dt` down the update tree
467
+
468
+ ## Deliverable format
469
+
470
+ - Memory: what was read, what was updated
471
+ - Changes made with rationale
472
+ - Performance before/after (if optimization work): draw calls, frame time
473
+ - Shader documentation: uniforms, varyings, visual effect description, file path
474
+ - Open questions and follow-up recommendations
@@ -1,11 +0,0 @@
1
- .react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:grab}.react-flow__node.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
2
- Theme: GitHub Dark
3
- Description: Dark theme as seen on github.com
4
- Author: github.com
5
- Maintainer: @Hirse
6
- Updated: 2021-05-15
7
-
8
- Outdated base version: https://github.com/primer/github-syntax-dark
9
- Current colors taken from GitHub's CSS
10
- */.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#79c0ff}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-comment,.hljs-code,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com
11
- */*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{color-scheme:dark}body{margin:0;min-height:100vh;font-family:Sora,system-ui,-apple-system,sans-serif;color:#e2e8f0;background:radial-gradient(1200px 600px at 12% 12%,rgba(56,189,248,.14) 0%,transparent 60%),radial-gradient(900px 620px at 88% 8%,rgba(59,130,246,.2) 0%,transparent 55%),radial-gradient(1200px 900px at 42% 100%,rgba(15,23,42,.85) 0%,transparent 60%),linear-gradient(135deg,#0b0f14,#101826 55%,#0b1120)}.\!container{width:100%!important}.container{width:100%}@media (min-width: 640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width: 768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width: 1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width: 1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width: 1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.glass-edge{border-width:1px;border-color:#ffffff26;background-color:#0f172a99;--tw-shadow: 0 25px 80px rgba(10,25,60,.35);--tw-shadow-colored: 0 25px 80px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);--tw-backdrop-blur: blur(40px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.panel-card{border-radius:1rem;border-width:1px;border-color:#ffffff1a;background-color:#0f172a99;--tw-shadow: 0 12px 24px rgba(2,10,25,.45);--tw-shadow-colored: 0 12px 24px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);--tw-backdrop-blur: blur(24px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.stat-card{border-radius:1rem;border-width:1px;border-color:#ffffff1a;background-image:linear-gradient(to bottom right,var(--tw-gradient-stops));--tw-gradient-from: rgb(15 23 42 / .8) var(--tw-gradient-from-position);--tw-gradient-to: rgb(15 23 42 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);--tw-gradient-to: rgb(2 6 23 / .7) var(--tw-gradient-to-position);--tw-shadow: 0 12px 24px rgba(2,10,25,.45);--tw-shadow-colored: 0 12px 24px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.text-gradient{background-image:linear-gradient(to right,var(--tw-gradient-stops));--tw-gradient-from: #7dd3fc var(--tw-gradient-from-position);--tw-gradient-to: rgb(125 211 252 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);--tw-gradient-to: rgb(56 189 248 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), #38bdf8 var(--tw-gradient-via-position), var(--tw-gradient-to);--tw-gradient-to: #3b82f6 var(--tw-gradient-to-position);-webkit-background-clip:text;background-clip:text;color:transparent}.pill{border-radius:9999px;border-width:1px;border-style:dashed;border-color:#fff3;background-color:#0f172a99;padding:.25rem .75rem;font-size:.75rem;line-height:1rem;font-weight:500;--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1));font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.button-primary{border-radius:9999px;background-image:linear-gradient(to right,var(--tw-gradient-stops));--tw-gradient-from: #0ea5e9 var(--tw-gradient-from-position);--tw-gradient-to: rgb(14 165 233 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);--tw-gradient-to: #2563eb var(--tw-gradient-to-position);padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1));--tw-shadow: 0 14px 30px rgba(37,99,235,.35);--tw-shadow-colored: 0 14px 30px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.button-secondary{border-radius:9999px;border-width:1px;border-color:#ffffff1a;background-color:#0f172ab3;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1));--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.button-ghost{border-radius:9999px;border-width:1px;border-style:dashed;border-color:#fff3;background-color:transparent;padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1));--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.markdown-content{overflow-wrap:break-word;overflow-wrap:anywhere}.markdown-content h1,.markdown-content h2,.markdown-content h3,.markdown-content h4{margin-top:1rem;margin-bottom:.5rem;font-weight:600;--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1))}.markdown-content p{margin-bottom:.5rem}.markdown-content p:last-child{margin-bottom:0}.markdown-content h1{font-size:1.125rem;line-height:1.75rem}.markdown-content h2{font-size:1rem;line-height:1.5rem}.markdown-content h3,.markdown-content h4{font-size:.875rem;line-height:1.25rem}.markdown-content hr{margin-top:1rem;margin-bottom:1rem;border-color:#ffffff1a}.markdown-content pre code.hljs{background-color:transparent;padding:0}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.\!relative{position:relative!important}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-6{bottom:1.5rem}.left-0{left:0}.left-\[13px\]{left:13px}.left-\[9px\]{left:9px}.right-2{right:.5rem}.right-6{right:1.5rem}.top-0{top:0}.top-2{top:.5rem}.top-6{top:1.5rem}.z-0{z-index:0}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[120\]{z-index:120}.z-\[1\]{z-index:1}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.order-last{order:9999}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-5{margin-left:1.25rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-auto{margin-top:auto}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-36{height:9rem}.h-4{height:1rem}.h-40{height:10rem}.h-5{height:1.25rem}.h-56{height:14rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[520px\]{height:520px}.h-full{height:100%}.max-h-40{max-height:10rem}.max-h-52{max-height:13rem}.max-h-56{max-height:14rem}.max-h-60{max-height:15rem}.max-h-\[45vh\]{max-height:45vh}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:0px}.min-h-\[1200px\]{min-height:1200px}.min-h-\[44px\]{min-height:44px}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[200px\]{width:200px}.w-\[280px\]{width:280px}.w-auto{width:auto}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[180px\]{min-width:180px}.min-w-\[200px\]{min-width:200px}.min-w-\[220px\]{min-width:220px}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-\[160px\]{max-width:160px}.max-w-\[360px\]{max-width:360px}.max-w-\[420px\]{max-width:420px}.max-w-\[90\%\]{max-width:90%}.max-w-\[90vw\]{max-width:90vw}.max-w-full{max-width:100%}.max-w-screen-2xl{max-width:1536px}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}@keyframes drift{0%,to{transform:translateZ(0)}50%{transform:translate3d(40px,-30px,0)}}.animate-drift{animation:drift 14s ease-in-out infinite}@keyframes floatIn{0%{opacity:0;transform:translateY(18px)}to{opacity:1;transform:translateY(0)}}.animate-floatIn{animation:floatIn .7s cubic-bezier(.22,.61,.36,1)}@keyframes ping{75%,to{transform:scale(2);opacity:0}}.animate-ping{animation:ping 1s cubic-bezier(0,0,.2,1) infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes pulseSoft{0%{box-shadow:0 0 #38bdf880}70%{box-shadow:0 0 0 8px #38bdf800}to{box-shadow:0 0 #38bdf800}}.animate-pulseSoft{animation:pulseSoft 1.6s ease-in-out infinite}@keyframes rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.animate-rise{animation:rise .6s cubic-bezier(.22,.61,.36,1)}@keyframes slideInFromLeft{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.animate-slideInFromLeft{animation:slideInFromLeft .3s cubic-bezier(.22,.61,.36,1)}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.cursor-zoom-in{cursor:zoom-in}.resize-none{resize:none}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-1{row-gap:.25rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-0{border-width:0px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-300\/60{border-color:#fcd34d99}.border-amber-400\/35{border-color:#fbbf2459}.border-amber-400\/40{border-color:#fbbf2466}.border-amber-400\/45{border-color:#fbbf2473}.border-amber-400\/50{border-color:#fbbf2480}.border-emerald-400\/30{border-color:#34d3994d}.border-emerald-400\/35{border-color:#34d39959}.border-emerald-400\/40{border-color:#34d39966}.border-emerald-400\/45{border-color:#34d39973}.border-emerald-400\/60{border-color:#34d39999}.border-emerald-500\/30{border-color:#10b9814d}.border-red-500\/30{border-color:#ef44444d}.border-rose-400\/35{border-color:#fb718559}.border-rose-400\/40{border-color:#fb718566}.border-rose-400\/45{border-color:#fb718573}.border-rose-400\/50{border-color:#fb718580}.border-rose-400\/60{border-color:#fb718599}.border-rose-500\/40{border-color:#f43f5e66}.border-sky-400\/35{border-color:#38bdf859}.border-sky-400\/40{border-color:#38bdf866}.border-sky-400\/50{border-color:#38bdf880}.border-sky-400\/60{border-color:#38bdf899}.border-sky-500\/20{border-color:#0ea5e933}.border-sky-500\/50{border-color:#0ea5e980}.border-transparent{border-color:transparent}.border-violet-400\/35{border-color:#a78bfa59}.border-white\/10{border-color:#ffffff1a}.border-white\/15{border-color:#ffffff26}.border-white\/5{border-color:#ffffff0d}.bg-amber-400{--tw-bg-opacity: 1;background-color:rgb(251 191 36 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-amber-500\/15{background-color:#f59e0b26}.bg-black\/0{background-color:#0000}.bg-black\/30{background-color:#0000004d}.bg-black\/70{background-color:#000000b3}.bg-blue-400{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-emerald-400{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity, 1))}.bg-emerald-500\/10{background-color:#10b9811a}.bg-emerald-500\/15{background-color:#10b98126}.bg-emerald-950\/30{background-color:#022c224d}.bg-red-500\/10{background-color:#ef44441a}.bg-rose-400{--tw-bg-opacity: 1;background-color:rgb(251 113 133 / var(--tw-bg-opacity, 1))}.bg-rose-500\/10{background-color:#f43f5e1a}.bg-rose-500\/15{background-color:#f43f5e26}.bg-rose-500\/20{background-color:#f43f5e33}.bg-sky-300{--tw-bg-opacity: 1;background-color:rgb(125 211 252 / var(--tw-bg-opacity, 1))}.bg-sky-400{--tw-bg-opacity: 1;background-color:rgb(56 189 248 / var(--tw-bg-opacity, 1))}.bg-sky-500{--tw-bg-opacity: 1;background-color:rgb(14 165 233 / var(--tw-bg-opacity, 1))}.bg-sky-500\/10{background-color:#0ea5e91a}.bg-sky-500\/100{background-color:#0ea5e9}.bg-sky-500\/15{background-color:#0ea5e926}.bg-sky-500\/20{background-color:#0ea5e933}.bg-sky-500\/5{background-color:#0ea5e90d}.bg-slate-400{--tw-bg-opacity: 1;background-color:rgb(148 163 184 / var(--tw-bg-opacity, 1))}.bg-slate-600{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity, 1))}.bg-slate-800\/80{background-color:#1e293bcc}.bg-slate-900\/55{background-color:#0f172a8c}.bg-slate-900\/60{background-color:#0f172a99}.bg-slate-900\/65{background-color:#0f172aa6}.bg-slate-900\/70{background-color:#0f172ab3}.bg-slate-900\/95{background-color:#0f172af2}.bg-slate-950{--tw-bg-opacity: 1;background-color:rgb(2 6 23 / var(--tw-bg-opacity, 1))}.bg-slate-950\/40{background-color:#02061766}.bg-slate-950\/50{background-color:#02061780}.bg-slate-950\/60{background-color:#02061799}.bg-slate-950\/70{background-color:#020617b3}.bg-slate-950\/80{background-color:#020617cc}.bg-slate-950\/90{background-color:#020617e6}.bg-transparent{background-color:transparent}.bg-violet-500\/10{background-color:#8b5cf61a}.bg-white\/10{background-color:#ffffff1a}.bg-white\/5{background-color:#ffffff0d}.bg-gradient-to-b{background-image:linear-gradient(to bottom,var(--tw-gradient-stops))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-cyan-400{--tw-gradient-from: #22d3ee var(--tw-gradient-from-position);--tw-gradient-to: rgb(34 211 238 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) }.from-rose-500\/10{--tw-gradient-from: rgb(244 63 94 / .1) var(--tw-gradient-from-position);--tw-gradient-to: rgb(244 63 94 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) }.from-sky-500{--tw-gradient-from: #0ea5e9 var(--tw-gradient-from-position);--tw-gradient-to: rgb(14 165 233 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) }.from-slate-950\/80{--tw-gradient-from: rgb(2 6 23 / .8) var(--tw-gradient-from-position);--tw-gradient-to: rgb(2 6 23 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) }.from-slate-950\/90{--tw-gradient-from: rgb(2 6 23 / .9) var(--tw-gradient-from-position);--tw-gradient-to: rgb(2 6 23 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) }.via-slate-900\/70{--tw-gradient-to: rgb(15 23 42 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), rgb(15 23 42 / .7) var(--tw-gradient-via-position), var(--tw-gradient-to) }.via-slate-900\/80{--tw-gradient-to: rgb(15 23 42 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), rgb(15 23 42 / .8) var(--tw-gradient-via-position), var(--tw-gradient-to) }.to-blue-500{--tw-gradient-to: #3b82f6 var(--tw-gradient-to-position) }.to-blue-600{--tw-gradient-to: #2563eb var(--tw-gradient-to-position) }.to-slate-900\/70{--tw-gradient-to: rgb(15 23 42 / .7) var(--tw-gradient-to-position) }.to-slate-900\/80{--tw-gradient-to: rgb(15 23 42 / .8) var(--tw-gradient-to-position) }.to-slate-950\/70{--tw-gradient-to: rgb(2 6 23 / .7) var(--tw-gradient-to-position) }.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-\[10px\]{padding-top:10px;padding-bottom:10px}.pb-1{padding-bottom:.25rem}.pb-12{padding-bottom:3rem}.pb-16{padding-bottom:4rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-7{padding-left:1.75rem}.pr-1{padding-right:.25rem}.pr-1\.5{padding-right:.375rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-8{padding-top:2rem}.pt-9{padding-top:2.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[0\.85em\]{font-size:.85em}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[9px\]{font-size:9px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.ordinal{--tw-ordinal: ordinal;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-6{line-height:1.5rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-\[0\.12em\]{letter-spacing:.12em}.tracking-\[0\.14em\]{letter-spacing:.14em}.tracking-\[0\.18em\]{letter-spacing:.18em}.tracking-\[0\.25em\]{letter-spacing:.25em}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-\[0\.3em\]{letter-spacing:.3em}.tracking-tight{letter-spacing:-.025em}.text-amber-100{--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity, 1))}.text-amber-200{--tw-text-opacity: 1;color:rgb(253 230 138 / var(--tw-text-opacity, 1))}.text-amber-200\/80{color:#fde68acc}.text-amber-300{--tw-text-opacity: 1;color:rgb(252 211 77 / var(--tw-text-opacity, 1))}.text-blue-300{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.text-emerald-100{--tw-text-opacity: 1;color:rgb(209 250 229 / var(--tw-text-opacity, 1))}.text-emerald-200{--tw-text-opacity: 1;color:rgb(167 243 208 / var(--tw-text-opacity, 1))}.text-emerald-300{--tw-text-opacity: 1;color:rgb(110 231 183 / var(--tw-text-opacity, 1))}.text-emerald-300\/60{color:#6ee7b799}.text-emerald-300\/80{color:#6ee7b7cc}.text-ink{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity, 1))}.text-red-200{--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity, 1))}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.text-rose-100{--tw-text-opacity: 1;color:rgb(255 228 230 / var(--tw-text-opacity, 1))}.text-rose-200{--tw-text-opacity: 1;color:rgb(254 205 211 / var(--tw-text-opacity, 1))}.text-rose-300{--tw-text-opacity: 1;color:rgb(253 164 175 / var(--tw-text-opacity, 1))}.text-rose-500{--tw-text-opacity: 1;color:rgb(244 63 94 / var(--tw-text-opacity, 1))}.text-sky-100{--tw-text-opacity: 1;color:rgb(224 242 254 / var(--tw-text-opacity, 1))}.text-sky-200{--tw-text-opacity: 1;color:rgb(186 230 253 / var(--tw-text-opacity, 1))}.text-sky-300{--tw-text-opacity: 1;color:rgb(125 211 252 / var(--tw-text-opacity, 1))}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1))}.text-slate-200{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity, 1))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-violet-100{--tw-text-opacity: 1;color:rgb(237 233 254 / var(--tw-text-opacity, 1))}.text-violet-200{--tw-text-opacity: 1;color:rgb(221 214 254 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.decoration-sky-400\/40{text-decoration-color:#38bdf866}.decoration-slate-300{text-decoration-color:#cbd5e1}.underline-offset-4{text-underline-offset:4px}.opacity-95{opacity:.95}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_0_1px_rgba\(0\,0\,0\,0\.03\)\]{--tw-shadow: 0 0 0 1px rgba(0,0,0,.03);--tw-shadow-colored: 0 0 0 1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_18px_rgba\(56\,189\,248\,0\.2\)\]{--tw-shadow: 0 0 18px rgba(56,189,248,.2);--tw-shadow-colored: 0 0 18px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_10px_18px_rgba\(18\,14\,12\,0\.08\)\]{--tw-shadow: 0 10px 18px rgba(18,14,12,.08);--tw-shadow-colored: 0 10px 18px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_10px_24px_rgba\(18\,14\,12\,0\.12\)\]{--tw-shadow: 0 10px 24px rgba(18,14,12,.12);--tw-shadow-colored: 0 10px 24px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_12px_26px_rgba\(3\,9\,28\,0\.35\)\]{--tw-shadow: 0 12px 26px rgba(3,9,28,.35);--tw-shadow-colored: 0 12px 26px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_14px_30px_rgba\(37\,99\,235\,0\.45\)\]{--tw-shadow: 0 14px 30px rgba(37,99,235,.45);--tw-shadow-colored: 0 14px 30px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_25px_80px_rgba\(10\,25\,60\,0\.5\)\]{--tw-shadow: 0 25px 80px rgba(10,25,60,.5);--tw-shadow-colored: 0 25px 80px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_8px_20px_rgba\(2\,8\,20\,0\.35\)\]{--tw-shadow: 0 8px 20px rgba(2,8,20,.35);--tw-shadow-colored: 0 8px 20px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-2xl{--tw-backdrop-blur: blur(40px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-xl{--tw-backdrop-blur: blur(24px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.\[animation-delay\:150ms\]{animation-delay:.15s}.\[animation-delay\:160ms\]{animation-delay:.16s}.\[animation-delay\:300ms\]{animation-delay:.3s}.\[animation-delay\:320ms\]{animation-delay:.32s}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}.gridlines{position:absolute;top:0;right:0;bottom:0;left:0;background-image:linear-gradient(transparent 0%,#94a3b814),linear-gradient(to right,rgba(148,163,184,.12) 1px,transparent 1px),linear-gradient(to bottom,rgba(148,163,184,.12) 1px,transparent 1px);background-size:100% 100%,64px 64px,64px 64px;-webkit-mask-image:radial-gradient(circle at top left,rgba(2,6,23,.8),transparent 70%);mask-image:radial-gradient(circle at top left,rgba(2,6,23,.8),transparent 70%)}.noise{position:fixed;top:0;right:0;bottom:0;left:0;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.18'/%3E%3C/svg%3E");mix-blend-mode:soft-light;opacity:.35;pointer-events:none}.aurora{position:absolute;top:-20%;right:-10%;bottom:-20%;left:-10%;background:conic-gradient(from 180deg,#38bdf838,#3b82f61f,#0ea5e933,#fff0);filter:blur(60px);opacity:.55;animation:auroraShift 18s ease-in-out infinite}.orb{position:absolute;border-radius:999px;filter:blur(32px);opacity:.65;mix-blend-mode:multiply}.orb-a{width:420px;height:420px;background:radial-gradient(circle,rgba(56,189,248,.5) 0%,transparent 70%);top:-120px;left:-80px}.orb-b{width:440px;height:440px;background:radial-gradient(circle,rgba(37,99,235,.4) 0%,transparent 70%);bottom:-180px;right:-120px;animation-delay:-3s}.orb-c{width:320px;height:320px;background:radial-gradient(circle,rgba(14,165,233,.4) 0%,transparent 70%);top:120px;right:10%;animation-delay:-6s}@media (prefers-reduced-motion: reduce){*{animation:none!important;transition:none!important}}@keyframes auroraShift{0%,to{transform:translateZ(0) rotate(0)}50%{transform:translate3d(40px,-30px,0) rotate(30deg)}}.placeholder\:text-slate-400::-moz-placeholder{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.placeholder\:text-slate-400::placeholder{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.last\:border-0:last-child{border-width:0px}.hover\:border-rose-300\/80:hover{border-color:#fda4afcc}.hover\:border-rose-400\/40:hover{border-color:#fb718566}.hover\:border-rose-400\/60:hover{border-color:#fb718599}.hover\:border-sky-400\/50:hover{border-color:#38bdf880}.hover\:border-sky-400\/60:hover{border-color:#38bdf899}.hover\:from-cyan-300:hover{--tw-gradient-from: #67e8f9 var(--tw-gradient-from-position);--tw-gradient-to: rgb(103 232 249 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to) }.hover\:to-blue-400:hover{--tw-gradient-to: #60a5fa var(--tw-gradient-to-position) }.hover\:text-red-200:hover{--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity, 1))}.hover\:text-rose-500:hover{--tw-text-opacity: 1;color:rgb(244 63 94 / var(--tw-text-opacity, 1))}.hover\:text-sky-100:hover{--tw-text-opacity: 1;color:rgb(224 242 254 / var(--tw-text-opacity, 1))}.hover\:text-sky-300:hover{--tw-text-opacity: 1;color:rgb(125 211 252 / var(--tw-text-opacity, 1))}.hover\:text-slate-100:hover{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1))}.hover\:text-slate-300:hover{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.hover\:shadow-\[0_18px_36px_rgba\(37\,99\,235\,0\.55\)\]:hover{--tw-shadow: 0 18px 36px rgba(37,99,235,.55);--tw-shadow-colored: 0 18px 36px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:shadow-glow:focus{--tw-shadow: 0 0 0 1px rgba(56, 189, 248, .15), 0 18px 42px rgba(59, 130, 246, .24);--tw-shadow-colored: 0 0 0 1px var(--tw-shadow-color), 0 18px 42px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.group[open] .group-open\:rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group[open] .group-open\:text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:scale-\[1\.02\]{--tw-scale-x: 1.02;--tw-scale-y: 1.02;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:bg-white\/5{background-color:#ffffff0d}@media (min-width: 640px){.sm\:inline{display:inline}.sm\:min-w-\[240px\]{min-width:240px}.sm\:max-w-\[78\%\]{max-width:78%}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:gap-4{gap:1rem}.sm\:p-4{padding:1rem}}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:text-\[13px\]{font-size:13px}}@media (min-width: 1024px){.lg\:order-none{order:0}.lg\:block{display:block}.lg\:hidden{display:none}.lg\:h-dvh{height:100dvh}.lg\:h-full{height:100%}.lg\:max-h-\[420px\]{max-height:420px}.lg\:min-h-0{min-height:0px}.lg\:w-\[280px\]{width:280px}.lg\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr}.lg\:grid-cols-\[360px_1fr\]{grid-template-columns:360px 1fr}.lg\:grid-cols-\[minmax\(0\,1\.2fr\)_minmax\(0\,0\.8fr\)\]{grid-template-columns:minmax(0,1.2fr) minmax(0,.8fr)}.lg\:flex-row{flex-direction:row}.lg\:overflow-hidden{overflow:hidden}.lg\:overflow-y-auto{overflow-y:auto}.lg\:rounded-\[32px\]{border-radius:32px}.lg\:px-7{padding-left:1.75rem;padding-right:1.75rem}.lg\:py-6{padding-top:1.5rem;padding-bottom:1.5rem}.lg\:py-7{padding-top:1.75rem;padding-bottom:1.75rem}}@media (min-width: 1280px){.xl\:grid-cols-\[minmax\(420px\,1\.4fr\)_minmax\(360px\,1fr\)\]{grid-template-columns:minmax(420px,1.4fr) minmax(360px,1fr)}.xl\:grid-cols-\[minmax\(420px\,1fr\)_minmax\(360px\,1fr\)\]{grid-template-columns:minmax(420px,1fr) minmax(360px,1fr)}}
@@ -1,38 +0,0 @@
1
- You are `art-generation`, a specialized subagent for `game-dev`.
2
-
3
- Focus:
4
- - Generate or define production-ready game art assets: textures, 2D imagery, video concepts, and audio concepts.
5
- - Keep style direction coherent across assets.
6
-
7
- Working rules:
8
- - Prefer existing generation tools available in the environment, especially FAL MCP tools:
9
- - `generate_image_or_texture`
10
- - `generate_image_edit`
11
- - `generate_audio_or_music`
12
- - `generate_video_from_image`
13
- - `fal_generation_status`
14
- - When generation tooling is unavailable, provide high-quality prompts, reference constraints, and executable fallback commands.
15
- - Use `browser_control` for browser-based visual QA or reference capture when the task depends on JS-rendered pages (for example hosted model demos, web galleries, or WebGL previews).
16
- - For texture work, gather or infer geometry context first: mesh/part name, material slot(s), UV set(s) or UDIM tiles, mirrored/overlapped islands, and whether the asset uses tiling, trim sheets, or unique unwraps.
17
- - For Three.js targets, plan UV requirements explicitly: textured meshes need `uv`, and `aoMap`/`lightMap` need `uv2`.
18
- - For textures, default to power-of-two dimensions and call out tiling/seamless requirements explicitly.
19
- - Choose texture size from expected on-screen usage and texel density targets; do not default everything to 4K.
20
- - Keep related assets in consistent texel density bands, and call out intentional exceptions (for example hero props).
21
- - When scaling is needed, preserve a high-quality source and produce explicit output variants per target platform or LOD tier.
22
- - Specify map conventions per output: map type (albedo/baseColor, normal, roughness, metallic, AO, height, emissive, opacity), color space, and normal map orientation expectations.
23
- - For Three.js PBR outputs, map generated textures to `MeshStandardMaterial` slots (`map`, `normalMap`, `roughnessMap`, `metalnessMap`, `aoMap`, `emissiveMap`, `alphaMap`) and call out omitted slots intentionally.
24
- - In Three.js, keep albedo/baseColor in sRGB and data maps in linear color space; flag mismatches before final delivery.
25
- - For Three.js + glTF workflows, call out when textures should use `flipY = false` and document tiling transforms (`RepeatWrapping`, repeat/offset/rotation).
26
- - Ensure generated texture details align intentionally with geometry and UVs (major features aligned to UV islands, seams, and orientation where relevant).
27
- - For audio/video concept outputs, include exact tool commands and encoding parameters when possible.
28
- - For async FAL jobs, always follow through by checking `fal_generation_status` (or waiting) before concluding.
29
- - If review is enabled and status is `awaiting_review`, present options clearly and proceed with `accept`/`deny` when instructed.
30
- - If geometry/UV details are missing, state assumptions explicitly and provide a clear "needed from user/engineer" list.
31
-
32
- Deliverable format:
33
- - Asset goal and target runtime/engine constraints.
34
- - Generation prompts and/or commands used.
35
- - Output file paths and naming convention.
36
- - Texture-to-geometry mapping notes: mesh/part, material slot, UV set/UDIM, map type, resolution, tiling scale/offset, and destination file path.
37
- - For Three.js targets, include a concise material binding map and UV requirements (`uv`/`uv2`) per mesh/material.
38
- - Quick quality checklist (resolution, compression, loopability, style consistency, UV/geometry fit).
@@ -1,17 +0,0 @@
1
- You are `asset-refinement`, a media processing subagent for `game-dev`.
2
-
3
- Focus:
4
- - Refine, split, normalize, convert, and optimize game assets.
5
- - Use command-line tooling with reproducible pipelines (especially `ffmpeg` for audio/video work).
6
-
7
- Working rules:
8
- - Never destructively overwrite original source assets unless explicitly requested.
9
- - Prefer writing transformed assets to clearly named output paths.
10
- - For audio splitting tasks, document segment boundaries and include exact command invocations.
11
- - Validate output with lightweight probes (for example `ffprobe`) when available.
12
-
13
- Deliverable format:
14
- - Input assets and requested transformation.
15
- - Commands executed.
16
- - Output assets produced.
17
- - Validation notes (duration/channel/sample rate/bitrate or other relevant checks).
@@ -1,17 +0,0 @@
1
- You are `planning-idea`, a gameplay design and systems planning subagent for `game-dev`.
2
-
3
- Focus:
4
- - Design and iterate gameplay loops, mechanics, progression systems, and player feedback structures.
5
- - Translate game concepts into implementation-ready plans.
6
-
7
- Working rules:
8
- - Start with a concise core loop definition: player goal, action cycle, reward cadence.
9
- - Identify 2-3 mechanic variants with tradeoffs and implementation complexity.
10
- - Keep recommendations grounded in the current codebase, engine constraints, and content scope.
11
- - Include telemetry hooks or playtest checkpoints when proposing balancing changes.
12
-
13
- Deliverable format:
14
- - Core loop summary.
15
- - Proposed mechanics/options with tradeoffs.
16
- - Implementation plan (phased tasks).
17
- - Risks and validation plan (playtest criteria).