chore: share game-studio hermes plugin

This commit is contained in:
2026-05-11 12:00:45 +08:00
parent d23cf3807d
commit 81f57ea5ce
43 changed files with 2230 additions and 1 deletions

View File

@@ -0,0 +1,46 @@
{
"name": "game-studio",
"version": "0.1.0",
"description": "Design, prototype, and ship browser games with guided 2D and 3D workflows, asset pipelines, and playtesting support.",
"author": {
"name": "OpenAI",
"email": "support@openai.com",
"url": "https://openai.com/"
},
"homepage": "https://openai.com/",
"repository": "https://github.com/openai/plugins",
"license": "MIT",
"keywords": [
"games",
"phaser",
"threejs",
"react-three-fiber",
"gltf",
"rapier",
"webgl",
"sprites",
"playtest"
],
"skills": "./skills/",
"interface": {
"displayName": "Game Studio",
"shortDescription": "Design, prototype, and ship browser games",
"longDescription": "Plan, prototype, and build browser games with guided workflows for gameplay systems, UI, asset pipelines, and playtesting across 2D and 3D projects.",
"developerName": "OpenAI",
"category": "Coding",
"capabilities": [
"Interactive",
"Write"
],
"websiteURL": "https://openai.com/",
"privacyPolicyURL": "https://openai.com/policies/privacy-policy/",
"termsOfServiceURL": "https://openai.com/policies/terms-of-use/",
"defaultPrompt": [
"Design a browser game and plan the core loop"
],
"brandColor": "#0F766E",
"composerIcon": "./assets/game-studio.svg",
"logo": "./assets/app-icon.png",
"screenshots": []
}
}

View File

