agents/openai.yaml
interface:
display_name: "Three.js AAA Graphics Builder"
short_description: "Upgrade Three.js graphics quality"
default_prompt: "Load threejs-aaa-graphics-builder/SKILL.md (try ~/.codex/skills/threejs-aaa-graphics-builder/SKILL.md, then ~/.claude/skills, ~/.agents/skills, or repo skills/) and follow it exactly, including its reference gates and the external asset sourcing gate. Non-negotiables: for premium asset categories, run the credential probe and load threejs-3d-generator and/or threejs-image-generator before deciding procedural assets are enough, producing real task IDs/output paths or blocker evidence; report the filled visual scorecard with measured evidence; do not claim premium quality while any required reference, evidence item, or scorecard category is missing."
references/checklists/aaa-game-quality-gate.md
# AAA Browser Game Quality Gate
- The game is immediately playable and not presented as a landing page.
- The core loop has objective, scoring/progress, fail/retry, pacing, and feedback.
- Screenshots do not read as a collection of default primitives, debug HUDs, or generic placeholder panels.
- Unadorned boxes, cones, spheres, flat planes, and stretched buildings are not the dominant art language unless explicitly intentional.
- UI is genre-specific, compact, readable during motion, responsive, and includes needed modal states.
- Player, threats, rewards, and objectives have distinct silhouettes and material/feedback language.
- Player/hero asset has primary silhouette, secondary structure, tertiary detail, material contrast, and state feedback.
- Obstacle/enemy set includes at least three authored variants with unique telegraphs.
- Reward/interactable set includes at least two authored variants with collection/interaction feedback.
- World kit includes reusable modules and does not rely on one repeated skyline/block/road primitive.
- The scene has foreground, midground, and background depth instead of one flat play lane.
- Lighting, shadows, fog, and post-processing clarify depth and mood without hiding gameplay.
- Procedural models use the authored factories, shared material kit, reusable prop kits, and collision proxies from `references/implementation-blueprint.md` and `references/technical-art.md`.
- Movement, camera, speed, impact, and restart loop feel tuned through play, not just configured.
- Audio/visual feedback exists for core actions and state transitions.
- Mobile viewport preserves framing, safe areas, touch targets, and text fit.
- Renderer diagnostics from `references/technical-art.md` are reviewed when visual fidelity changes.
- Visual scorecard in `references/visual-scorecard.md` passes: every category at least 2 and average at least 2.3.
- Build, browser run, console/page errors, screenshots, nonblank canvas, interaction, and responsive checks all pass.
- A screenshot critique identifies no unresolved high-impact placeholder-quality blockers.
- If any premium surface was intentionally deferred, the final report says which one and why.
references/checklists/aaa-visual-scorecard.md
# AAA Visual Scorecard Checklist
Use with `threejs-aaa-graphics-builder/references/visual-scorecard.md`.
- Current desktop and mobile active-play screenshots are available.
- Art direction category scored 0-3.
- Hero/player asset category scored 0-3.
- Obstacles/enemies category scored 0-3.
- Rewards/interactables category scored 0-3.
- World/environment category scored 0-3.
- Materials/textures category scored 0-3.
- Lighting/render category scored 0-3.
- VFX/motion category scored 0-3.
- UI/HUD category scored 0-3.
- Performance evidence category scored 0-3.
- No automatic failure is present: check every item in the canonical Automatic Failures list in `threejs-aaa-graphics-builder/references/visual-scorecard.md` (do not rely on a from-memory summary of it).
- Technical-art evidence includes material kit, VFX readability, instancing/LOD/culling decision, DPR/post/shadow tradeoffs, and imported asset diagnostics when generated/imported assets are used.
- Premium gate passes only when every category is at least 2 and average score is at least 2.3.
- Showcase gate passes only when at least six categories are 3, no category is below 2, and average score is at least 2.7.
references/checklists/material-lighting-quality.md
# Material and Lighting Quality Checklist
Gate the lighting/material recipes in `references/render-recipes.md` and the material kit in `references/technical-art.md`.
- Renderer color space, tone mapping, exposure, and shadow settings are intentional.
- Key, fill, rim, ambient, and environment lighting follow the lighting stack in `references/render-recipes.md` and clarify depth and gameplay roles.
- Materials avoid flat default looks through roughness/metalness/emissive/vertex-color variation.
- Important objects have readable silhouettes against background, fog, and effects.
- Shadows help ground assets without obscuring navigation or collision boundaries.
- Fog, bloom, particles, and post-processing support readability instead of hiding it.
- Procedural textures or decals are scaled, stable, and not visually noisy during movement.
- Materials reuse the shared kit in `references/technical-art.md` where possible and are disposed when obsolete.
- Desktop and mobile screenshots are checked after lighting/material changes.
- Renderer info or frame-time evidence is gathered when render cost changes.
references/checklists/performance-safe-visual-detail.md
# Performance-Safe Visual Detail Checklist
Gate the render budget and instancing/LOD guidance in `references/technical-art.md`.
- Baseline renderer info is captured when increasing fidelity.
- Draw calls, triangles, geometries, materials, textures, and frame time are reviewed against the render budget in `references/technical-art.md` after changes.
- Repeated details use the instancing/LOD approach in `references/technical-art.md`: instancing, shared resources, atlases, or generated texture reuse where practical.
- High segment counts are limited to silhouette-critical forms.
- Shadows are scoped by light count, shadow map size, casters/receivers, and camera distance.
- Post-processing is justified by gameplay readability or strong art direction.
- DPR caps or adaptive quality are considered for mobile.
- Generated resources have a disposal/reuse strategy.
- The worst-case gameplay scene, not only idle view, is inspected.
- Visual detail remains readable at mobile resolution without excessive GPU cost.
references/checklists/procedural-model-quality.md
# Procedural Model Quality Checklist
Gate the procedural modeling guidance in `references/model-recipes.md` and the material kit in `references/technical-art.md`.
- The model has a recognizable silhouette from the gameplay camera.
- Primary forms read clearly before material or post-processing detail.
- Secondary detail supports the asset role: panels, trims, ridges, tubes, fins, sockets, decals, or emissive accents.
- Tertiary detail is visible at intended camera distance and does not create noise.
- Materials use the kit in `references/technical-art.md` with purposeful contrast in roughness, metalness, color, emissive, or texture.
- Bevels, curves, and segment counts improve silhouette or highlight behavior.
- Repeated props use shared geometries/materials, instancing, or pools when practical.
- Visual mesh and gameplay collision/proxy are intentionally separated when needed.
- The factory returns named groups/meshes and keeps ownership/disposal clear.
- Renderer diagnostics from `references/technical-art.md` are checked when triangles, materials, textures, or draw calls increase.
- Mobile screenshot still shows the asset as more than a primitive placeholder.
references/checklists/technical-art-quality.md
# Technical Art Quality Checklist
Use before claiming premium, AAA, showcase, high-fidelity, or less-basic visual quality after graphics changes. Each item gates the guidance in `references/technical-art.md`.
- Technical art brief converts art direction into shapes, material roles, lighting, VFX, camera, UI/world motifs, and budgets.
- Hero surfaces and support surfaces are identified separately.
- Material kit uses the named shared roles from `references/technical-art.md`, not scattered one-off colors/materials.
- Shader/post-processing choices have player-facing purpose and measured or bounded cost.
- VFX follow the event-driven language in `references/technical-art.md`: readable, short-lived, and not hiding collision, threats, rewards, or UI.
- Instancing is used for large repeated same-geometry/same-material detail where appropriate.
- LOD, culling, or simplified far variants are planned for heavy background/imported assets.
- Imported/generated models have scale, pivot/orientation, bounds, file size, triangle/material/texture counts when available, and collision proxies checked.
- Decals/trim/detail systems reinforce function, route, faction, scale, or state.
- Threats, rewards, interactables, and player state are not communicated by color alone.
- DPR cap, shadow settings, post-processing passes, and mobile tradeoffs are reported.
- Renderer diagnostics match the render budget reporting in `references/technical-art.md`: calls, triangles, geometries, textures, and material count when available.
- Final visual scorecard performance evidence category includes budget and technical-art evidence, not only screenshots.
references/implementation-blueprint.md
# AAA Graphics Implementation Blueprint
Use this when a Three.js game reads as basic even after it is playable. The goal is a production graphics architecture that can be iterated, scored, profiled, and reused. For premium/AAA/showcase work, also load `references/technical-art.md` and treat the technical art brief and budget as part of the graphics architecture.
## Recommended Ownership
```text
src/assets/MaterialLibrary.ts
src/assets/ProceduralTextures.ts
src/assets/DecalShapes.ts
src/assets/ModelDiagnostics.ts
src/assets/ImportedAssetRegistry.ts
src/assets/modelFactories/HeroFactory.ts
src/assets/modelFactories/ObstacleFactory.ts
src/assets/modelFactories/RewardFactory.ts
src/assets/modelFactories/WorldPropKit.ts
src/systems/LightingRig.ts
src/systems/RenderPipeline.ts
src/systems/VfxSystem.ts
src/systems/WorldArtDirector.ts
src/systems/QualityDiagnostics.ts
```
Keep these boundaries lightweight. In small projects, a single file can contain multiple factories, but the concepts must remain separate: materials, authored geometry, repeated props, effects, render settings, and diagnostics.
## Hybrid AI Asset Pipeline
Choose the asset path per surface:
- Procedural Three.js: repeated detail, simple props, rails, track parts, decals, collision proxies, VFX geometry, debug-friendly primitives.
- `threejs-image-generator`: concept sheets, T-pose/A-pose references, texture references, trim sheets, decals, icons, logos, skies, backgrounds, UI art.
- `threejs-3d-generator`: hero/player, characters, creatures, vehicles, buildings, weapons, signature props, pickups, bosses, complex terrain modules.
- Hybrid: image-generator concept/reference -> 3D-generator image-to-model -> Three.js import -> procedural collision/VFX/prop kit -> visual scorecard.
For premium/AAA/showcase/high-fidelity/less-basic games, do not decide `threejs-3d-generator` or `threejs-image-generator` is unnecessary before loading the relevant skill when the game includes characters, creatures, vehicles, ships, weapons, buildings, signature props, hero pickups, skies, textures, decals, logos, icons, or GUI art. Load first, run the credential probe, then document the tradeoff.
Use `threejs-3d-generator` when generated model fidelity will materially improve the active screenshot. Do not use generated 3D for every repeated small prop; use instancing/procedural kits for volume.
For premium hero surfaces, procedural-only is not a valid final choice unless a real blocker is recorded: missing key from the credential probe, API/network/quota error after an attempted command, user requested no external assets, or offline-only constraint. Repeated low-value props can stay procedural.
Fill the external asset sourcing ledger before the graphics phase using the canonical template in `threejs-game-director/references/phase-playbook.md` (Ledger Templates). It records the credential probe output, the chosen source per surface (procedural / `threejs-image-generator` / `threejs-3d-generator` / hybrid), and the generated outputs or allowed blocker for each surface.
## Production Surfaces
A premium pass must touch every weak visible surface:
- Hero/player: authored silhouette, state feedback, decals/trim, readable front/up/side, collision proxy.
- Hazards/enemies: at least three distinct silhouettes with telegraphs and material cues.
- Rewards/interactables: at least two forms with collection states and motion/VFX hooks.
- World kit: foreground, playable lane/arena, midground, background/parallax, set dressing, scale cues.
- Materials/textures: shared PBR/stylized material library, procedural panel lines, noise, trim, wear, emissive masks.
- Lighting/render: color space, tone mapping, exposure, shadows/contact, fog/depth, post-processing discipline.
- VFX/motion: event-driven bursts, trails, impact rings, speed lines, shield/boost states, pickup/fail feedback.
- UI/world cohesion: UI colors, icons, alerts, and meters echo gameplay materials and status colors.
- Diagnostics: renderer counts, material/geometry/texture counts, screenshots, scorecard.
For imported generated 3D assets, also require downloaded GLB/PBR output, import wrappers with scale/pivot/bounds, simple collision proxies, animation clips when relevant, and triangle/material/texture/file-size diagnostics.
## Technical Art Contract
Before broad implementation, write the technical art brief and render budget from `references/technical-art.md`: hero vs support surfaces, render budget target, material kit roles, shader/VFX purpose, instancing/LOD/culling plan, and imported asset cleanup. Treat that brief as part of this graphics architecture.
Do not add costly effects until this contract exists. A technical-art pass should make the scene more authored and more measurable at the same time.
## Material Library
Implement the named material-role kit defined in `references/technical-art.md` (`bodyPrimary`, `bodySecondary`, `trim`, `hazard`, `reward`, `glass`, `emissiveSignal`, `groundContact`, `decalDark`/`decalLight`, plus shared UI/world signal colors) in `src/assets/MaterialLibrary.ts`. Create named roles instead of one-off colors and share materials across repeated meshes.
## Procedural Texture And Decal Kit
Use canvas textures, shape geometry, or thin offset meshes for detail that would otherwise require external assets:
- Panel lines and access hatches.
- Trim sheets and edge bands.
- Window strips, city light grids, arena markings.
- Hazard stripes, arrows, target indicators, lane glyphs.
- Scratches, wear, noise, dirt, heat tint, scorch marks.
- UI/world icon motifs reused in HUD and diegetic markers.
Set texture filtering, mipmaps, repeat/wrap, color space, and anisotropy intentionally. Avoid unique full-size textures for tiny repeated marks.
Use `threejs-image-generator` for high-value 2D source art: terrain/rock/asphalt/snow/moss texture references, sci-fi trim sheets, signs, hazard stripes, cockpit decals, sky/background plates, menu/loading art, faction logos, pickup icons, ability icons, and GUI glyphs. Use the resulting images either as actual 2D assets or as image-to-3D inputs.
## Model Factories
Factories should return a grouped object plus metadata:
```ts
type ModelFactoryResult = {
root: THREE.Group;
collision?: THREE.Object3D;
lod?: THREE.LOD;
bounds?: THREE.Box3;
diagnostics?: {
meshes: number;
materials: number;
geometries: number;
triangles?: number;
};
};
```
Use named child meshes for readable debugging. Separate visual detail from collision proxies. Keep repeated detail instanced where practical.
For imported generated 3D models, create an `ImportedAssetRegistry` or loader wrapper that returns similar metadata: root group, bounds, collision proxy, animation clips, and diagnostics. Never put 3D/image/audio generation API calls in browser runtime code.
## World Art Director
Build the world as layers:
- Play layer: ground, lanes, rails, objective path, hazards, pickups.
- Near layer: speed props, signs, arches, barriers, debris, foreground occluders used carefully.
- Mid layer: buildings, cliffs, hangars, pillars, platforms, arena machinery.
- Far layer: skyline, terrain silhouettes, nebula/cloud/fog cards, parallax planes.
- Motion layer: speed lines, particles, trail strips, dust, sparks, screen-space UI feedback.
Every layer should support gameplay readability. Do not obscure threats or the next decision.
## Render Pipeline
Own renderer setup in one place:
- `outputColorSpace = THREE.SRGBColorSpace`.
- Tone mapping and exposure selected for the art direction.
- DPR capped for mobile and high-density displays.
- Shadows enabled only for objects that benefit from grounding.
- Post-processing is limited and measured: bloom, vignette, chromatic aberration, film grain, or color grade only when they improve authored forms.
- Resize updates canvas, renderer, camera, composer, and UI CSS variables.
## VFX System
Implement the event-driven VFX language from `references/technical-art.md` in `src/systems/VfxSystem.ts`. Effects should be pooled, readable, and tied to state; they must clarify state instead of adding permanent particle clutter.
## Diagnostics
Own diagnostics in `src/systems/QualityDiagnostics.ts`. Report the renderer diagnostics defined in `references/technical-art.md` (calls, triangles, geometries, textures, material count, DPR/post/shadow settings), plus these architecture-specific counts:
- Scene mesh count, instanced mesh count, unique materials/geometries/textures.
- Approximate visible prop counts by layer.
- Screenshot paths and visual scorecard.
- Performance notes after post-processing, shadows, or many repeated props.
## Browser Game Budgets
Use the render budget starting points and instancing/LOD/culling guidance in `references/technical-art.md`, then measure on the target game after every major graphics pass.
## Implementation Order
1. Score active screenshots and identify the weakest three categories.
2. Add material and diagnostic foundations.
3. Decide which weak surfaces need procedural, `threejs-image-generator`, `threejs-3d-generator`, or hybrid treatment.
4. Build/import hero/player and one complete obstacle/reward family.
5. Add world prop kit and layered composition.
6. Add lighting/render polish.
7. Add event-driven VFX.
8. Re-score desktop/mobile active screenshots.
9. Optimize measured bottlenecks.
references/model-recipes.md
# Procedural Model Recipes
These recipes are for scratch-built Three.js models when external art assets are unavailable. The goal is not photorealism; it is authored, layered, readable, premium browser-game art.
## Modeling Principles
- Start with silhouette. A model should be recognizable as a dark shape before materials or glow.
- Combine primitive bases with authored geometry: extrusions, bevels, curves, tubes, lathes, custom buffers, decals, trim, and instanced micro-detail.
- Use asymmetry and functional parts: hinges, fins, vents, handles, rails, brackets, sensors, cables, panels, bolts.
- Put detail where the camera sees it. Spend triangles on player-facing surfaces, not hidden undersides.
- Create state variants through material swaps, animated child parts, emissive strips, and VFX sockets.
- Keep a simple collision proxy separate from the detailed visual group.
- Use shared geometries/materials and instancing for repeated bolts, panels, lights, windows, spikes, rocks, or rail segments.
- Name important child meshes: `cockpitGlass`, `leftEngine`, `hazardTeeth`, `pickupCore`, `collisionProxy`.
## Minimum Premium Asset Pass
For a game that asks for premium/AAA/showcase quality, build at least:
- One hero/player model with readable front/up/side and three state cues.
- Three obstacle/enemy variants with unique silhouettes and telegraphs.
- Two reward/interactable variants with idle and collect states.
- One world prop kit with at least eight reusable parts.
- One material kit with trim, decals, panel lines, and emissive masks.
- Collision proxies and renderer diagnostics for the above.
## Hero Vehicle Recipe
Use for runners, racers, hovercraft, spaceships, drones, or arcade vehicles.
- Core hull: `ExtrudeGeometry` or custom tapered `BufferGeometry`, not just a box.
- Nose/front: wedge, intake, sensor strip, bumper, or blade shape.
- Cockpit/core: glass dome from sphere/lathe segments, beveled capsule, or faceted canopy.
- Engines: cylinders/cones/tubes with nozzle rings, inner emissive discs, heat fins, and trail sockets.
- Wings/fins: extruded triangular or curved plates with bevel/trim lines.
- Undercarriage: skids, landing pads, rail clamps, suspension arms, or thruster pods.
- Decals: panel lines, numeric marks, faction glyph, hazard ticks, small bolts.
- State cues: boost flares, shield shell, damage scorch, pickup glow, overheat red.
- Collision proxy: one capsule/box/sphere group matching gameplay footprint.
Reject if the hero is mostly a box with two cylinders and a glow.
## Hero Character Recipe
Use for arena fighters, brawlers, platformers, or stylized third-person games.
- Body mass: torso, pelvis, head/helmet, limbs with tapered capsule/cylinder custom scales.
- Rig illusion: separate shoulders, elbows, knees, wrists, ankles, belt, backpack, armor plates.
- Face/identity: visor, mask, hair/helmet crest, color-blocked silhouette, weapon/tool.
- Animation-ready pivots: group limbs under named joints even if animation is procedural.
- Material zones: skin/fabric/armor/metal/glass/emissive accents.
- State cues: hit flash material, shield ring, attack trail socket, stamina/charge glow.
- Collision proxy: capsule or cylinder independent of mesh detail.
Reject if the character reads as stacked spheres/cylinders with no costume, joints, or silhouette.
## Obstacle And Enemy Families
Build distinct gameplay reads:
- Low barrier: ground-hugging slab, spikes, rails, caution panels, animated warning light.
- Gate/arch: overhead frame, side posts, pulsing pass/avoid lane, moving shutters.
- Moving hazard: rotating arm, sweeper beam, drone, crusher, sliding block, orbiting mines.
- Trap/zone: laser grid, electric puddle, collapsing tile, gravity well, proximity mine.
- Enemy: body core, sensor/head, weapon, shield, locomotion/hover base, attack telegraph.
Each variant needs:
- Unique silhouette.
- Material cue for danger.
- Telegraph from distance.
- Animation or state change.
- Collision proxy.
- Low-cost repeated detail.
Reject if all hazards are recolored cubes/cones.
## Reward And Interactable Recipes
Rewards should be readable and desirable during motion.
- Token: outer ring, inner core, value icon, shimmer cards, collect burst socket.
- Shard: faceted crystal, metal bracket, orbiting chips, emissive seam.
- Capsule: glass shell, suspended item, end caps, rotating label strip.
- Power-up: icon silhouette matched to effect, color and shape differ from score pickups.
- Objective item: larger scale, unique motion, UI echo, stronger lighting/VFX.
States:
- Idle: slow rotation, pulse, bob, or orbit.
- Attract: line/trail toward player.
- Collect: vanish, burst, score trail, HUD meter update.
Reject if rewards are plain spheres or torus rings without state feedback.
## World Prop Kit
Build modular props that can be instanced and recombined:
- Track/road: lane plates, seams, arrows, side rails, guard segments, repair panels.
- Arena: boundary rings, floor tiles, spawn pads, cover blocks, goal markers.
- City/sci-fi: window strips, antennas, rooftop units, bridge trusses, pylons, billboards.
- Nature: rocks from custom faceted buffers, cliffs, roots, crystals, grasses as cards.
- Industrial: pipes, vents, cables, tanks, crates, gantries, lights, warning signs.
- Space/air: debris panels, satellites, buoys, asteroid chunks, parallax dust.
Layer the kit:
- Near props create speed and scale.
- Mid props define the playable corridor.
- Far props create depth without stealing draw calls.
Reject if the world is mostly stretched boxes or a flat plane.
## Procedural Geometry Techniques
- `ExtrudeGeometry`: panels, fins, wings, badges, UI/world glyphs, signs.
- `LatheGeometry`: capsules, domes, engines, pipes, bottles, turret bases.
- `TubeGeometry`: cables, rails, trails, conduits, curved weapons.
- Custom `BufferGeometry`: tapered hulls, rocks, shards, wedges, low-poly terrain.
- `ShapeGeometry`: decals, flat icons, trim strips, hazard markers.
- `InstancedMesh`: windows, bolts, lane markers, debris, grass, lights, small props.
- `LOD`: hero/background variants and dense prop reductions.
Use bevel-like layering when real bevel geometry is too expensive: duplicate thin trim meshes, edge strips, or slightly offset darker panels.
## Material And Detail Rules
- Use roughness/metalness contrast, not only hue contrast.
- Use emissive for authored signals, not entire objects.
- Use glass/clearcoat sparingly on hero details.
- Add darker contact material under important objects.
- Use decals to imply scale and function.
- Reuse UI icon shapes as world decals for cohesion.
## Diagnostics Checklist
After a model pass, report:
- Mesh count.
- Instanced mesh count.
- Unique geometries/materials/textures.
- Approximate triangle count if available.
- Collision proxies included.
- LOD or culling strategy for repeated/background props.
- Active-play screenshots, not only showroom renders.
references/prompt-templates.md
# Three.js AAA Graphics Prompt Templates
Reusable prompt templates packaged with this skill. Use only templates relevant to the current request, and adapt placeholders to the game/project context.
---
# AAA Graphics Production Pass Prompt
Use `threejs-aaa-graphics-builder` to upgrade this Three.js game from basic prototype visuals to premium browser-game graphics.
Current screenshot blockers:
-
Target art direction:
-
Required pass:
- Score current screenshots with `threejs-aaa-graphics-builder/references/visual-scorecard.md`.
- Add or improve the graphics architecture from `references/implementation-blueprint.md`.
- Add the technical art brief from `references/technical-art.md`: material kit, shader/VFX purpose, instancing/LOD/culling, imported asset cleanup, renderer budget, mobile tradeoffs.
- Build material library, procedural texture/decal helpers, model factories, world prop kit, VFX system, lighting/render pipeline, and diagnostics.
- Use `threejs-3d-generator` for high-value hero/player, character, creature, vehicle, building, weapon, pickup, boss, rigging, animation, texture, or conversion needs when procedural code is not enough.
- Use `threejs-image-generator` for 2D concepts, T-pose/A-pose references, texture references, decals, logos, icons, GUI art, skies, backgrounds, or image-to-3D inputs.
- Upgrade hero/player, obstacles/enemies, rewards/interactables, world kit, HUD cohesion, lighting, effects, and renderer metrics.
Do not count as completion:
- Recolored boxes/cones/spheres.
- Glow, fog, or darkness hiding missing detail.
- One improved object while world/obstacles/UI remain placeholders.
- Idle/showroom screenshots only.
- Missing renderer diagnostics after visual density changes.
Verification:
- Capture active gameplay desktop and mobile screenshots.
- Report visual score before/after.
- Report draw calls, triangles, geometries, textures, material count, DPR cap, shadow/post settings, and instancing/LOD/culling decisions when available.
- Run build, browser, console/page error, nonblank canvas, interaction, and responsive checks.
- Continue until every scorecard category is at least 2, or report exactly why the target was not reached.
---
# Before/After Visual Critique Prompt
Use `threejs-aaa-graphics-builder` to critique this Three.js game's current screenshots with the visual scorecard and produce a prioritized graphics plan.
Evidence to gather:
- Desktop screenshot.
- Mobile screenshot.
- Optional before/after screenshots if a pass was already completed.
- Renderer diagnostics if available.
- Notes on the game genre, core verb, and target mood.
Critique dimensions:
- Gameplay readability.
- UI hierarchy and text fit.
- Procedural model silhouette and fidelity.
- Material, lighting, shadows, color, and contrast.
- Camera composition and motion clarity.
- Mobile framing and touch/control readability.
- Performance risk from proposed upgrades.
Output:
- Pass/fail on whether the game looks polished enough for the current milestone.
- Top five blockers ordered by player impact.
- Recommended next skill/phase: `threejs-aaa-graphics-builder`, `threejs-game-ui-designer`, `threejs-debug-profiler`, or `threejs-qa-release`.
- Concrete acceptance criteria for the next pass.
---
# Material, Lighting, and Render Quality Pass Prompt
Use `threejs-aaa-graphics-builder` for scene-level render quality, material libraries, model materials, geometry factories, and visual scoring.
Current problem:
-
Target look:
-
Work areas:
- Renderer color space, tone mapping, exposure, shadow settings, DPR cap.
- Key/fill/rim/environment lighting.
- Material roughness, metalness, emissive accents, vertex colors, generated textures, and decals.
- Fog, background, post-processing, and feedback effects only where they improve readability.
- Camera composition and gameplay-distance readability.
Constraints:
- Improve lighting and materials before adding heavy post-processing.
- Keep threats, pickups, player, and objective readable during motion.
- Avoid excessive bloom, low-contrast fog, and particle clutter.
- Re-measure renderer info if visual complexity changes.
Verification:
- Capture desktop and mobile screenshots.
- Check console/page errors and nonblank canvas pixels.
- Compare renderer calls/triangles/textures before and after when practical.
- Play the core loop and confirm effects do not hide gameplay information.
---
# Technical Art Pass Prompt
Use `threejs-aaa-graphics-builder` for a technical-art pass on this Three.js game.
Current visual/performance risk:
-
Target art direction:
-
Required pass:
- Load `references/technical-art.md`.
- Write a technical art brief: hero surfaces, support surfaces, material kit, VFX language, lighting stack, render budget, asset strategy, mobile constraint.
- Convert art direction into renderable systems: materials, decals/trim, shaders, VFX, LOD, instancing, culling, imported asset cleanup.
- Make threats, rewards, player state, and objectives readable by shape/motion/value, not color alone.
- Keep API/generated asset calls out of browser runtime.
Verification:
- Capture active desktop and mobile screenshots.
- Report renderer diagnostics: calls, triangles, geometries, textures, material count when available, DPR cap, shadow/post settings.
- Report imported/generated asset diagnostics when relevant: file size, bounds, scale, orientation, collision proxy, triangles/materials/textures/clips when available.
- Report VFX readability: trigger, duration, player-facing meaning, and reduced-motion concern if applicable.
- State what was optimized, what was intentionally left rich, and remaining performance risks.
---
# Procedural Hero Asset Pass Prompt
Use `threejs-aaa-graphics-builder` to create or upgrade a high-fidelity scratch-built Three.js hero asset.
Asset brief:
- Role:
- Silhouette:
- Scale:
- Camera distance:
- Style references:
- Performance budget:
Requirements:
- Build a reusable model factory that returns a named `THREE.Group`.
- Establish a recognizable silhouette before adding small detail.
- Add secondary and tertiary detail through bevels, trims, panels, ridges, tubes, decals, emissive elements, and material contrast.
- Add visible subassemblies, not just a few primitives: shell/body, core/cockpit, trims/rails, engines/emitters, decals/surface marks, and state feedback when relevant.
- Use shared geometries/materials where possible.
- Use PBR-style materials, shadows, color management, and lighting intentionally.
- Keep collision or gameplay proxies simpler than the visual mesh.
Avoid:
- Placeholder stacks of primitives.
- Detail visible only from a showroom camera.
- Excessive segment counts, unique materials, or draw calls without gameplay value.
- Glow-only upgrades that leave the silhouette primitive.
Verification:
- Build and run locally.
- Capture gameplay-camera screenshot and one inspection screenshot if useful.
- Report renderer info before/after when available.
- Verify the asset reads clearly at desktop and mobile gameplay distances.
---
# Visual Polish Prompt
Use `threejs-aaa-graphics-builder` to improve the game's visual clarity and identity.
Use focused prompts instead when the main problem is narrower:
- Use `threejs-game-ui-designer/references/prompt-templates.md` for HUD/menu/interface quality prompts.
- Use the procedural hero asset or world prop kit sections in this file for scratch-built model fidelity inside the AAA graphics phase.
- Use the before/after visual critique section in this file when priorities are unclear.
Target feel:
-
Constraints:
- Keep the game readable during motion.
- Avoid generic purple gradients, excessive bloom, particle clutter, and static showroom composition.
- Prefer purposeful lighting, color contrast, silhouettes, material variation, and procedural geometry that supports gameplay.
- Hand off substantial UI craft to `threejs-game-ui-designer`; keep model/world/render construction under `threejs-aaa-graphics-builder`.
- Keep performance visible while polishing.
Verification:
- Capture before/after screenshots where possible.
- Check desktop and mobile framing.
- Confirm the game remains interactive and no console errors were introduced.
---
# World Prop Detail Kit Pass Prompt
Use `threejs-aaa-graphics-builder` to create a reusable procedural prop/detail kit for this Three.js game's world.
World role:
-
Kit requirements:
- Define 4-8 reusable prop factories with shared materials.
- Include scale variants, color/material variants, and clear placement rules.
- Use instancing or shared geometry/materials for repeated details.
- Add visual detail that supports navigation, danger, reward, or atmosphere.
- Keep the kit coherent with the existing game UI and world lighting.
- For city/runner worlds, include skyline modules with setbacks/window bands/roof details, foreground speed props, track hardware, signage/cables/supports, and distant parallax layers.
Performance constraints:
- Avoid unique material explosions.
- Keep repeated props instanced or pooled when practical.
- Track draw calls, triangles, geometries, textures, and frame impact.
Verification:
- Capture before/after screenshots from gameplay camera.
- Check desktop and mobile readability.
- Report renderer diagnostics.
- Confirm no console/page errors and no obvious collision/occlusion issues.
- If the world is still dominated by stretched boxes, continue the prop-kit pass.
---
# Fresh-Eyes Scorecard Review Prompt
Use for the independent review pass required by `references/visual-scorecard.md` for premium/AAA/showcase claims. Give the reviewer ONLY the inputs below — no build history, no prior scores, no description of the work performed.
Inputs:
- The COMPLETE screenshot capture set — every captured state, desktop and mobile, never a hand-picked subset: <paths>
- Scorecard rubric: `threejs-aaa-graphics-builder/references/visual-scorecard.md`
- Calibration anchors: `threejs-aaa-graphics-builder/assets/scorecard-anchors/`
- Inspector metrics JSON: <paths>
Task:
- Score all ten scorecard categories from the screenshots alone, using the 0-3 anchors and calibration images.
- Cross-check scores against the metrics (colorEntropyBits, edgeDensity, luminance.contrast, dominantColorShare, renderBudget) and flag any score the numbers contradict.
- List every automatic failure you can see in the screenshots.
- Do not give benefit of the doubt: if a surface could be a 1 or a 2, score it 1 and say what visible change would earn the 2.
Report:
- Ten category scores with one-sentence visual evidence each.
- Automatic failures observed.
- The three highest-impact changes to raise the lowest scores.
references/render-recipes.md
# Render, Lighting, And VFX Recipes
Use this after authored forms exist. Rendering polish cannot compensate for missing models, props, or readable gameplay silhouettes.
## Renderer Setup
- Set `renderer.outputColorSpace = THREE.SRGBColorSpace`.
- Choose tone mapping deliberately. `ACESFilmicToneMapping` often works for cinematic stylized scenes; simpler tone mapping can be better for bright arcade readability.
- Tune exposure against active gameplay, not a static title view.
- Cap DPR, especially on mobile. Start around `Math.min(devicePixelRatio, 1.5 or 2)` and profile.
- Update renderer, camera, composer, and CSS UI dimensions on resize.
- Use a transparent or explicit background only when composition requires it.
## Camera Composition
- Keep the next decision visible. The camera should show player, immediate threat/reward, and route.
- Add depth layers: foreground speed elements, playable midground, background scale cues.
- Use FOV and camera distance to communicate speed without hiding hazards.
- Use camera shake sparingly and clamp intensity.
- Add camera impulses for hits/near misses/boosts, then ease back quickly.
- Check mobile framing separately; vertical and narrow layouts often need different offsets.
## Lighting Stack
Use a small readable stack:
- Key light: defines form and direction.
- Fill light: keeps gameplay objects legible.
- Rim/back light: separates player and hazards from background.
- Practical/emissive lights: authored beacons, engines, pickups, arena markers.
- Contact shadows or shadow blobs: ground important objects.
Avoid many unmeasured dynamic lights. Prefer baked-looking material/emissive cues, light cards, or small unlit decals for repeated signals.
## Shadows And Contact
- Use shadows for hero/player, major hazards, and large world anchors.
- Use smaller shadow maps and limited shadow casters when profiling shows cost.
- Add cheap contact discs or transparent planes for pickups/hovering objects.
- Tune bias to avoid acne and peter-panning.
- Do not let shadows hide collision reads.
## Materials
Define material roles with the material kit in `references/technical-art.md` (`MeshStandardMaterial` for most surfaces, `MeshPhysicalMaterial` only where the premium feature is visible). At render time:
- Prefer material contrast before post effects: matte vs glossy, metal vs plastic, transparent vs opaque, bright trim vs dark contact.
- Use emissive maps or small emissive parts for signals instead of making entire objects glow.
- Keep material roles matched across UI and world: danger, reward, shield, boost, objective.
## Fog, Background, And Depth
- Fog should reveal depth and mood, not hide empty worlds.
- Layer background silhouettes at varied scales and heights.
- Add parallax or slow-moving far layers for motion-heavy games.
- Avoid single flat sky colors when the world needs scale; use gradients only as support, not the whole art direction.
- Keep hazards/rewards readable against fog and background values.
## Post-Processing
Use post as a finishing pass:
- Bloom: only authored emissive elements, not all bright materials.
- Vignette: subtle focus, never heavy darkness.
- Film grain/noise: low opacity; avoid compression-like artifacts.
- Chromatic aberration: only brief event-driven impacts or very subtle style.
- Motion blur/trails: prefer geometry trails or particles that preserve gameplay clarity.
Always compare screenshots with post enabled/disabled and profile the cost.
## Event-Driven VFX
Tie effects to state using the event-driven VFX language in `references/technical-art.md` (pickup, hit/fail, boost/speed, near miss/combo, shield/invulnerable, spawn/despawn). Pool effects, reuse geometries/materials, and keep permanent particle fields cheap and sparse.
## Readability Checks
During active play, confirm:
- Player orientation is clear.
- Threats differ from rewards by both shape and material.
- Important pickups are visible before reaction time expires.
- UI feedback does not cover the play path.
- VFX clarifies state instead of obscuring collisions.
- Background contrast does not swallow dark objects.
## Performance Checks
After render changes, report the renderer diagnostics from `references/technical-art.md` (calls, triangles, geometries, textures, materials, DPR/post/shadow settings), plus FPS/frame time and composer/post pass count when available.
If performance drops, reduce post/shadow cost first, then cull/LOD/instance, then reduce asset density only where it is least visible.
references/shader-cookbook.md
# Shader And Material Cookbook
Concrete material, shader, and post-processing recipes. Use with `references/technical-art.md` (budgets, when shader work is justified) and `references/render-recipes.md` (render pipeline).
Targets three.js `^0.184`; imports use the `three/addons/*` alias (maps to `examples/jsm`). Every entry lists **When**, **Cost** (draw calls / fill rate / compile), and **Read** (the rule: effects clarify gameplay, never hide missing geometry).
## Prerequisite: Renderer And Environment Map
Metals and glossy dielectrics read as flat gray without an environment map to reflect. Set this up once before PBR materials.
```ts
import * as THREE from 'three';
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping; // simpler tone mapping for bright arcade reads
renderer.toneMappingExposure = 1.0;
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
// 5-line env map: neutral studio IBL, no HDR file needed.
const pmrem = new THREE.PMREMGenerator(renderer);
scene.environment = pmrem.fromScene(new RoomEnvironment(), 0.04).texture; // r184: RoomEnvironment() takes no args
scene.environmentIntensity = 1.0; // r184 global multiplier over per-material envMapIntensity
pmrem.dispose();
```
Needed by any scene with metal, ceramic, glass, or clearcoat. Cost is one PMREM bake at startup, near-zero per frame; it lights support surfaces so hero emissive/trim still wins attention.
## PBR Material Recipes
Copy the config; tune `color` to the palette. `envMapIntensity` values assume the env map above. Use `MeshStandardMaterial` unless a `MeshPhysicalMaterial`-only feature (clearcoat, transmission, sheen) is visible during play.
```ts
// Painted metal (car body, ship hull panel) — dielectric paint over metal read via clearcoat.
new THREE.MeshPhysicalMaterial({ color: 0x1f6feb, metalness: 0.0, roughness: 0.5,
clearcoat: 0.9, clearcoatRoughness: 0.15, envMapIntensity: 1.0 });
// Bare brushed metal (raw steel, gun frame) — needs the env map to look metallic.
new THREE.MeshStandardMaterial({ color: 0xaeb4bd, metalness: 1.0, roughness: 0.4, envMapIntensity: 1.1 });
// Rubber / tire — near-black, no reflection, kills the env map.
new THREE.MeshStandardMaterial({ color: 0x0a0a0b, metalness: 0.0, roughness: 0.92, envMapIntensity: 0.35 });
// Matte plastic (housings, crates) — dielectric, mid roughness, muted reflection.
new THREE.MeshStandardMaterial({ color: 0xd23b3b, metalness: 0.0, roughness: 0.62, envMapIntensity: 0.6 });
// Glossy ceramic / clean hull — sharp reflection, add clearcoat for wet-look premium.
new THREE.MeshPhysicalMaterial({ color: 0xf5f5f5, metalness: 0.0, roughness: 0.12,
clearcoat: 1.0, clearcoatRoughness: 0.05, envMapIntensity: 1.0 });
// Emissive signal (beacon, pickup core) — dark base so only the glow reads; >1 intensity feeds bloom.
new THREE.MeshStandardMaterial({ color: 0x101010, emissive: 0x18e0ff, emissiveIntensity: 2.5,
metalness: 0.0, roughness: 0.4 });
// Cloth / fabric — high roughness + sheen for the soft edge highlight.
new THREE.MeshPhysicalMaterial({ color: 0x3a4a6b, metalness: 0.0, roughness: 0.9,
sheen: 1.0, sheenRoughness: 0.5, sheenColor: new THREE.Color(0x8899bb), envMapIntensity: 0.5 });
```
**Read:** separate roles by roughness/metalness contrast (matte vs glossy, metal vs plastic), not hue alone.
### Glass: real vs fake
```ts
// REAL refractive glass — MeshPhysicalMaterial transmission.
new THREE.MeshPhysicalMaterial({ metalness: 0.0, roughness: 0.05, transmission: 1.0,
thickness: 0.5, ior: 1.5, envMapIntensity: 1.0 });
```
- **When:** one or two hero surfaces (cockpit canopy, potion vial) at close range.
- **Cost:** high. Each transmissive material triggers an extra scene render into a transmission buffer every frame; fill-rate heavy and multiplies with resolution. Never use on repeated/instanced props.
- **Read:** refraction must not smear the hazard behind it into unreadability.
```ts
// CHEAP fake glass — no transmission buffer. Use for repeated windows, visors, shields.
new THREE.MeshPhysicalMaterial({ color: 0x88ccff, metalness: 0.0, roughness: 0.1,
transparent: true, opacity: 0.25, clearcoat: 1.0, envMapIntensity: 1.5, depthWrite: false });
```
- **Cost:** one transparent draw call, no extra render target. Add the fresnel rim below for a readable edge.
## onBeforeCompile Patterns
Inject GLSL into stock materials to keep PBR lighting for free. Rules that make this safe with shared materials:
- **Cache key:** any material whose `onBeforeCompile` injects code MUST set `customProgramCacheKey` returning a string unique to that injection. Without it three can hand back a cached program compiled from a different (un-injected) material of the same type, silently dropping your code.
- **Sharing:** `onBeforeCompile` runs once per compiled program. Reuse one material instance across meshes and its uniforms update once for all. For per-object variation, use separate material instances (same cache key → program is still reused) or drive it from `instanceMatrix` / `instanceColor`.
- **Animating uniforms:** `onBeforeCompile` fires once, so stash the shader (`material.userData.shader = shader`) and write the uniform each frame: `if (m.userData.shader) m.userData.shader.uniforms.uTime.value = t;`. The snippets below use this pattern.
### (a) Fresnel rim glow
`vNormal` and `vViewPosition` (both view space) exist in the Standard/Physical fragment shader; `saturate` is defined in `<common>`.
```ts
material.onBeforeCompile = (shader) => {
shader.uniforms.uRimColor = { value: new THREE.Color(0x33ccff) };
shader.uniforms.uRimPower = { value: 3.0 };
shader.uniforms.uRimStrength = { value: 1.5 };
shader.fragmentShader =
'uniform vec3 uRimColor;\nuniform float uRimPower;\nuniform float uRimStrength;\n' +
shader.fragmentShader.replace(
'#include <emissivemap_fragment>',
`#include <emissivemap_fragment>
float fres = pow(1.0 - saturate(dot(normalize(vNormal), normalize(vViewPosition))), uRimPower);
totalEmissiveRadiance += uRimColor * fres * uRimStrength;`
);
};
material.customProgramCacheKey = () => 'fresnel-rim';
```
- **When:** shields, cloak/invuln states, silhouette separation from a busy background.
- **Cost:** a few ALU ops, no extra passes.
- **Read:** the rim marks a state change; keep base color readable when the rim is off.
### (b) Scrolling emissive panels
Inject a private UV varying so it works without a map assigned.
```ts
material.onBeforeCompile = (shader) => {
shader.uniforms.uTime = { value: 0 };
shader.uniforms.uPanelColor = { value: new THREE.Color(0x18e0ff) };
material.userData.shader = shader;
shader.vertexShader = 'varying vec2 vCookUv;\n' + shader.vertexShader.replace(
'#include <begin_vertex>', '#include <begin_vertex>\n vCookUv = uv;');
shader.fragmentShader =
'uniform float uTime;\nuniform vec3 uPanelColor;\nvarying vec2 vCookUv;\n' +
shader.fragmentShader.replace(
'#include <emissivemap_fragment>',
`#include <emissivemap_fragment>
float scroll = fract(vCookUv.y * 6.0 - uTime * 0.5);
float band = smoothstep(0.46, 0.5, scroll) * smoothstep(0.54, 0.5, scroll);
totalEmissiveRadiance += uPanelColor * band * 2.0;`
);
};
material.customProgramCacheKey = () => 'scroll-emissive';
```
- **When:** energy conduits, reactor walls, loading/charge bars, boost lanes.
- **Cost:** one `fract`/`smoothstep`, no textures.
- **Read:** scroll direction/speed should encode state (charging up, draining down).
### (c) Wind sway (foliage / flags)
`transformed` is object space and displaced before `<project_vertex>` applies `instanceMatrix`, so read the instance translation column for per-instance phase. Assumes model origin at the base, up = +Y.
```ts
material.onBeforeCompile = (shader) => {
shader.uniforms.uTime = { value: 0 };
material.userData.shader = shader;
shader.vertexShader = 'uniform float uTime;\n' + shader.vertexShader.replace(
'#include <begin_vertex>',
`#include <begin_vertex>
#ifdef USE_INSTANCING
float phase = instanceMatrix[3].x + instanceMatrix[3].z; // instance world offset
#else
float phase = 0.0;
#endif
float h = max(position.y, 0.0); // base stays planted, tips move most
transformed.x += sin(uTime * 1.5 + phase) * 0.08 * h;
transformed.z += cos(uTime * 1.1 + phase) * 0.05 * h;`
);
};
material.customProgramCacheKey = () => 'wind-sway';
```
- **When:** grass cards, banners, antennae, kelp — background life, not gameplay geometry.
- **Cost:** two trig ops per vertex; free on an `InstancedMesh`.
- **Read:** sway is ambient motion; never move collidable/interactable geometry with it.
### (d) Dissolve / spawn
Threshold-discard with a glowing edge. Inject a local-position varying and a hash; drive `uProgress` 0→1 to despawn, 1→0 to spawn.
```ts
material.onBeforeCompile = (shader) => {
shader.uniforms.uProgress = { value: 0 };
shader.uniforms.uEdgeColor = { value: new THREE.Color(0xff6a00) };
material.userData.shader = shader;
shader.vertexShader = 'varying vec3 vDisPos;\n' + shader.vertexShader.replace(
'#include <begin_vertex>', '#include <begin_vertex>\n vDisPos = position;');
shader.fragmentShader =
`uniform float uProgress;\nuniform vec3 uEdgeColor;\nvarying vec3 vDisPos;
float hash13(vec3 p){ p = fract(p * 0.1031); p += dot(p, p.yzx + 33.33); return fract((p.x + p.y) * p.z); }\n` +
shader.fragmentShader.replace(
'#include <dithering_fragment>',
`float n = hash13(floor(vDisPos * 12.0));
if (n < uProgress) discard;
float edge = smoothstep(uProgress, uProgress + 0.08, n);
gl_FragColor.rgb += uEdgeColor * (1.0 - edge) * 3.0; // post-tonemap add feeds bloom
#include <dithering_fragment>`
);
};
material.customProgramCacheKey = () => 'dissolve';
```
- **When:** enemy death, teleport-in, pickup spawn, object streaming.
- **Cost:** one hash + `discard` (discard disables early-Z; keep it to spawning objects, not the whole scene).
- **Read:** the edge color/direction telegraphs the event — spawn vs destroy must look different.
## Gradient Sky Dome
Cheaper than a cubemap for stylized scenes: a `BackSide` sphere with a top/horizon lerp plus a sun disc and halo.
```ts
const skyUniforms = {
uTop: { value: new THREE.Color(0x3a6fb0) },
uHorizon: { value: new THREE.Color(0xcfe4f5) },
uSunColor: { value: new THREE.Color(0xfff2cc) },
uSunDir: { value: new THREE.Vector3(0.4, 0.28, 0.6).normalize() },
};
const sky = new THREE.Mesh(
new THREE.SphereGeometry(500, 32, 16),
new THREE.ShaderMaterial({
side: THREE.BackSide, depthWrite: false, uniforms: skyUniforms,
vertexShader: `varying vec3 vDir;
void main(){ vDir = normalize(position); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
fragmentShader: `varying vec3 vDir;
uniform vec3 uTop, uHorizon, uSunColor, uSunDir;
void main(){
float h = clamp(vDir.y * 0.5 + 0.5, 0.0, 1.0);
vec3 col = mix(uHorizon, uTop, pow(h, 0.6));
float d = clamp(dot(normalize(vDir), normalize(uSunDir)), 0.0, 1.0);
col += uSunColor * (pow(d, 800.0) + pow(d, 8.0) * 0.25); // disc + halo
gl_FragColor = vec4(col, 1.0);
}`,
})
);
sky.frustumCulled = false;
scene.add(sky);
```
- **When:** any stylized outdoor scene without a photographic backdrop.
- **Cost:** one draw call, no cubemap textures, no mips.
- **Read:** a raw `ShaderMaterial` bypasses tone mapping and sRGB conversion — author colors in display space; if the scene runs ACES, nudge them brighter. Keep horizon value distinct from hazards silhouetted against it.
## Post-Processing Chain
Finishing pass only. Move tone mapping/sRGB to `OutputPass`; keep `renderer.toneMapping` set so it reads it.
```ts
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
// UnrealBloomPass(resolution, strength, radius, threshold)
const bloom = new UnrealBloomPass(new THREE.Vector2(innerWidth, innerHeight),
0.45, // strength: 0.35-0.6
0.3, // radius: 0.2-0.4
0.85); // threshold: only pixels brighter than this bloom
composer.addPass(bloom);
const VignetteShader = {
uniforms: { tDiffuse: { value: null }, uStrength: { value: 0.85 }, uSize: { value: 0.72 } },
vertexShader: `varying vec2 vUv; void main(){ vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
fragmentShader: `uniform sampler2D tDiffuse; uniform float uStrength, uSize; varying vec2 vUv;
void main(){
vec4 c = texture2D(tDiffuse, vUv);
float d = distance(vUv, vec2(0.5));
c.rgb *= mix(1.0, smoothstep(uSize, uSize - 0.45, d), uStrength);
gl_FragColor = c;
}`,
};
composer.addPass(new ShaderPass(VignetteShader));
composer.addPass(new OutputPass()); // ALWAYS last: tone mapping + sRGB
// loop: composer.render() instead of renderer.render()
// resize: composer.setSize(w, h); composer.setPixelRatio(Math.min(devicePixelRatio, 2));
```
- **Bloom rule:** bloom sells authored emissive (threshold 0.85 keeps mid-bright materials out). It must never be the main source of detail — if a shape only reads because it glows, the geometry is missing.
- **Vignette cost:** one full-screen ShaderPass; keep `uStrength` subtle, never darken the play path.
- **Mobile:** the composer allocates full-resolution HDR targets, so cost scales with DPR². Cap DPR before adding passes. On low-end, skip the composer (call `renderer.render`) or run bloom-only via `composer.setPixelRatio(Math.min(devicePixelRatio, 1.25))`. Compare screenshots with post on/off and profile.
## Cheap Tricks
- **Vertex-color AO** — bake occlusion into the mesh: `geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))`, material `{ vertexColors: true }`, darken cavities/creases. **When:** static props/terrain. **Cost:** one attribute, zero draw calls. **Read:** ground shapes with contact darkness; don't tint gameplay-critical surfaces.
- **Polygon-offset decals** — coplanar decal mesh with `{ polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -1, transparent: true }` to kill z-fighting. **When:** panel lines, numbers, faction glyphs. **Cost:** +1 draw call each — instance repeats. **Read:** decals imply function/scale, not random surface noise.
- **Fake contact shadow** — flat `PlaneGeometry` with a radial-gradient `CanvasTexture`, `{ transparent: true, depthWrite: false }`, under the object; scale/fade alpha with height. **When:** hovering or moving props that don't warrant a shadow map. **Cost:** one draw call, no shadow pass. **Read:** anchors floating objects so position reads.
- **Emissive LOD signals** — swap `emissiveIntensity` or material by distance so far pickups/beacons still read, add geometry detail only up close. **When:** dense repeated signals. **Cost:** a material/uniform swap. **Read:** keep the signal color constant across LOD so identity survives the transition.
- **Matcap props** — `new THREE.MeshMatcapMaterial({ matcap })` bakes lighting into one texture; no lights or env needed. **When:** background/stylized props. **Cost:** the cheapest lit-looking material, one texture. **Read:** matcap ignores scene lights, so never use it where a dynamic light or state glow must show on the surface.
references/technical-art.md
# Technical Art For Three.js Games
Use this reference before premium/AAA/showcase graphics work, shader/material/post-processing changes, VFX systems, generated/imported asset cleanup, LOD/instancing work, or any visual pass that could affect browser performance.
Technical art is the bridge between art direction and real-time constraints. The goal is not maximum detail; it is readable authored detail that survives active gameplay, mobile viewports, and WebGL budgets.
Research basis: Three.js exposes renderer diagnostics through `WebGLRenderer.info`; `InstancedMesh` is designed for many objects sharing geometry/materials; `LOD` switches objects by distance; `KTX2Loader` supports Basis Universal GPU texture workflows; MDN WebGL best practices emphasize eliminating errors, understanding system limits, eager deletion, batching draw calls, per-pixel VRAM budgets, smaller back buffers, mipmaps, compressed textures, and high-DPI discipline.
## Technical Art Brief
Before implementation, write:
- Art direction in renderable terms: shapes, materials, lighting, VFX, camera, UI/world motifs.
- Hero surfaces: what must look authored at active-play distance.
- Support surfaces: what can be procedural, instanced, simplified, or culled.
- Material kit: named roles, not one-off colors.
- VFX language: event-driven effects and state readability.
- Lighting stack: key/fill/rim/practical/contact/depth.
- Render budget target: draw calls, triangles, textures, materials, DPR, shadow/post cost.
- Asset strategy: procedural / generated 2D / generated 3D / hybrid / imported.
- Mobile constraint: what changes first if performance or readability fails.
## Render Budget Starting Points
These are starting contracts, not universal limits — measure on the target game, and document every deliberate overrun as a tradeoff. The canvas inspector (`npm run inspect:canvas`) compares live diagnostics against the same numbers and reports over-budget rows.
| Metric (worst active-play view) | Desktop tier | Mobile tier |
| --- | --- | --- |
| Draw calls (`info.render.calls`) | <= 300 | <= 150 |
| Triangles (`info.render.triangles`) | <= 750k | <= 300k |
| Geometries (`info.memory.geometries`) | <= 300 | <= 200 |
| Textures (`info.memory.textures`) | <= 60 | <= 40 |
| Texture memory (est.) | <= 256 MB | <= 128 MB |
| Shadow-casting lights | <= 2 | 1 |
| Shadow map size | <= 2048 | <= 1024 |
| DPR cap | 2 | 1.5-2 |
| Post passes (beyond render+output) | <= 2 | 0-1 |
How to spend within them:
- Draw calls: repeated world/detail pieces should be instanced or merged by material.
- Triangles: spend on silhouettes near the camera; reduce background detail through LOD, impostors, or simplified meshes.
- Materials: share material roles aggressively. Unique material count often grows faster than geometry count.
- Textures: keep opaque large images compressed or small; avoid unique 2K+ textures for tiny repeated props.
- Shadows: reserve real shadows for hero objects and grounding anchors; use blob/contact meshes for small repeated props (see `references/shader-cookbook.md` for the cheap contact-shadow recipe).
- Post: every pass must earn its cost and preserve gameplay clarity; concrete chain settings are in `references/shader-cookbook.md`.
Always report actual renderer diagnostics after the graphics pass: calls, triangles, geometries, textures, material count if available, post passes, shadow settings, DPR cap, and bottlenecks.
## Material And Shader System
Use a material kit of named shared roles, not one-off colors. Reuse each role across every mesh that plays the same part:
- `bodyPrimary`: dominant player/world shell.
- `bodySecondary`: panel contrast.
- `trim`: rails, bevel highlights, borders, edge highlights.
- `hazard`: danger surfaces, damage cues, warning stripes.
- `reward`: collectible surfaces with readable value.
- `shieldBoost`: shield, boost, and status states.
- `glass`: cockpit, shield, lens, visor.
- `emissiveSignal`: authored glow strips, status lights, beacon cores.
- `groundContact`: dark matte surfaces and shadow receivers.
- `decalDark` and `decalLight`: panel lines, scratches, numbers, icons.
- UI/world signal colors shared between HUD and diegetic markers.
Use `MeshStandardMaterial` for most surfaces. Use `MeshPhysicalMaterial` selectively for cockpit glass, clearcoat panels, iridescent shields, or premium hero details. Share materials across repeated meshes.
Shader or `onBeforeCompile` work must have a reason:
- State readability: shield ripple, heat, cloak, damage pulse.
- Surface identity: water, forcefield, hologram, scanline, energy core.
- Performance: cheap procedural variation instead of many textures.
- Composition: separating player/threat/reward from background.
Reject shader work that only adds noise, bloom bait, or hidden cost without improving active-play decisions. When shader work is justified, use the proven recipes in `references/shader-cookbook.md` (material values, onBeforeCompile patterns, sky, post chain) instead of improvising GLSL.
## VFX Readability
Every VFX effect must answer:
- What event or state triggers it?
- What does it tell the player?
- Does it point to player, threat, reward, objective, or impact?
- How long does it last?
- Is it pooled or cheap to recreate?
- Does it obscure collision, HUD, or the next decision?
- Is there a reduced-motion fallback for heavy shake/strobe?
Use event-driven VFX over permanent particle clutter:
- Pickup: ring contraction, shard burst, score trail, brief HUD echo.
- Hit/fail: impact ring, debris, damage flash, brief hit pause, camera impulse.
- Boost/speed: engine trail, lane streaks, FOV ease, side streaks, audio pitch.
- Near miss/combo: side spark, line snap, badge pulse, streak counter.
- Shield/invulnerable: refractive shell, rim pulse, absorbed-impact ripple, material swap.
- Spawn/despawn: anticipation pulse, telegraph, dissolve or scale snap.
Pool effects and reuse geometries/materials. Permanent particle fields must stay cheap and sparse.
## Instancing, LOD, And Culling
Use instancing for many copies with the same geometry/material and different transforms: windows, bolts, lane markers, city lights, debris, foliage-like props, stars, crowd cards, track panels, repeated pickups, background modules.
Rules:
- Update `instanceMatrix.needsUpdate` and `instanceColor.needsUpdate` only after batched changes.
- Compute or update bounds for instanced groups when transforms change materially.
- Do not instance everything blindly. Different materials or constantly changing transforms can erase the win.
- Keep collision separate from instanced visual detail.
Use LOD when:
- A hero/background object spans large distance ranges.
- The silhouette matters near camera but not far away.
- Imported/generated models are heavier than needed for background use.
Rules:
- Add hysteresis or distance gaps to reduce visible popping.
- Use impostor cards or simplified silhouettes for far layers when appropriate.
- Verify LOD transitions during gameplay camera motion, not only static orbit.
## Generated And Imported Asset Cleanup
For every Tripo/imported GLB/FBX hero asset:
- Confirm scale, pivot, forward/up orientation, bounds, and active-play silhouette.
- Create a simple collision proxy independent from the visual mesh.
- Inspect file size, approximate triangles, mesh count, material count, texture count, and animation clips when available.
- Replace or simplify excessive materials and textures.
- Add LOD or simplified background variant when reused many times.
- Verify PBR material readability under the game's lighting, not only in a model viewer.
- Keep API keys and temporary URLs out of client code and checked-in files.
## Decals, Trim, And Surface Detail
Prefer reusable surface systems:
- Canvas-generated trim sheets for panel lines, markings, arrows, numbers.
- Thin offset decal meshes for hazard marks, faction symbols, lane glyphs, scuffs.
- Shared small textures for noise/wear rather than unique full-size images.
- Procedural UV-independent detail for repeated hard-surface props.
Surface detail must reinforce scale, function, faction, route, or state. Do not add random lines everywhere.
## Color And Readability
Readability beats palette consistency:
- Threats differ from rewards by shape and motion, not only hue.
- Interactables differ from background by silhouette/value/material.
- UI signal colors match world signal colors.
- Bloom/fog/darkness cannot be the primary separator.
- Colorblind-risk information has shape/icon/motion backup.
## Technical Art Report
Report:
- Technical art brief.
- Material kit and shader/VFX decisions.
- Instancing/LOD/culling strategy.
- Render budget target and actual diagnostics.
- Imported/generated asset cleanup evidence.
- VFX readability checks.
- Mobile/DPR/post/shadow tradeoffs.
- Remaining visual performance risks.
references/visual-scorecard.md
# Visual Scorecard
Score active-play screenshots, not idle title screens or isolated showroom models. Use desktop and mobile screenshots when mobile is in scope.
Scores are self-assessed against the anchors below, so they drift optimistic. Two countermeasures are mandatory for premium/AAA/showcase claims: cite Measured Evidence for the categories it supports, and run the Fresh-Eyes Review before finalizing.
## Calibration Anchors
Reference screenshots for score calibration are packaged in `threejs-aaa-graphics-builder/assets/scorecard-anchors/`:
- `scene-1.jpg` — score ~1: primitive player and pickups on a flat sparse arena, utility HUD.
- `scene-2.jpg` — score ~2: authored track kit, imported hero asset, designed genre HUD, intentional lighting.
- `scene-3.jpg` — score ~2.5-3: dense layered world in active play, readable hero silhouette, event VFX, cohesive HUD.
Before scoring World/environment, Hero/player, Materials/textures, or Lighting/render, view the anchors and compare: if your screenshot reads closer to `scene-1.jpg` than `scene-3.jpg` for that surface, the category is at most a 1-2 regardless of how much code was written.
## Scoring Scale
- 0: Placeholder. Default primitives, sparse world, unreadable state, debug UI, or no evidence.
- 1: Basic styled. Playable and themed, but still obvious prototype assets, flat composition, repeated silhouettes, or generic UI.
- 2: Premium stylized. Authored silhouettes, material/detail systems, readable state, cohesive UI/world, measured performance.
- 3: Showcase. Strong art direction, memorable hero and world, dense authored detail, excellent readability, polished VFX/rendering, and diagnostics.
## Categories
1. Art direction.
- 0: No clear theme.
- 1: Theme is mostly colors/fog.
- 2: Theme affects forms, materials, UI, world, and feedback.
- 3: Distinct identity visible in every surface.
2. Hero/player.
- 0: Default primitive stack.
- 1: Basic object with glow or simple attachments.
- 2: Authored silhouette, decals/trim, state cues, collision proxy.
- 3: Memorable model with layered construction and expressive feedback.
3. Obstacles/enemies.
- 0: Cubes/cones/spheres.
- 1: Recolored repeated silhouette.
- 2: Three readable variants with telegraphs and material cues.
- 3: Varied family with animation, anticipation, and gameplay clarity.
4. Rewards/interactables.
- 0: Plain sphere/ring/token.
- 1: Repeated object with simple glow.
- 2: Two authored forms with idle/collect states and UI feedback.
- 3: Desirable, animated, and clearly valued during motion.
5. World/environment.
- 0: Flat plane, empty arena, box skyline.
- 1: Themed but sparse repeated blocks.
- 2: Layered prop kit with foreground/midground/background and scale cues.
- 3: Dense authored world that supports gameplay readability.
6. Materials/textures.
- 0: Flat colors.
- 1: Basic roughness/metalness or emissive color.
- 2: Shared material roles, procedural decals, trim, panel lines, wear/noise.
- 3: Rich cohesive material language with measured texture/resource use.
7. Lighting/render.
- 0: Default lights or unreadable darkness.
- 1: Fog/bloom used as main style.
- 2: Intentional tone mapping, exposure, key/fill/rim, contact, depth.
- 3: Cinematic but readable composition with disciplined post-processing.
8. VFX/motion.
- 0: None or random particles.
- 1: Generic particles/trails.
- 2: Event-driven VFX for boost, pickup, hit, fail, combo, shield, or spawn.
- 3: High-impact effects that clarify gameplay and remain performant.
9. UI/HUD.
- 0: Debug text or missing UI.
- 1: Generic stat-card dashboard.
- 2: Genre-specific HUD states, meters/icons, responsive text fit.
- 3: Cohesive game interface with strong hierarchy and polished transitions.
10. Performance evidence.
- 0: No metrics after visual changes.
- 1: Informal "seems fine".
- 2: Renderer counts, build/browser QA, desktop/mobile screenshots, and technical-art budget notes.
- 3: Baseline/post metrics, bottleneck notes, budgets, optimized asset strategy, and VFX/readability tradeoffs.
## Thresholds
Premium:
- Every category at least 2.
- Average at least 2.3.
- Desktop and mobile active-play screenshots captured when mobile is in scope.
- Renderer diagnostics reported after graphics changes.
Showcase:
- At least six categories score 3.
- No category below 2.
- Average at least 2.7.
- Performance evidence includes before/after or budget-aware notes.
## Automatic Failures
Any of these prevents a premium/AAA/showcase claim:
- Active screenshot is primitive-dominant.
- Main world is mostly stretched boxes, flat planes, or a sparse arena.
- Hero asset is mostly default primitives plus glow.
- Obstacles or rewards are one repeated silhouette.
- HUD is mostly rectangular stat/debug cards.
- Fog, darkness, bloom, or particles hide missing authored geometry.
- UI overlaps the play path, clips text, or fails mobile safe areas.
- The game is not playable through real input.
- No active-play screenshot was captured.
- No renderer diagnostics were collected after major graphics work.
- No technical-art budget or imported/generated asset diagnostics were reported for premium graphics work.
## Measured Evidence
Run the canvas inspector (`npm run inspect:canvas`, or `threejs-qa-release/scripts/inspect-threejs-canvas.mjs`) on desktop and mobile and cite its `metrics` and `renderBudget` blocks in the scorecard. The numbers are advisory signals, not gates, but they must be reported and low values must be explained rather than ignored:
- `colorEntropyBits` below ~3.0 or `dominantColorShare` above ~0.6 suggests a sparse, flat scene — supporting evidence against World/environment or Materials/textures scores above 2.
- `edgeDensity` below ~0.04 suggests primitive-dominant or empty framing — supporting evidence against World/environment and Hero/player scores above 2.
- `luminance.contrast` below ~60 suggests fog/darkness compression — supporting evidence against Lighting/render scores above 2.
- `renderBudget` rows over the tier budget require a documented tradeoff in the technical-art budget (see `references/technical-art.md`).
- Renderer diagnostics (calls, triangles, geometries, textures) back the Performance evidence category.
## Fresh-Eyes Review
The builder must not be the only grader. For premium/AAA/showcase claims:
- If the runner supports subagents (Task tool or equivalent), spawn a reviewer with ONLY: the screenshots, this scorecard file, and the inspector metrics JSON. No build context, no prior scores. The reviewer must receive the COMPLETE capture set — every captured state, desktop and mobile — never a hand-picked subset; a curated selection can hide weak states or miss content the builder knows exists (capture states with the inspector's `--state` flag so nothing is gated behind live play). The reviewer fills the scorecard independently; reconcile by taking the lower score per category unless concrete evidence overturns it. Report both score sets.
- If subagents are unavailable, run an adversarial self-review before finalizing: for each category, write one sentence making the strongest case that the score is a 1, citing what is visible in the screenshot; only then assign the score. Include these sentences in the report.
## Report Format
```text
Visual scorecard:
- Art direction: before X / after Y - evidence:
- Hero/player: before X / after Y - evidence:
- Obstacles/enemies: before X / after Y - evidence:
- Rewards/interactables: before X / after Y - evidence:
- World/environment: before X / after Y - evidence:
- Materials/textures: before X / after Y - evidence:
- Lighting/render: before X / after Y - evidence:
- VFX/motion: before X / after Y - evidence:
- UI/HUD: before X / after Y - evidence:
- Performance evidence: before X / after Y - evidence:
Measured evidence: colorEntropyBits / edgeDensity / luminance.contrast /
dominantColorShare per viewport, renderer diagnostics, render budget rows
Fresh-eyes review: subagent scores or adversarial self-review notes
Average:
Automatic failures remaining:
```
If any category remains below threshold, state the exact next pass instead of declaring completion.