@@ -0,0 +1,38 @@
"""Hermes wrapper for the OpenAI Codex Game Studio plugin.
This plugin was imported from a Codex curated plugin cache. It exposes the
plugin's bundled SKILL.md files as Hermes plugin skills using qualified names
like `game-studio:phaser-2d-game`.
"""
from __future__ import annotations
from pathlib import Path
def _read_description(skill_md: Path) -> str:
try:
text = skill_md.read_text(encoding="utf-8")[:4000]
except Exception:
return ""
if text.startswith("---"):
end = text.find("\n---", 3)
if end != -1:
frontmatter = text[3:end]
for line in frontmatter.splitlines():
if line.strip().startswith("description:"):
return line.split(":", 1)[1].strip().strip("\"'")
return ""
def register(ctx) -> None:
root = Path(__file__).resolve().parent
skills_root = root / "skills"
if not skills_root.exists():
return
for skill_md in sorted(skills_root.glob("*/SKILL.md")):
ctx.register_skill(
name=skill_md.parent.name,
path=skill_md,
description=_read_description(skill_md),
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" role="img" aria-labelledby="title desc">
<title id="title">Game Studio</title>
<desc id="desc">A stylized browser game plugin icon with a viewport frame, a d-pad, and layered tiles.</desc>
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#134E4A"/>
<stop offset="100%" stop-color="#0F766E"/>
</linearGradient>
<linearGradient id="screen" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#CCFBF1"/>
<stop offset="100%" stop-color="#5EEAD4"/>
</linearGradient>
</defs>
<rect width="256" height="256" rx="52" fill="url(#bg)"/>
<rect x="40" y="46" width="176" height="124" rx="20" fill="#062F2D" stroke="#7DD3C7" stroke-width="8"/>
<rect x="58" y="62" width="140" height="92" rx="12" fill="url(#screen)"/>
<path d="M76 132h28l14-18 18 20 24-30 18 18v18H76z" fill="#0F766E" opacity="0.9"/>
<rect x="62" y="178" width="50" height="50" rx="18" fill="#0B2F2D" stroke="#7DD3C7" stroke-width="6"/>
<rect x="144" y="178" width="50" height="50" rx="18" fill="#0B2F2D" stroke="#7DD3C7" stroke-width="6"/>
<rect x="81" y="189" width="12" height="28" rx="4" fill="#CCFBF1"/>
<rect x="73" y="197" width="28" height="12" rx="4" fill="#CCFBF1"/>
<circle cx="160" cy="203" r="8" fill="#FDE68A"/>
<circle cx="178" cy="203" r="8" fill="#FCA5A5"/>
<circle cx="169" cy="192" r="8" fill="#BFDBFE"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,6 @@
name: game-studio
version: 0.1.0
description: Design, prototype, and ship browser games with guided 2D and 3D workflows,
asset pipelines, and playtesting support.
author: OpenAI
kind: standalone

View File

@@ -0,0 +1,50 @@
# Alternative 3D Engines
This plugin defaults to Three.js and React Three Fiber for code generation. Babylon.js and PlayCanvas still matter, but they are reference-only alternatives in the current plugin shape.
## Babylon.js
Useful sources:
- [Babylon.js home](https://babylonjs.com/)
- [Engine specifications](https://www.babylonjs.com/specifications/)
- [Babylon.js Editor](https://editor.babylonjs.com/)
Choose Babylon.js when:
- the user explicitly wants Babylon.js
- the team wants a more engine-heavy stack with scene, material, viewer, and editor tooling built around one ecosystem
- WebGPU, Havok, node-based rendering or material tooling, or Babylon-specific runtime features are part of the reason for the choice
What Babylon.js is good at:
- full-engine 3D workflows
- strong built-in tooling and editor surfaces
- WebGL and WebGPU support inside one ecosystem
- integrated viewer and inspection-oriented workflows
## PlayCanvas
Useful sources:
- [PlayCanvas graphics overview](https://developer.playcanvas.com/user-manual/graphics/)
- [Supported formats](https://developer.playcanvas.com/user-manual/assets/supported-formats/)
- [PlayCanvas React GLTF API](https://developer.playcanvas.com/user-manual/react/api/gltf/)
- [PlayCanvas Web Components](https://developer.playcanvas.com/user-manual/web-components/)
Choose PlayCanvas when:
- the user explicitly wants PlayCanvas
- the team prefers an editor-centric browser engine workflow
- GLB import, runtime tooling, React bindings, or web-component-based embedding are central to the project
What PlayCanvas is good at:
- editor and engine working together
- GLB-centric browser asset workflows
- strong web embedding patterns
- WebGL and WebGPU support with browser-focused runtime tooling
## Default recommendation
If the user has not already chosen Babylon.js or PlayCanvas, prefer Three.js or React Three Fiber in this plugin because they give the best balance of portability, ecosystem depth, and predictable code generation across normal browser-game repos.

View File

@@ -0,0 +1,53 @@
# Engine Selection
Use this table to choose the default implementation path for browser games in this plugin.
## Default choices
- Choose Phaser for 2D games unless the user explicitly asks for another stack.
- Choose vanilla Three.js for explicit 3D or WebGL-first experiences in plain TypeScript or Vite apps.
- Choose React Three Fiber when the 3D scene is part of a React application and shared app state or declarative composition matters.
- Choose raw WebGL only when engine abstractions are the problem, not because WebGL sounds more advanced.
- Treat Babylon.js and PlayCanvas as alternative ecosystems, not the default path in this plugin.
## Phaser is the best fit when
- the game is sprite- or tile-based
- the game is top-down, side-view, or grid tactics
- you need camera, sprite, and scene primitives quickly
- the UI will mostly live in DOM overlays
- the game loop is gameplay-first rather than renderer-first
## Three.js is the best fit when
- the game is genuinely 3D
- camera movement and depth are central to play
- materials, lighting, or scene composition matter more than sprite tooling
- the user explicitly asks for Three.js or WebGL-based 3D work
- the team wants direct control over scene setup, loaders, physics integration, and the game loop
## React Three Fiber is the best fit when
- the project already lives in React
- the 3D scene needs to share app state with the rest of the product
- declarative scene composition is more valuable than a fully imperative loop
- the team benefits from pmndrs tooling such as Drei, React Postprocessing, or `@react-three/rapier`
## Babylon.js or PlayCanvas are the best fit when
- the user explicitly asks for those engines
- the team already has engine-specific tooling or editor workflows in those ecosystems
- the project wants engine-heavy runtime features, editor-first workflows, or platform-specific tooling that Three.js does not provide by default
## Raw WebGL is the best fit when
- the project is shader-heavy
- you need a custom renderer or post-processing pipeline
- the user explicitly wants low-level rendering control
## Avoid these mismatches
- Do not choose a 3D stack for a normal 2D tactics or platformer game.
- Do not choose raw WebGL for a game that mostly needs engine conveniences.
- Do not force HUD and menus into canvas or WebGL when DOM would be clearer.
- Do not default to Babylon.js or PlayCanvas when the user mainly wants portable TypeScript code generation across browser-game repos.

View File

@@ -0,0 +1,97 @@
# Frontend Prompts
Use these prompt shapes to keep browser-game UI intentional instead of generic.
## Prompt ingredients
- game genre and fantasy
- camera or viewpoint
- player verbs
- HUD zones
- menu surfaces
- motion tone
- desktop and mobile expectations
- playfield protection and disclosure strategy
- anti-patterns to avoid
## HUD implementation prompt
```text
Design and implement the HUD for a browser game.
Game fantasy: <genre and world>
Viewpoint: <top-down, side-view, tactical grid, third-person, first-person>
Primary verbs: <attack, move, cast, build, dodge, inspect>
HUD zones: <top status, bottom command bar, side objectives, modal panels>
Tone: <ornate, rugged, clean sci-fi, painterly, arcade>
Motion: <restrained, snappy, dramatic only on important state changes>
Platforms: desktop and mobile
Constraints: readable over active gameplay, DOM-based overlays, CSS variables, no generic dashboard look
Playfield protection: keep the central play area clear during normal play, prefer one primary persistent HUD cluster, and move long-form notes or controls behind menus
Avoid: flat admin UI, default font stack, cluttered overlays, constant micro-animation, equal-weight cards around every edge, broad always-on panels that cover the world
```
## Menu implementation prompt
```text
Build the shell UI for a browser game with the following surfaces:
- title screen
- pause menu
- settings panel
- game-over or victory screen
Keep the menus visually tied to the game world, not to a SaaS app aesthetic. Use strong hierarchy, intentional typography, meaningful motion, and responsive layout.
```
## Low-chrome 3D starter prompt
```text
Design the initial playable HUD for a browser 3D game.
Goal: the first screen should feel playable in under 3 seconds, not like a dashboard.
Camera mode: <third-person, first-person, orbit, rail>
Primary verbs: <move, inspect, interact, attack, build>
Persistent UI budget:
- one compact objective chip or status cluster
- one optional small secondary surface
- one transient controls or interaction hint
Interaction rules:
- keep the center of the playfield clear
- keep the lower-middle playfield mostly clear during normal play
- lore, notes, quest details, and long control lists live behind a drawer, pause menu, or toggle
- modal and pause states must gate camera input correctly
Avoid:
- giant title cards over live gameplay
- field notes, controls, and objectives all open at once
- equally weighted glass panels in every corner
- full-screen overlay chrome during normal movement
```
## 3D overlay prompt
```text
Design and implement the HUD and menu overlays for a browser 3D game.
Engine context: <vanilla Three.js or React Three Fiber>
Camera mode: <third-person, first-person, orbit, rail>
Primary verbs: <move, inspect, interact, attack, build>
Overlay surfaces: <reticle, quest log, inventory, pause menu, settings>
Interaction constraints:
- DOM overlays, not in-scene UI by default
- modal and menu states must suspend or gate camera input correctly
- keyboard and pointer states must be explicit
- reduced-motion support for non-essential transitions
- keep the center of the screen clear during normal play
- keep the lower-middle playfield mostly clear during normal play
- start with one compact objective surface and transient hints rather than multiple permanent cards
- secondary content such as notes, lore, and full control references should be collapsed by default
Avoid:
- dashboard UI
- cluttered full-screen overlays
- boxed panels around every edge of the viewport
- full-width top-and-bottom panel stacks
- permanent text-heavy cards competing with the scene
- camera movement continuing under active menus
```

View File

@@ -0,0 +1,43 @@
# GLB Loading Starter
Use this as the canonical minimal pattern for loading shipped 3D content.
## Vanilla Three.js
```ts
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
const draco = new DRACOLoader();
draco.setDecoderPath("/draco/");
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(draco);
gltfLoader.load("/assets/hero.glb", (gltf) => {
const root = gltf.scene;
root.traverse((node) => {
if ("castShadow" in node) {
node.castShadow = true;
node.receiveShadow = true;
}
});
scene.add(root);
});
```
## React Three Fiber
```tsx
import { useGLTF } from "@react-three/drei";
function HeroModel() {
const gltf = useGLTF("/assets/hero.glb");
return <primitive object={gltf.scene} />;
}
```
## Notes
- Default shipping format is GLB or glTF 2.0.
- Keep optimization upstream in the asset pipeline; loader code should stay boring.

View File

@@ -0,0 +1,56 @@
# Phaser Architecture
This is the default 2D structure for the plugin.
## Recommended module split
```text
src/
game/
simulation/
state.ts
systems/
rules/
content/
encounters/
items/
maps/
input/
actions.ts
bindings.ts
assets/
manifest.ts
phaser/
boot/
scenes/
BootScene.ts
MenuScene.ts
BattleScene.ts
view/
sprites/
fx/
camera/
adapters/
sceneBridge.ts
ui/
hud/
menus/
overlays/
```
## Responsibilities
- `simulation/`: source of truth for rules and saveable state
- `content/`: authored data and encounter configuration
- `input/`: action map and physical control bindings
- `assets/`: stable manifest keys and asset metadata
- `phaser/scenes/`: scene orchestration, not game rules
- `phaser/view/`: render and effect helpers
- `ui/`: DOM HUD, menus, and narrative panels
## Rules
- Phaser scenes read from and write to the simulation through a defined bridge.
- Game state changes should not depend on sprite or tween lifetime.
- Camera behavior should be isolated from combat or movement rules.
- Use DOM for dense text and settings surfaces.

View File

@@ -0,0 +1,51 @@
# Playtest Checklist
Use this checklist for browser-game QA.
## Universal checks
- Does the game boot into a useful first state?
- Are the main verbs obvious and responsive?
- Does the HUD remain readable over gameplay?
- Does the first playable screen prioritize play over dashboard chrome?
- Does the central playfield stay mostly clear during normal play?
- Do pause, failure, and recovery states work?
- Does the game survive viewport changes?
## 2D checks
- sprite baseline consistency
- hit, hurt, and attack timing
- command menu focus and input state
- tile or platform readability
- particle or camera effects obscuring gameplay
## 3D checks
- camera control stability
- camera and menu-state handoff
- depth readability
- persistent overlay weight versus scene readability
- secondary notes, controls, and quest details collapsed by default
- resize and aspect-ratio handling
- renderer fallback or context-loss handling
- material and lighting stability across states
- GLB asset and texture streaming behavior
- collision proxy alignment
- GPU bottlenecks isolated with capture tools when needed
## Browser checks
- desktop and mobile viewports
- input modality differences
- reduced-motion behavior
- pause behavior when focus changes
- pointer-lock and camera-input release when overlays open
- transient onboarding hints dismiss or fade once the player is moving
## Reporting
- Capture screenshots for visual findings.
- Put findings in severity order.
- Include reproduction steps.
- Call out whether the likely owner is simulation, renderer, frontend, or asset pipeline.

View File

@@ -0,0 +1,42 @@
# Rapier Integration Starter
Use this as the smallest canonical pattern for adding physics without letting it take over the whole runtime.
## Vanilla Three.js
```ts
import RAPIER from "@dimforge/rapier3d-compat";
await RAPIER.init();
const world = new RAPIER.World({ x: 0, y: -9.81, z: 0 });
const body = world.createRigidBody(RAPIER.RigidBodyDesc.dynamic().setTranslation(0, 2, 0));
world.createCollider(RAPIER.ColliderDesc.cuboid(0.5, 0.5, 0.5), body);
renderer.setAnimationLoop(() => {
world.step();
const p = body.translation();
mesh.position.set(p.x, p.y, p.z);
renderer.render(scene, camera);
});
```
## React Three Fiber
```tsx
import { Physics, RigidBody } from "@react-three/rapier";
<Physics gravity={[0, -9.81, 0]}>
<RigidBody colliders="cuboid">
<mesh>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="#3dd9b8" />
</mesh>
</RigidBody>
</Physics>;
```
## Notes
- Keep physics state synchronized through an explicit bridge.
- Do not bury gameplay rules inside render or physics callbacks.

View File

@@ -0,0 +1,42 @@
# React Three Fiber Stack
This is the default React-native 3D stack for the plugin.
## Primary components
- [React Three Fiber](https://r3f.docs.pmnd.rs/getting-started/introduction) for declarative Three.js rendering in React.
- [Drei](https://drei.docs.pmnd.rs/controls/introduction) for controls, loaders, helpers, environments, and common scene utilities.
- [React Postprocessing](https://react-postprocessing.docs.pmnd.rs/introduction) for effect composition in React-hosted scenes.
- [React Three Rapier](https://pmndrs.github.io/react-three-rapier/) for physics integration.
- [React Three A11y](https://a11y.docs.pmnd.rs/introduction) when scene interaction benefits from accessibility-aware patterns.
- [glTF Transform](https://gltf-transform.dev/) and the [glTF 2.0 specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html) for shipped assets.
## Default stack choices
- Runtime: `@react-three/fiber` + `three`
- Helper ecosystem: `@react-three/drei`
- Physics: `@react-three/rapier`
- Effects: `@react-three/postprocessing`
- Accessibility: `@react-three/a11y` when appropriate
- Assets: GLB or glTF 2.0
## Choose this stack when
- the 3D scene lives inside a React app
- the UI shell, settings, or product flow already uses React
- the team benefits from declarative scene composition
- the scene must share app state with non-canvas UI
## Avoid this stack when
- the project wants a cleaner imperative loop with minimal React coordination
- the whole game runtime would be easier to reason about in plain TypeScript
## Companion references
- `threejs-stack.md`
- `react-three-fiber-starter.md`
- `gltf-loading-starter.md`
- `rapier-integration-starter.md`
- `web-3d-asset-pipeline.md`
- `webgl-debugging-and-performance.md`

View File

@@ -0,0 +1,51 @@
# React Three Fiber Starter
Use this as the smallest canonical starting point for a React-hosted 3D scene.
## Files
```text
src/
App.tsx
```
## `src/App.tsx`
```tsx
import { Canvas } from "@react-three/fiber";
function Spinner() {
return (
<mesh rotation={[0.4, 0.6, 0]}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="#3dd9b8" />
</mesh>
);
}
export default function App() {
return (
<div className="app-shell">
<Canvas camera={{ position: [0, 1.5, 4], fov: 60 }}>
<color attach="background" args={["#101418"]} />
<ambientLight intensity={0.7} />
<directionalLight position={[4, 6, 3]} intensity={1.2} />
<Spinner />
</Canvas>
<div className="hud">
<div className="objective-chip">Reach the lantern bridge.</div>
<div className="hint-pill">WASD to move. Hold mouse to look.</div>
</div>
</div>
);
}
```
## Notes
- Start here when the 3D scene lives inside an existing React app.
- Keep the initial HUD sparse. One compact objective surface and one transient hint is usually enough for a first playable scaffold.
- Put lore, notes, map, and settings behind drawers or modals instead of opening them all by default.
- Add GLB loading with `gltf-loading-starter.md`.
- Add physics with `rapier-integration-starter.md`.
- Use `three-hud-layout-patterns.md` for low-chrome 3D overlay defaults.

View File

@@ -0,0 +1,57 @@
# Sprite Pipeline
This is the default 2D animation workflow for the plugin.
## Principles
- Start from one approved in-game frame.
- Generate the animation as one strip, not isolated frames.
- Normalize the whole strip with one shared scale.
- Use one shared anchor, typically bottom-center.
- Preview before approving the asset.
## Why this works
- The approved seed frame preserves identity.
- Strip-first generation reduces frame-to-frame drift.
- Shared-scale normalization prevents one tall pose from making the character feel smaller.
- Locking frame 01 back to the shipped sprite preserves continuity for idle-to-action transitions.
## Prompt template
```text
Intended use: candidate production spritesheet for a 2D browser game animation review.
Edit the provided transparent reference canvas into a single horizontal <N>-frame spritesheet.
The existing sprite in the leftmost slot is the anchor frame and must remain the same character:
- same facing direction
- same silhouette family
- same palette family
- same proportions
- same readable face or key features
- same outfit details
Composition:
- transparent canvas
- exactly one row of <N> equal frame slots
- no extra characters
- no labels
- no scenery
- no poster layout
Action:
- describe the specific animation beat from frame 1 through frame N
Style:
- authentic pixel-art production asset
- crisp pixel clusters
- restrained palette
- not concept art
```
## Normalization notes
- Use the union of detected sprite bounds per slot.
- Compute one scale from the largest detected frame and anchor.
- Bottom-align frames into the target canvas.
- Reuse the exact shipped frame for frame 01 when `--lock-frame1` is appropriate.

View File

@@ -0,0 +1,61 @@
# 3D HUD Layout Patterns
Use these defaults for initial 3D browser-game scaffolds. The first screen should be playable before it is informational.
## Layout Budget
- Keep the center of the screen clear during normal play.
- On desktop, prefer one primary persistent cluster and one small secondary cluster.
- On mobile, prefer one compact persistent cluster and transient prompts.
- Secondary information belongs in drawers, toggles, pause menus, or contextual popovers.
## Good Default Patterns
### Objective chip
- One short objective in a compact top-corner chip.
- One optional sublabel for location or mode.
- No giant hero banner over the live scene.
### Contextual interaction prompt
- Bottom-center or lower-corner pill.
- Appears only near interactables or during onboarding.
- Dismisses after first use or fades once the player is moving confidently.
### Small status strip
- Health, energy, party count, or beacon progress in a narrow edge-aligned strip.
- Use icons, short labels, and compact meters instead of stacked cards.
### Collapsible journal or quest log
- Closed by default.
- Opened by a hotkey, button, or pause state.
- Holds longer prose, lore, map notes, and multi-step objective details.
### Pause and settings modal
- Explicit modal state.
- Suspends pointer-lock, drag-look, or camera input while active.
## Anti-Patterns
- four to six glass cards permanently framing the viewport
- large lore or field-notes panels open during normal movement
- controls lists permanently pinned to the screen
- symmetric dashboard composition that competes with the scene
- oversized title panels staying visible after the first second of play
## Example UI Budget
- top-left: objective chip
- top-right: compact status strip
- bottom-center: transient interaction or controls hint
- pause menu or drawer: map, notes, inventory, settings
## Prompt Add-On
```text
Default to a low-chrome playable HUD. Keep the central playfield clear. Use one compact objective chip, one small status surface, and transient prompts. Put lore, field notes, full controls, and long checklists behind a drawer or pause menu. Avoid equal-weight boxed panels in every corner.
```

View File

@@ -0,0 +1,61 @@
# Three WebGL Architecture
This is the default 3D structure for the plugin.
## Recommended module split
```text
src/
game/
simulation/
content/
input/
save/
render/
app/
createRenderer.ts
createScene.ts
createCamera.ts
createLoop.ts
loaders/
loadGltf.ts
loadEnvironment.ts
loadTextures.ts
objects/
materials/
lights/
post/
adapters/
renderBridge.ts
physics/
world.ts
colliders.ts
sync.ts
diagnostics/
debugFlags.ts
perf.ts
ui/
hud/
menus/
overlays/
```
## Responsibilities
- `simulation/`: rules, state, AI, progression, save data
- `render/app/`: renderer, scene, camera, resize, context lifecycle
- `render/loaders/`: GLTF, compression, texture, and environment loading
- `render/objects/`: scene graph construction and disposal
- `render/materials/`: material setup and shader boundaries
- `physics/`: Rapier world and simulation bridge
- `diagnostics/`: performance probes and GPU debugging hooks
- `ui/`: DOM HUD and menus
## Rules
- Scene graph objects are not the source of truth for game rules.
- Keep camera logic explicit and testable.
- Handle resize and context-loss as real browser concerns.
- Keep high-density UI in DOM even when the world is fully 3D.
- Treat GLB or glTF 2.0 as the default content format.
- Add physics and diagnostics as real subsystems, not temporary one-off utilities.

View File

@@ -0,0 +1,41 @@
# Three.js Stack
This is the default non-React 3D runtime stack for the plugin.
## Primary components
- [Three.js documentation](https://threejs.org/docs/) for the core renderer, scene graph, materials, cameras, loaders, and examples.
- [Rapier JavaScript guide](https://rapier.rs/docs/user_guides/javascript/getting_started_js/) for physics integration.
- [glTF 2.0 specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html) for the default shipping asset format.
- [glTF Transform](https://gltf-transform.dev/) for optimization, packaging, and compression workflows.
- [SpectorJS](https://spector.babylonjs.com/) for WebGL frame capture and GPU debugging.
## Default stack choices
- Runtime: `three`
- Tooling: TypeScript + Vite
- Assets: GLB or glTF 2.0
- Loaders: `GLTFLoader`, `DRACOLoader`, `KTX2Loader` when the asset pipeline requires them
- Physics: Rapier JS
- UI: DOM overlays, not in-scene UI by default
## Choose this stack when
- the project is not React-first
- the team wants direct control over the render loop
- scene composition, loader setup, or custom render behavior needs imperative structure
- the game code should feel engine-like without a React abstraction layer
## Avoid this stack when
- the surrounding app is already React-heavy and wants shared declarative state
- the project needs an editor-first engine workflow more than a portable TypeScript runtime
## Companion references
- `three-webgl-architecture.md`
- `threejs-vanilla-starter.md`
- `gltf-loading-starter.md`
- `rapier-integration-starter.md`
- `web-3d-asset-pipeline.md`
- `webgl-debugging-and-performance.md`

View File

@@ -0,0 +1,58 @@
# Three.js Vanilla Starter
Use this as the smallest canonical starting point for a plain TypeScript or Vite Three.js app.
## Files
```text
src/
main.ts
```
## `src/main.ts`
```ts
import * as THREE from "three";
const scene = new THREE.Scene();
scene.background = new THREE.Color("#101418");
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 200);
camera.position.set(0, 1.5, 4);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
scene.add(new THREE.AmbientLight(0xffffff, 0.7));
const light = new THREE.DirectionalLight(0xffffff, 1.2);
light.position.set(4, 6, 3);
scene.add(light);
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: "#3dd9b8" }),
);
scene.add(mesh);
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
renderer.setAnimationLoop(() => {
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
});
```
## Notes
- Start here for direct loop and renderer control.
- If the scaffold needs UI, start with one compact objective chip and one transient controls hint rather than multiple permanent cards.
- Keep notes, codex, maps, and settings behind on-demand surfaces. The starter scene should stay readable while moving the camera.
- Add GLB loading with `gltf-loading-starter.md`.
- Add physics sync with `rapier-integration-starter.md`.
- Use `three-hud-layout-patterns.md` for low-chrome 3D overlay defaults.

View File

@@ -0,0 +1,47 @@
# Web 3D Asset Pipeline
This is the default 3D asset shipping guidance for the plugin.
## Primary sources
- [Blender glTF exporter manual](https://docs.blender.org/manual/en/latest/addons/import_export/scene_gltf2.html)
- [glTF 2.0 specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html)
- [glTF Transform](https://gltf-transform.dev/)
- [PlayCanvas supported formats](https://developer.playcanvas.com/user-manual/assets/supported-formats/) for a good reference on why GLB is the recommended runtime format in browser engines
## Default output
- Ship GLB when possible.
- Use `.gltf` with external files only when the asset pipeline or delivery strategy genuinely needs that shape.
## Recommended workflow
1. Clean the source asset in the DCC tool.
2. Export to GLB or glTF 2.0.
3. Run glTF Transform for validation, pruning, deduplication, and size reduction.
4. Apply the chosen geometry and texture compression strategy.
5. Verify pivots, scale, collision assumptions, and hierarchy naming.
6. Test the asset in the runtime before treating it as final.
## Compression and optimization
- Use Draco or Meshopt deliberately, not both by default.
- Use KTX2 or BasisU when the runtime stack supports GPU-friendly compressed textures.
- Keep texture resolution aligned with actual on-screen use.
- Reuse materials and avoid unnecessary texture uniqueness.
## Runtime checks
- scale is consistent across assets
- pivots match gameplay expectations
- node names are stable
- collision proxy needs are handled
- animation clips and variants load correctly
- memory and load time are reasonable for the scene
## Starter patterns
- `threejs-vanilla-starter.md`
- `react-three-fiber-starter.md`
- `gltf-loading-starter.md`
- `rapier-integration-starter.md`

View File

@@ -0,0 +1,36 @@
# WebGL Debugging and Performance
Use this reference when a browser 3D scene is visually wrong, unstable, or slower than expected.
## Primary tools
- [SpectorJS](https://spector.babylonjs.com/) for frame capture, pipeline inspection, draw-call review, and shader debugging.
- Browser performance tooling for main-thread work, asset decode stalls, and memory pressure.
- Engine-native debug views and stats surfaces where available.
## What to inspect first
- draw-call count
- shader compilation churn
- texture memory pressure
- geometry count and material count
- post-processing cost
- asset decode and streaming stalls
- WebGL context loss or fallback behavior
## Common causes of poor performance
- too many unique materials
- oversized textures
- heavy GLB assets loaded without optimization
- complex post-processing on top of an already expensive scene
- physics and render state fighting for ownership
- React and scene state updating each other too frequently in React-hosted 3D apps
## Debugging rules
- Capture first, then guess.
- Reduce the scene until the perf cliff becomes obvious.
- Disable post-processing before rewriting core scene code.
- Verify the asset pipeline before blaming the renderer.
- Treat context-loss handling as a browser requirement, not an edge case.

View File

@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Build a transparent edit canvas around a shipped seed sprite frame."""
from __future__ import annotations
import argparse
from pathlib import Path
try:
from PIL import Image
except ImportError as exc: # pragma: no cover
raise SystemExit(
"Pillow is required. Install it with `python3 -m pip install pillow`."
) from exc
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Upscale a seed sprite with nearest-neighbor sampling and place it into "
"the leftmost slot of a larger transparent edit canvas."
)
)
parser.add_argument("--seed", required=True, help="Path to the approved seed frame.")
parser.add_argument("--out", required=True, help="Path to the output PNG.")
parser.add_argument(
"--frames",
type=int,
default=4,
help="Number of horizontal frame slots to reserve. Default: 4.",
)
parser.add_argument(
"--slot-size",
type=int,
default=256,
help="Size of each square frame slot in pixels. Default: 256.",
)
parser.add_argument(
"--canvas-size",
type=int,
default=1024,
help="Size of the square transparent canvas in pixels. Default: 1024.",
)
return parser.parse_args()
def resize_seed(seed: Image.Image, slot_size: int) -> Image.Image:
max_dim = max(seed.size)
scale = slot_size / max_dim
if scale >= 1:
scale = max(1, int(scale))
width = max(1, int(round(seed.width * scale)))
height = max(1, int(round(seed.height * scale)))
return seed.resize((width, height), Image.Resampling.NEAREST)
def main() -> None:
args = parse_args()
if args.frames < 1:
raise SystemExit("--frames must be at least 1.")
if args.slot_size < 1 or args.canvas_size < 1:
raise SystemExit("--slot-size and --canvas-size must be positive.")
strip_width = args.frames * args.slot_size
if strip_width > args.canvas_size or args.slot_size > args.canvas_size:
raise SystemExit("Frame slots do not fit inside the requested canvas size.")
seed = Image.open(args.seed).convert("RGBA")
seed = resize_seed(seed, args.slot_size)
canvas = Image.new("RGBA", (args.canvas_size, args.canvas_size), (0, 0, 0, 0))
strip_left = (args.canvas_size - strip_width) // 2
strip_top = (args.canvas_size - args.slot_size) // 2
slot_left = strip_left
slot_top = strip_top
paste_x = slot_left + (args.slot_size - seed.width) // 2
paste_y = slot_top + (args.slot_size - seed.height) // 2
canvas.alpha_composite(seed, (paste_x, paste_y))
out_path = Path(args.out)
out_path.parent.mkdir(parents=True, exist_ok=True)
canvas.save(out_path)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""Normalize a raw animation strip into fixed-size transparent frames."""
from __future__ import annotations
import argparse
from pathlib import Path
from typing import Iterable
try:
from PIL import Image
except ImportError as exc: # pragma: no cover
raise SystemExit(
"Pillow is required. Install it with `python3 -m pip install pillow`."
) from exc
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Extract one horizontal strip into fixed-size frames using a shared "
"global scale and bottom-center alignment."
)
)
parser.add_argument("--input", required=True, help="Path to the raw strip image.")
parser.add_argument("--out-dir", required=True, help="Output directory for frames.")
parser.add_argument(
"--frames",
type=int,
required=True,
help="Number of horizontal frames in the strip.",
)
parser.add_argument(
"--frame-size",
type=int,
default=64,
help="Output square frame size in pixels. Default: 64.",
)
parser.add_argument(
"--anchor",
help="Optional anchor frame used to stabilize global scale and frame 01 output.",
)
parser.add_argument(
"--lock-frame1",
action="store_true",
help="Replace frame 01 with the provided anchor frame after normalization.",
)
parser.add_argument(
"--alpha-threshold",
type=int,
default=8,
help="Pixels with alpha above this threshold count as sprite content. Default: 8.",
)
return parser.parse_args()
def threshold_bbox(image: Image.Image, alpha_threshold: int) -> tuple[int, int, int, int] | None:
alpha = image.getchannel("A").point(lambda value: 255 if value > alpha_threshold else 0)
return alpha.getbbox()
def crop_to_content(image: Image.Image, alpha_threshold: int) -> Image.Image | None:
bbox = threshold_bbox(image, alpha_threshold)
if bbox is None:
return None
return image.crop(bbox)
def split_strip(strip: Image.Image, frames: int) -> list[Image.Image]:
if frames < 1:
raise ValueError("frames must be at least 1")
step = strip.width / frames
slots: list[Image.Image] = []
for index in range(frames):
left = int(round(index * step))
right = int(round((index + 1) * step))
slots.append(strip.crop((left, 0, right, strip.height)))
return slots
def max_content_size(images: Iterable[Image.Image | None]) -> tuple[int, int]:
widths: list[int] = []
heights: list[int] = []
for image in images:
if image is None:
continue
widths.append(image.width)
heights.append(image.height)
if not widths or not heights:
raise SystemExit("No sprite content was detected in the provided strip.")
return max(widths), max(heights)
def compose_frame(
image: Image.Image | None,
frame_size: int,
scale: float,
) -> Image.Image:
canvas = Image.new("RGBA", (frame_size, frame_size), (0, 0, 0, 0))
if image is None:
return canvas
width = max(1, int(round(image.width * scale)))
height = max(1, int(round(image.height * scale)))
resized = image.resize((width, height), Image.Resampling.NEAREST)
offset_x = (frame_size - width) // 2
offset_y = frame_size - height
canvas.alpha_composite(resized, (offset_x, offset_y))
return canvas
def load_anchor(path: str | None, alpha_threshold: int) -> tuple[Image.Image | None, Image.Image | None]:
if path is None:
return None, None
anchor = Image.open(path).convert("RGBA")
cropped = crop_to_content(anchor, alpha_threshold)
return anchor, cropped
def main() -> None:
args = parse_args()
if args.frames < 1:
raise SystemExit("--frames must be at least 1.")
if args.frame_size < 1:
raise SystemExit("--frame-size must be positive.")
if args.lock_frame1 and not args.anchor:
raise SystemExit("--lock-frame1 requires --anchor.")
strip = Image.open(args.input).convert("RGBA")
slots = split_strip(strip, args.frames)
contents = [crop_to_content(slot, args.alpha_threshold) for slot in slots]
anchor_image, anchor_content = load_anchor(args.anchor, args.alpha_threshold)
max_width, max_height = max_content_size([*contents, anchor_content])
scale = min(args.frame_size / max_width, args.frame_size / max_height)
out_dir = Path(args.out_dir)
out_dir.mkdir(parents=True, exist_ok=True)
for index, content in enumerate(contents, start=1):
if index == 1 and args.lock_frame1:
assert anchor_image is not None
if anchor_image.width == args.frame_size and anchor_image.height == args.frame_size:
frame = anchor_image
else:
frame = compose_frame(anchor_content, args.frame_size, scale)
else:
frame = compose_frame(content, args.frame_size, scale)
frame.save(out_dir / f"{index:02d}.png")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""Render a simple contact sheet from a directory of normalized sprite frames."""
from __future__ import annotations
import argparse
import math
import re
from pathlib import Path
try:
from PIL import Image, ImageDraw
except ImportError as exc: # pragma: no cover
raise SystemExit(
"Pillow is required. Install it with `python3 -m pip install pillow`."
) from exc
NUMBER_RE = re.compile(r"(\d+)")
def natural_key(path: Path) -> list[int | str]:
parts: list[int | str] = []
for chunk in NUMBER_RE.split(path.stem):
if not chunk:
continue
if chunk.isdigit():
parts.append(int(chunk))
else:
parts.append(chunk)
parts.append(path.suffix)
return parts
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Render a preview contact sheet from a directory of sprite frames."
)
parser.add_argument("--frames-dir", required=True, help="Directory containing PNG frames.")
parser.add_argument("--out", required=True, help="Output PNG path.")
parser.add_argument(
"--columns",
type=int,
default=4,
help="Number of columns in the preview sheet. Default: 4.",
)
parser.add_argument(
"--gap",
type=int,
default=8,
help="Gap between frames in pixels. Default: 8.",
)
return parser.parse_args()
def paint_checkerboard(image: Image.Image, tile: int = 16) -> None:
draw = ImageDraw.Draw(image)
colors = ((240, 243, 246, 255), (225, 230, 235, 255))
for top in range(0, image.height, tile):
for left in range(0, image.width, tile):
color = colors[((left // tile) + (top // tile)) % 2]
draw.rectangle((left, top, left + tile, top + tile), fill=color)
def main() -> None:
args = parse_args()
if args.columns < 1:
raise SystemExit("--columns must be at least 1.")
if args.gap < 0:
raise SystemExit("--gap cannot be negative.")
frame_dir = Path(args.frames_dir)
frames = sorted(frame_dir.glob("*.png"), key=natural_key)
if not frames:
raise SystemExit("No PNG frames were found in --frames-dir.")
images = [Image.open(path).convert("RGBA") for path in frames]
frame_width = max(image.width for image in images)
frame_height = max(image.height for image in images)
rows = math.ceil(len(images) / args.columns)
sheet_width = args.columns * frame_width + max(0, args.columns - 1) * args.gap
sheet_height = rows * frame_height + max(0, rows - 1) * args.gap
sheet = Image.new("RGBA", (sheet_width, sheet_height), (255, 255, 255, 255))
paint_checkerboard(sheet)
for index, image in enumerate(images):
row = index // args.columns
column = index % args.columns
left = column * (frame_width + args.gap) + (frame_width - image.width) // 2
top = row * (frame_height + args.gap) + (frame_height - image.height) // 2
sheet.alpha_composite(image, (left, top))
out_path = Path(args.out)
out_path.parent.mkdir(parents=True, exist_ok=True)
sheet.save(out_path)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,76 @@
---
name: game-playtest
description: Run browser-game playtests and frontend QA. Use when the user asks for smoke tests, screenshot-based verification, browser automation, HUD or overlay review, or structured issue-finding in a browser game.
---
# Game Playtest
## Overview
Use this skill to test browser games the way players experience them: through boot, input, scene transitions, HUD readability, and visual state changes. Prefer browser automation and screenshot review when the project supports it.
## Preferred Workflow
1. Boot the game and confirm the first actionable screen.
2. Exercise the main verbs.
3. Capture screenshots from representative states.
4. Check the UI layer independently from the render layer.
5. Report findings in severity order with reproduction steps.
## Tooling Guidance
- Prefer Playwright or equivalent browser automation already available in the repo.
- When the game is canvas or WebGL heavy, screenshots are mandatory because DOM assertions alone miss visual regressions.
- Use screenshots to judge playfield obstruction and HUD weight, not just correctness of text or layout.
- When deterministic automation is not practical, do a structured manual pass and capture evidence.
- For 3D rendering bugs or unexplained frame cost, use SpectorJS and browser performance tooling rather than guessing from code alone.
## Common Checks
### 2D checks
- sprite alignment and baseline consistency
- hit or hurt animation readability
- HUD overlap with the playfield
- command menu state changes
- tile or platform readability
- input-state feedback and turn-state clarity
### 3D checks
- first-load playability versus dashboard-like chrome
- persistent overlay weight versus playfield visibility
- camera control and camera reset behavior
- pointer-lock or drag-look transitions when menus and overlays open
- depth readability and silhouette clarity
- secondary panels collapsed or dismissible during normal play
- resize behavior
- WebGL context loss or renderer fallback behavior
- material or lighting regressions
- GLB or texture streaming stalls
- collision proxy or physics mismatch
- performance cliffs tied to post-processing or asset load
## Responsive and Browser Checks
- desktop and mobile viewport sanity
- safe-area and notch issues where relevant
- reduced-motion behavior for UI transitions
- keyboard, pointer, and pause-state handling
- React state and scene state synchronization when the project uses React Three Fiber
## Reporting Standard
Lead with findings. Keep each finding concrete:
- what the user sees
- how to reproduce it
- why it matters
- what likely subsystem owns it
## References
- Shared architecture: `../web-game-foundations/SKILL.md`
- Frontend review cues: `../game-ui-frontend/SKILL.md`
- 3D debugging notes: `../../references/webgl-debugging-and-performance.md`
- Full checklist: `../../references/playtest-checklist.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Game Playtest"
short_description: "Run browser-game playtests and QA"
default_prompt: "Playtest the browser game, check core interactions and visual state changes, and report concrete issues."

View File

@@ -0,0 +1,94 @@
---
name: game-studio
description: Route early browser-game work. Use when the user needs stack selection and workflow planning across design, implementation, assets, and playtesting before moving to a specialist skill.
---
# Game Studio
## Overview
Use this skill as the umbrella entrypoint for browser-game work. Default to a 2D Phaser path unless the user explicitly asks for 3D, Three.js, React Three Fiber, shader-heavy rendering, or another WebGL-first direction.
This plugin is intentionally asymmetric:
- 2D is the strongest execution path in v1.
- 3D has one opinionated default ecosystem: vanilla Three.js for plain TypeScript or Vite apps, React Three Fiber for React-hosted 3D apps, and GLB or glTF 2.0 as the default shipping asset format.
- Shared architecture, UI, and playtest practices apply to both.
## Use This Skill When
- the user is still choosing a stack
- the request spans multiple domains such as runtime, UI, asset pipeline, and QA
- the user says "help me build a game" without naming the implementation path
## Do Not Stay Here When
- the runtime is clearly plain Three.js
- the runtime is clearly React Three Fiber
- the task is clearly a shipped-asset problem
- the task is clearly frontend-only or QA-only
Once the intent is clear, route to the most specific specialist skill and continue from there.
## Routing Rules
1. Classify the request before designing or coding:
- `2D default`: Phaser, sprites, tilemaps, top-down, side-view, grid tactics, action platformers.
- `3D + plain TS/Vite`: imperative scene control, engine-like loops, non-React apps, direct Three.js work.
- `3D + React`: React-hosted product surfaces, declarative scene composition, shared React state, UI-heavy 3D apps.
- `3D asset pipeline`: GLB, glTF, texture packaging, compression, LOD, runtime asset size.
- `Alternative engine`: Babylon.js or PlayCanvas requests, usually as comparison or ecosystem fit questions.
- `Shared`: core loop design, frontend direction, save/debug/perf boundaries, browser QA.
2. Route to the specialist skills immediately after classification:
- Shared architecture and engine choice: `../web-game-foundations/SKILL.md`
- Deep 2D implementation: `../phaser-2d-game/SKILL.md`
- Vanilla Three.js implementation: `../three-webgl-game/SKILL.md`
- React-hosted 3D implementation: `../react-three-fiber-game/SKILL.md`
- 3D asset shipping and optimization: `../web-3d-asset-pipeline/SKILL.md`
- HUD and menu direction: `../game-ui-frontend/SKILL.md`
- 2D sprite generation and normalization: `../sprite-pipeline/SKILL.md`
- Browser QA and visual review: `../game-playtest/SKILL.md`
3. Keep one coherent plan across the routed skills. Do not let engine, UI, asset, and QA decisions drift apart.
## Default Workflow
1. Lock the game fantasy and player verbs.
2. Define the core loop, failure states, progression, and target play session length.
3. Choose the implementation track:
- Default to Phaser for 2D browser games.
- Choose vanilla Three.js when the project is explicitly 3D and wants direct render-loop control in a plain TypeScript or Vite app.
- Choose React Three Fiber when the project already lives in React or wants declarative scene composition with shared React state.
- Choose raw WebGL only when the user explicitly wants a custom renderer or shader-first surface.
4. Define the UI surface early. Browser games usually need a DOM HUD and menu layer even when the playfield is canvas or WebGL.
- For 3D starter scaffolds, default to a low-chrome HUD that preserves the playfield and keeps secondary panels collapsed.
5. Decide the asset workflow:
- 2D characters and effects: use `sprite-pipeline`.
- 3D models, textures, and shipping format: use `web-3d-asset-pipeline`.
6. Close with a playtest loop before calling the work production-ready.
## Output Expectations
- For planning requests, return a game-specific plan with stack choice, gameplay loop, UI surface, asset workflow, and test approach.
- For implementation requests, keep the chosen stack obvious in the file structure and code boundaries.
- For mixed requests, preserve the plugin default: 2D Phaser first unless the user asks for something else.
- When the user asks about Babylon.js or PlayCanvas, compare them honestly but keep Three.js and R3F as the primary code-generation defaults unless the user explicitly chooses another engine.
## References
- Engine selection: `../../references/engine-selection.md`
- Three.js stack: `../../references/threejs-stack.md`
- React Three Fiber stack: `../../references/react-three-fiber-stack.md`
- 3D asset pipeline: `../../references/web-3d-asset-pipeline.md`
- Vanilla Three.js starter: `../../references/threejs-vanilla-starter.md`
- React Three Fiber starter: `../../references/react-three-fiber-starter.md`
- Frontend prompting patterns: `../../references/frontend-prompts.md`
- Playtest checklist: `../../references/playtest-checklist.md`
## Examples
- "Help me prototype a browser tactics game."
- "I need a Phaser-based action game loop with a HUD and menus."
- "I want a Three.js exploration demo with WebGL lighting and browser-safe UI."
- "I want a React-based 3D configurator with React Three Fiber."
- "Optimize my GLB assets for the web and keep the file sizes under control."
- "Set up the asset workflow for consistent 2D sprite animations."

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Game Studio"
short_description: "Route browser-game work to the right path"
default_prompt: "Help me choose the right browser-game stack and workflow before implementation starts."

View File

@@ -0,0 +1,112 @@
---
name: game-ui-frontend
description: Design UI surfaces for browser games. Use when the user asks for HUDs, menus, overlays, responsive layouts, or visual direction that must protect the playfield.
---
# Game UI Frontend
## Overview
Use this skill whenever the game needs a visible interface layer. The job is not to produce generic dashboard UI. The job is to produce a readable, thematic browser-game interface that supports the play experience.
Default assumption: build the game world in canvas or WebGL, and build text-heavy UI in DOM.
## Frontend Standards
1. Establish visual direction before coding.
- Genre and fantasy
- Material language
- Typography
- Palette
- Motion tone
2. Use CSS variables for the UI theme.
3. Build clear hierarchy.
- Critical combat or survival information first
- Secondary tools second
- Rarely used settings behind menus or drawers
4. Protect the playfield first, especially in 3D.
- The initial screen should feel playable within a few seconds.
- Default to one primary persistent HUD cluster and at most one small secondary cluster.
- Keep the center of the playfield clear during normal play.
- Keep the lower-middle playfield mostly clear during normal play.
- Put lore, field notes, quest details, and long control lists behind drawers, toggles, or pause surfaces.
- Prefer contextual prompts and transient hints over permanent boxed panels.
5. Keep overlays readable over motion.
- Use backing panels, edge treatment, contrast, and restrained blur where needed.
6. Design for both desktop and mobile from the start.
7. Design 3D UI around camera and input control boundaries.
- Pause or gate camera-control input when menus, dialogs, or pointer-driven UI are active.
- Keep pointer-lock, drag-to-look, and menu interaction states explicit.
## 3D Starter Defaults
For exploration, traversal, or third-person starter scaffolds, prefer this UI budget:
- one compact objective chip or status strip at the edge
- one transient controls hint or interaction prompt
- one optional collapsible secondary surface such as a journal, map, or quest log
Do not open every informational surface on first load. The scene should be readable before the user opens any deeper UI.
As a default implementation constraint for 3D browser games:
- no always-on full-width header plus multi-card body plus full-width footer layout
- no large center-screen or lower-middle overlays during normal movement
- no more than roughly 20-25% of the viewport covered by persistent HUD on desktop unless the user explicitly requests a denser layout
- on mobile, collapse to a narrow stack or contextual chips before covering the playfield with larger panels
## Prompting Rules
When asking the model to design or implement game UI, include:
- the game fantasy
- the camera or viewpoint
- the player verbs
- the HUD layers
- the camera or control mode when the game is 3D
- the tone of motion
- desktop and mobile expectations
- playfield protection and disclosure strategy
- explicit anti-patterns to avoid
Use `../../references/frontend-prompts.md` for concrete prompt shapes.
## Motion Rules
- Prefer a few meaningful transitions over constant micro-animation.
- Reserve strong motion for state change, reward, danger, and onboarding.
- Respect reduced-motion settings for non-essential animation.
- Keep 3D HUD motion from competing with camera motion.
## What Good Looks Like
- HUD elements are legible without flattening the scene.
- Menus feel native to the game world, not like a SaaS admin panel.
- Layout adapts cleanly across breakpoints.
- Pointer, keyboard, and game-state feedback are obvious.
- In 3D games, menu and HUD states do not fight camera control or pointer-lock.
- In 3D games, the first playable view keeps most of the viewport available for movement, aiming, and spatial reading.
- Persistent information density is low enough that screenshots still read as game scenes, not UI comps.
## Anti-Patterns
- Generic app dashboard layouts
- Flat placeholder styling with no theme
- Default font stacks without intent
- Dense overlays that obscure the playfield
- Large title cards or multi-paragraph notes sitting over a live playable scene
- Equal-weight boxed panels distributed around every edge of the viewport
- Controls, objectives, notes, and lore all expanded at once on first load
- Full-width top-and-bottom chrome with large always-on center or body panels in 3D play
- Excessive motion on every element
- Canvas-only UI when DOM would be clearer and cheaper
- Forcing HUD controls into the 3D scene when standard DOM would be clearer
- Letting camera input remain active under modals or inventory panels
## References
- Shared architecture: `../web-game-foundations/SKILL.md`
- Prompt recipes: `../../references/frontend-prompts.md`
- Low-chrome 3D layout patterns: `../../references/three-hud-layout-patterns.md`
- React-hosted 3D UI context: `../react-three-fiber-game/SKILL.md`
- Playtest review: `../../references/playtest-checklist.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Game UI Frontend"
short_description: "Design browser-game HUDs, menus, and overlays"
default_prompt: "Design a browser-game UI layer that supports the play experience without crowding the playfield."

View File

@@ -0,0 +1,88 @@
---
name: phaser-2d-game
description: Implement 2D browser games with Phaser. Use when the user wants a Phaser, TypeScript, and Vite stack for scenes, gameplay systems, cameras, sprite animation, and DOM-overlay HUD patterns.
---
# Phaser 2D Game
## Overview
Use this skill for the main execution path in this plugin. Phaser is the default stack for 2D browser games here because it handles rendering, timing, sprites, cameras, and scene orchestration well without forcing gameplay rules into the framework.
Preferred stack:
- Phaser
- TypeScript
- Vite
- DOM-based HUD or menus layered over the game canvas
## Architecture
1. Keep gameplay state outside Phaser scenes.
- Systems own rules, turn order, movement, combat, inventory, objectives, and progression.
- Phaser scenes adapt system state into sprites, camera motion, animation playback, and effects.
2. Make scenes thin.
- Boot and asset preload
- Menu or shell scene
- Gameplay scene
- Optional overlay or debug scene
3. Keep renderer-facing objects disposable.
- Sprite containers, emitters, tweens, and camera rigs are view state, not source of truth.
4. Favor stable asset manifest keys over direct file-path references throughout gameplay code.
## Implementation Guidance
- Use one integration boundary where the scene reads simulation state and emits input actions back.
- Prefer deterministic system updates over scene-local mutation.
- Treat HUD and menus as DOM when text, status density, or responsiveness matter.
- Keep animation state derived from gameplay state rather than ad hoc sprite flags.
## 2D Modes Covered Well
- Turn-based grids and tactics
- Top-down exploration
- Side-view action platformers
- Character-action combat with sprite animation
- Lightweight management or deck-driven battle scenes
## Camera and Presentation
- Choose the camera model early: locked, follow, room-based, or tactical-pan.
- Keep camera logic separate from game rules.
- Use restrained screen shake, hit-stop, and parallax. Effects should improve readability, not obscure it.
## UI Integration
- Use DOM overlays for HUD, command menus, settings, and narrative panels.
- Keep the canvas responsible for the world, combat readability, and motion.
- Avoid shoving dense text or complex settings UIs into Phaser unless the project explicitly needs an in-canvas presentation.
## Asset Organization
- `characters/`
- `environment/`
- `ui/`
- `fx/`
- `audio/`
- `data/`
Keep manifest keys human-readable and stable.
## Default Directory Shape
See `../../references/phaser-architecture.md` for a concrete module split.
## Anti-Patterns
- Game rules inside `update()` loops without a system boundary
- Scene-to-scene state passed through mutable global objects
- HUD text rendered in the game canvas just because it is convenient
- Asset paths embedded everywhere instead of a manifest layer
- Overusing generic React dashboard patterns for game UI
## References
- Shared architecture: `../web-game-foundations/SKILL.md`
- Frontend direction: `../game-ui-frontend/SKILL.md`
- Sprite workflow: `../sprite-pipeline/SKILL.md`
- Phaser structure: `../../references/phaser-architecture.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Phaser 2D Game"
short_description: "Build 2D browser games with Phaser"
default_prompt: "Implement this 2D browser game with Phaser, TypeScript, and a clear gameplay architecture."

View File

@@ -0,0 +1,87 @@
---
name: react-three-fiber-game
description: Build React-hosted 3D browser games with React Three Fiber. Use when the user wants pmndrs-based scene composition, shared React state, and 3D HUD integration inside a React app.
---
# React Three Fiber Game
## Overview
Use this skill when the 3D runtime lives inside a React application. This is the default React-native 3D path in the plugin and should be preferred over vanilla Three.js when the app shell, settings, storefront, editor surface, or surrounding product already uses React.
Recommended stack:
- `@react-three/fiber`
- `three`
- `@react-three/drei`
- `@react-three/rapier`
- `@react-three/postprocessing`
- `@react-three/a11y` when accessibility-sensitive interaction matters
- DOM overlays in the normal React tree
## Use This Skill When
- the project already uses React
- the 3D scene must share state with the rest of the app
- declarative scene composition is a net gain
- the team wants pmndrs helpers instead of building every helper layer by hand
## Do Not Use This Skill When
- the app is not React-based
- the project wants a cleaner imperative runtime with minimal React coordination
- the problem is asset packaging rather than runtime composition
## Best Fit Scenarios
- 3D configurators and tool-rich browser products
- React apps with embedded game or scene surfaces
- 3D menus, editors, or world maps in an existing React app
- 3D game UIs that depend on shared app state and non-canvas shells
## Core Rules
1. Keep simulation state outside render components.
- React components should describe scene composition, not become the source of truth for gameplay rules.
2. Use React state and scene state deliberately.
- Shared UI state can live in app state.
- High-frequency simulation should not force the whole app through unnecessary React churn.
3. Use pmndrs helpers intentionally.
- Drei for controls, loaders, helpers, environments, and common scene primitives.
- `@react-three/rapier` for physics integration.
- `@react-three/postprocessing` for optional effects.
- `@react-three/a11y` when the interaction model benefits from accessible scene semantics.
4. Keep HUD, settings, and menus in DOM by default.
5. Keep starter scaffolds visually restrained.
- Start with one compact objective or status surface and transient prompts.
- Keep notes, maps, and multi-step checklists collapsed until opened.
- Do not surround the `Canvas` with equally weighted glass cards.
## Architectural Guidance
- Use a dedicated scene root component that owns the `Canvas`.
- Keep camera rigs and control components isolated from gameplay systems.
- Keep loader and asset wrappers predictable.
- Keep DOM overlays and the 3D scene coordinated through explicit state boundaries.
- If a system needs tight imperative control, isolate it rather than forcing everything into declarative patterns.
- If the scene is immediately playable, keep the initial overlay budget low and let the world do more of the onboarding.
## Anti-Patterns
- Treating React components as the gameplay state store
- Pushing heavy per-frame mutation through broad app state
- Using R3F only because React is available, even when the project needs a cleaner imperative runtime
- Building HUD or inventory UI inside the 3D scene by default
- Shipping an initial scaffold with large cards occupying every side of the viewport
## References
- Shared architecture: `../web-game-foundations/SKILL.md`
- Frontend direction: `../game-ui-frontend/SKILL.md`
- 3D HUD layout patterns: `../../references/three-hud-layout-patterns.md`
- React Three Fiber stack: `../../references/react-three-fiber-stack.md`
- React starter: `../../references/react-three-fiber-starter.md`
- GLB loader starter: `../../references/gltf-loading-starter.md`
- Rapier starter: `../../references/rapier-integration-starter.md`
- 3D asset pipeline: `../../references/web-3d-asset-pipeline.md`
- WebGL debugging and perf: `../../references/webgl-debugging-and-performance.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "React Three Fiber Game"
short_description: "Build React-hosted 3D browser games"
default_prompt: "Build this 3D browser game with React Three Fiber and keep the 3D runtime aligned with the React app shell."

View File

@@ -0,0 +1,102 @@
---
name: sprite-pipeline
description: Generate and normalize 2D sprite animations. Use when the user asks for full-strip generation from approved source frames, consistent anchor and scale normalization, or preview assets for browser-game animation.
---
# Sprite Pipeline
## Overview
Use this skill for 2D sprite generation and normalization. This workflow is intentionally anchored around one approved frame and a whole-strip generation pass because frame-by-frame generation drifts too easily.
This skill is 2D-specific. If the request is for 3D characters, meshes, or materials, route back through `../game-studio/SKILL.md`.
## Core Workflow
1. Start from an approved in-game seed frame.
- The seed frame should already reflect the right silhouette, palette, costume, and proportions.
2. Build a larger transparent reference canvas around that frame.
- Use `../../scripts/build_sprite_edit_canvas.py`.
3. Ask for the full animation strip in one edit request.
- Do not generate each frame independently unless the user explicitly accepts lower consistency.
4. Normalize the result into fixed-size game frames.
- Use `../../scripts/normalize_sprite_strip.py`.
- Use one shared scale across the whole strip.
- Align frames with one shared anchor, typically bottom-center.
5. Optionally lock frame 01 back to the shipped seed frame.
- Do this when the animation should begin from the exact idle or base pose already in game.
6. Render a preview sheet and inspect the animation in-engine before approving it.
- Use `../../scripts/render_sprite_preview_sheet.py`.
## Prompting Rules
Always preserve these invariants in the prompt:
- same character
- same facing direction
- same palette family
- same silhouette family
- same readable face or key features
- same outfit proportions
- transparent background
- exact frame count and slot layout
Always ask for:
- one strip at once
- a transparent canvas
- no scenery, labels, or poster composition
- crisp pixel-art clusters for pixel work
- production asset tone, not concept art
## Using Image Generation
For live asset generation or edits, use the installed `imagegen` skill in this workspace. This skill defines the game-specific process; `imagegen` handles the API-backed generation or edit execution.
## Script Recipes
Create a reference canvas:
```bash
python3 scripts/build_sprite_edit_canvas.py \
--seed output/sprites/idle-01.png \
--out output/sprites/hurt-edit-canvas.png \
--frames 4 \
--slot-size 256 \
--canvas-size 1024
```
Normalize a raw strip:
```bash
python3 scripts/normalize_sprite_strip.py \
--input output/sprites/hurt-raw.png \
--out-dir output/sprites/hurt \
--frames 4 \
--frame-size 64 \
--anchor output/sprites/idle-01.png \
--lock-frame1
```
Render a preview sheet:
```bash
python3 scripts/render_sprite_preview_sheet.py \
--frames-dir output/sprites/hurt \
--out output/sprites/hurt-preview.png \
--columns 4
```
## Quality Gates
- proportions stay stable across frames
- frame-to-frame size does not drift
- action reads clearly at game scale
- transparency is preserved
- frame 01 matches the shipped sprite when lockback is enabled
- preview looks correct before any in-engine asset index update
## References
- Detailed workflow: `../../references/sprite-pipeline.md`
- Shared frontend context: `../game-ui-frontend/SKILL.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Sprite Pipeline"
short_description: "Generate and normalize 2D sprite animations"
default_prompt: "Create and normalize 2D sprite animation assets for a browser game with consistent scale and anchors."

View File

@@ -0,0 +1,124 @@
---
name: three-webgl-game
description: Implement browser-game runtimes with plain Three.js. Use when the user wants imperative scene control in TypeScript or Vite with GLB assets, loaders, physics, and low-level WebGL debugging.
---
# Three WebGL Game
## Overview
Use this skill for the default non-React 3D path in the plugin. This is not generic WebGL advice. It is an opinionated stack for browser 3D work:
- `three`
- TypeScript
- Vite
- GLB or glTF 2.0 assets
- Three.js loaders such as `GLTFLoader`, `DRACOLoader`, and `KTX2Loader`
- Rapier JS for physics
- SpectorJS for GPU and frame debugging
- DOM overlays for HUD, menus, and settings
Use this skill when the project wants direct scene, camera, renderer, and game-loop control. If the app already lives in React, route to `../react-three-fiber-game/SKILL.md` instead.
## Use This Skill When
- the app is plain TypeScript or Vite rather than React-first
- the project wants direct imperative control over the render loop
- the user asks for Three.js specifically
- the runtime needs engine-like control over scene, camera, loaders, and physics
## Do Not Use This Skill When
- the 3D scene lives inside an existing React app
- the main problem is shipped-asset optimization rather than runtime code
- the user explicitly chose Babylon.js or PlayCanvas
## Core Rules
1. Keep simulation state outside Three.js objects.
- Game rules, AI, quest state, timers, and progression should not live inside meshes or materials.
2. Treat the render graph as an adapter.
- Scene graph, cameras, materials, loaders, and post-processing are view concerns layered over simulation state.
3. Keep camera behavior explicit.
- Orbit, follow, chase, rail, and first-person styles each need their own control boundary.
4. Keep UI out of WebGL unless the presentation absolutely depends on it.
- Menus, HUD, inventories, and settings should default to DOM.
5. Use GLB or glTF 2.0 as the default shipping model format.
- Do not build the runtime around DCC-native formats.
6. Use Rapier instead of ad hoc collision code when the game has meaningful 3D physics or collision response.
7. Keep the first playable view low-chrome.
- Default to one compact objective or status cluster plus transient prompts.
- Long notes, lore, and controls references should be collapsed until asked for.
- Do not frame the scene with multiple equal-weight cards during normal play.
## Initial Scaffold UX
For exploration, traversal, and character-control prototypes, start with a sparse shell:
- one edge-aligned objective chip
- one transient controls hint
- one optional compact status strip
Only add larger UI surfaces when the game loop truly requires them. Journal, quest log, codex, map, and settings surfaces should open on demand, not occupy the viewport by default.
## Recommended Structure
Use the module shape in `../../references/three-webgl-architecture.md`, then keep these boundaries clean:
- `simulation/`: rules, progression, state, and AI
- `render/app/`: renderer, scene, camera, resize, context lifecycle
- `render/loaders/`: GLTF, Draco, KTX2, texture, and environment loading
- `render/objects/`: mesh instantiation and disposal
- `render/materials/`: material setup and shader boundaries
- `physics/`: Rapier world, bodies, colliders, and simulation bridge
- `ui/`: DOM overlays and menus
- `diagnostics/`: debug toggles, perf probes, and capture hooks
## Good Fit Scenarios
- Exploration demos
- Lightweight 3D combat prototypes
- Vehicle or traversal prototypes
- Scene-driven product or world showcases with gameplay
- Material, lighting, or post-process-led experiences
- 3D games where camera movement and depth readability are central
## Loaders, Assets, and Post-Processing
- Start with `GLTFLoader` for shipped 3D content.
- Add `DRACOLoader` or Meshopt-compatible optimization as part of the asset pipeline, not as a random runtime patch.
- Use `KTX2Loader` for compressed textures when the asset pipeline provides them.
- Prefer built-in Three.js render and post-processing utilities first. Add heavier abstraction only when the project actually needs it.
- Keep post-processing optional and measurable. Bloom and color effects should not hide gameplay readability.
## Shader and Material Guidance
- Start with standard Three.js materials and correct lighting before reaching for custom shaders.
- Use custom shaders only when the visual target genuinely needs them.
- Keep shader parameters driven by game state, not by incidental scene mutations.
- If a material stack gets complex, isolate it behind material factories instead of scattering shader setup across scene code.
## Browser Safety
- Handle resize explicitly.
- Expect WebGL context loss and recovery.
- Keep a fallback or degraded mode in mind for fragile GPU paths.
- Watch texture size, geometry count, draw-call growth, and post-processing cost.
- Use SpectorJS when the scene behaves incorrectly or frame cost is unclear.
## Scope Warning
Do not claim that this plugin offers equal 3D depth to the Phaser track. It supports serious 3D implementation, but the plugin is still 2D-first overall.
## References
- Shared architecture: `../web-game-foundations/SKILL.md`
- Frontend direction: `../game-ui-frontend/SKILL.md`
- 3D HUD layout patterns: `../../references/three-hud-layout-patterns.md`
- Three.js ecosystem: `../../references/threejs-stack.md`
- Three.js structure: `../../references/three-webgl-architecture.md`
- Vanilla starter: `../../references/threejs-vanilla-starter.md`
- GLB loader starter: `../../references/gltf-loading-starter.md`
- Rapier starter: `../../references/rapier-integration-starter.md`
- 3D asset pipeline: `../../references/web-3d-asset-pipeline.md`
- WebGL debugging and perf: `../../references/webgl-debugging-and-performance.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Three WebGL Game"
short_description: "Build browser-game runtimes with Three.js"
default_prompt: "Implement this browser-game runtime with plain Three.js and keep the scene architecture easy to debug."

View File

@@ -0,0 +1,78 @@
---
name: web-3d-asset-pipeline
description: Prepare and optimize browser-game 3D assets. Use when the user asks for GLB or glTF shipping work, including Blender cleanup and export, collision or LOD setup, compression, texture packaging, and runtime validation.
---
# Web 3D Asset Pipeline
## Overview
Use this skill for shipped 3D assets, not runtime scene code. The default output format for browser 3D work in this plugin is GLB or glTF 2.0. The goal is predictable runtime assets, not whatever the DCC tool happened to export first.
This guidance is engine-agnostic and can serve Three.js, React Three Fiber, Babylon.js, or PlayCanvas.
## Use This Skill When
- the task is about GLB or glTF shipping format
- the task is about model cleanup, texture packaging, compression, LOD, or collision proxies
- the runtime stack is already chosen and the remaining problem is asset quality or size
## Do Not Use This Skill When
- the task is about scene, camera, renderer, or game-loop structure
- the task is purely about React versus vanilla Three.js routing
- the user is still deciding between runtime engines
## Default Pipeline
1. Author and clean the source asset in a DCC tool such as Blender.
2. Export to GLB or glTF 2.0.
3. Optimize with glTF Transform.
4. Validate naming, pivots, transforms, material reuse, and texture budgets.
5. Add collision proxies, LOD strategy, and baked-lighting assumptions as needed.
6. Ship the optimized asset and load it with engine-native GLTF support.
## Format Rules
- Default shipping format: GLB or glTF 2.0.
- Do not treat FBX, OBJ, or DCC-native formats as the long-term runtime contract.
- Apply or normalize transforms before shipping.
- Keep units, pivots, and orientation conventions consistent across the whole asset set.
## Optimization Rules
- Use glTF Transform for pruning, deduplication, simplification, and packaging.
- Use geometry compression intentionally.
- Draco is a valid option when decode cost and compatibility fit the runtime.
- Meshopt is often a strong default for web delivery.
- Compress textures deliberately.
- Use KTX2 or BasisU when the runtime stack supports it.
- Use WebP or AVIF where they make sense in the broader asset pipeline.
- Reuse materials and textures where possible to cut memory and draw-call cost.
## Runtime-Ready Asset Rules
- Keep model hierarchy names stable and meaningful.
- Set pivots and origins for gameplay interaction, not just for DCC convenience.
- Author explicit collision proxies for physics-heavy scenes.
- Decide whether lighting is dynamic, baked, or hybrid before final export.
- Plan LODs for large environments or repeated props.
- Keep texture resolution proportional to on-screen use, not source-art ambition.
## Common Failure Modes
- Shipping raw DCC exports without cleanup
- Too many unique materials
- Texture sizes far above visible need
- Missing collision proxies
- Scale or pivot mismatches between assets
- Runtime code compensating for asset mistakes that should be fixed upstream
## References
- Three.js stack: `../../references/threejs-stack.md`
- React Three Fiber stack: `../../references/react-three-fiber-stack.md`
- GLB loader starter: `../../references/gltf-loading-starter.md`
- Rapier starter: `../../references/rapier-integration-starter.md`
- 3D asset pipeline reference: `../../references/web-3d-asset-pipeline.md`
- Alternative engines: `../../references/alternative-3d-engines.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Web 3D Asset Pipeline"
short_description: "Prepare and optimize browser-game 3D assets"
default_prompt: "Prepare these browser-game 3D assets for shipping as predictable runtime-ready GLB or glTF files."

View File

@@ -0,0 +1,95 @@
---
name: web-game-foundations
description: Set browser-game architecture before implementation. Use when the user needs engine choice, simulation and render boundaries, input model, asset organization, or save/debug/performance strategy.
---
# Web Game Foundations
## Overview
Use this skill to establish the non-negotiable architecture before implementation starts. Browser games degrade quickly when simulation, rendering, UI, asset loading, and input handling are mixed together.
Default rule: simulation state is owned outside the renderer, browser UI is not forced into the canvas unless there is a clear reason, and shipped 3D assets default to GLB or glTF 2.0 rather than ad hoc model formats.
## Use This Skill When
- the user has not settled the engine or renderer choice
- the task is about boundaries, module shape, state ownership, or asset policy
- multiple specialist skills need one shared architectural frame
## Do Not Stay Here When
- the runtime track is clearly Phaser
- the runtime track is clearly vanilla Three.js
- the runtime track is clearly React Three Fiber
- the task is purely about shipped 3D assets
Once the stack is clear, hand off to the runtime or asset specialist skill.
## Architecture Rules
1. Separate simulation from rendering.
- Simulation owns entities, turns, timers, collisions, progression, and saveable state.
- The renderer owns scene composition, animation playback, camera, particles, and input plumbing.
2. Keep input mapping explicit.
- Define actions such as `move`, `confirm`, `cancel`, `ability-1`, and `pause`.
- Map physical inputs to actions in one place.
3. Treat asset loading as a first-class system.
- Use stable manifest keys.
- Group by domain: characters, environment, UI, audio, FX.
- For 3D content, standardize on GLB or glTF 2.0 unless the chosen engine ecosystem requires another format upstream.
4. Define save/debug/perf boundaries up front.
- Save serializable simulation state, not renderer objects.
- Keep debug overlays and perf probes easy to toggle.
5. Use DOM overlays for menus and HUD by default.
- Canvas or WebGL should handle the playfield.
- DOM should handle text-heavy HUD, menus, settings, and accessibility-sensitive controls.
- In 3D, keep the persistent UI budget small so the scene stays readable and interactive.
6. Lock 3D runtime conventions early.
- Choose consistent units, origins, pivots, and naming conventions.
- Decide how collision proxies, LODs, and baked lighting data are authored before runtime integration starts.
## Engine Selection
- Default to Phaser for 2D games with sprites, tilemaps, top-down or side-view action, turn-based grids, and classic browser arcade flows.
- Default to vanilla Three.js for explicit 3D scenes that want direct scene, camera, renderer, and loop control in plain TypeScript or Vite.
- Default to React Three Fiber when the 3D scene lives inside a React application and needs declarative composition, shared app state, or React-first UI coordination.
- Use raw WebGL only for shader-heavy or renderer-first projects where engine abstractions would get in the way.
- Keep Babylon.js and PlayCanvas as alternative-engine paths rather than the default code-generation target.
See `../../references/engine-selection.md` for the default decision table.
## Implementation Checklist
Define these before writing core code:
- Player fantasy and primary verbs
- Core loop and loss or reset states
- Camera model
- Input action map
- Simulation modules
- Renderer modules
- Asset manifest layout
- 3D asset format and optimization rules
- HUD and menu surfaces
- Save data boundary
- Debug and perf surfaces
## Anti-Patterns
- Mixing gameplay rules directly into scene callbacks
- Treating the renderer as the source of truth for game state
- Putting all HUD and menu UI into the canvas by default
- Letting asset filenames become the public API instead of manifest keys
- Shipping unoptimized 3D assets straight from the DCC tool into the browser
- Mixing camera-control state and menu or modal state without an explicit input boundary
- Rebuilding architecture every time the game changes genre
## References
- Engine selection: `../../references/engine-selection.md`
- Phaser structure: `../../references/phaser-architecture.md`
- Three.js structure: `../../references/three-webgl-architecture.md`
- Three.js ecosystem stack: `../../references/threejs-stack.md`
- React Three Fiber stack: `../../references/react-three-fiber-stack.md`
- 3D asset shipping: `../../references/web-3d-asset-pipeline.md`

View File

@@ -0,0 +1,4 @@
interface:
display_name: "Web Game Foundations"
short_description: "Set browser-game architecture before implementation"
default_prompt: "Establish the core architecture for this browser game before implementation starts."