- name
- demo-builder
- description
- Automatically generate playable game demos from concept documents. Parses game designs, creates Three.js prototypes with scoring, characters, textures, and music. Transforms ideas into interactive experiences.
# Demo Builder Skill
## Purpose
This skill automatically generates playable game prototypes from game concept documents. It:
- **Parses concept documents** to extract game mechanics, theme, genre
- **Generates Three.js game code** using the threejs-game skill
- **Creates first playable level** with scoring, objectives, characters
- **Generates assets** (textures, colors, basic models)
- **Integrates music** (Suno AI generation or 8-bit MIDI)
- **Produces web-ready demo** that runs in browser
**Output**: Fully functional game demo with HTML/JS/CSS that can be played immediately.
## When to Use This Skill
Use this skill when you have:
- ✅ Game concept document (from brainstorming/design phases)
- ✅ Need to validate gameplay quickly with playable prototype
- ✅ Want to pitch game with interactive demo vs. static mockups
- ✅ Require rapid prototyping for playtesting
- ✅ Need proof-of-concept before full development investment
## Prerequisites
### Required Input
**Game Concept Document** (from brainstorming or design)
- Location: `/docs/*-game-concepts-*.md` or `/docs/plans/*-design.md`
- Must include: Title, description, genre, core mechanics, theme
- Example: `fps-game-concepts-market-driven-2025-10-26.md`
### Dependencies
- **threejs-game skill** (for 3D game implementation)
- Three.js library (loaded via CDN in generated HTML)
- Optional: Suno API key for music generation (can use MIDI fallback)
## Core Workflow
### Phase 1: Concept Parsing
**1. Load Game Concept**
```javascript
GameConcept = {
title: string,
description: string,
genre: string[], // ["FPS", "Extraction", "Co-op"]
theme: string, // "cyberpunk", "military", "horror", etc.
core_mechanics: string[],
target_persona: string,
price_point: number | "F2P"
}
```
**2. Extract Demo Requirements**
```javascript
DemoRequirements = {
game_type: "FPS" | "third-person" | "top-down" | "side-scroller",
camera_type: "first-person" | "third-person" | "fixed" | "isometric",
movement_type: "WASD" | "mouse" | "touch" | "hybrid",
primary_mechanic: "shooting" | "extraction" | "survival" | "puzzle",
color_palette: extractColorPalette(theme),
character_archetypes: extractCharacters(description),
objectives: extractObjectives(description),
music_style: extractMusicStyle(genre, theme)
}
```
### Phase 2: Demo Architecture Design
**3. Generate Demo Specifications**
Based on genre/mechanics, create demo spec:
**FPS Demo Template:**
```javascript
{
level: {
type: "arena" | "corridor" | "open-world-section",
size: {x: 100, y: 50, z: 100},
geometry: "modular" // Can be expanded
},
player: {
type: "fps-controller",
spawn: {x: 0, y: 2, z: 0},
health: 100,
weapons: ["basic_rifle"],
movement_speed: 5,
look_sensitivity: 0.002
},
enemies: [
{type: "basic_enemy", count: 5, spawn_pattern: "random"},
{type: "patrol_enemy", count: 3, patrol_routes: [[...]]}
],
objectives: [
{type: "eliminate_targets", target_count: 5, points: 100},
{type: "survive_time", duration: 60, points: 50},
{type: "collect_items", item_count: 3, points: 150}
],
scoring: {
enemy_kill: 20,
item_collect: 50,
time_bonus: 1 // per second survived
},
ui: {
hud: ["health", "ammo", "score", "timer"],
crosshair: true,
minimap: false
}
}
```
**Extraction Shooter Demo Template:**
```javascript
{
level: {
type: "extraction-zone",
zones: ["hot_zone", "neutral", "extract_point"],
size: {x: 80, y: 30, z: 80}
},
player: {
type: "tactical-controller",
inventory_slots: 8,
health: 100,
stamina: 100
},
loot: [
{type: "resource", count: 10, value: 10},
{type: "rare_item", count: 3, value: 50}
],
enemies: {
type: "AI_guards",
difficulty: "medium",
count: 4
},
objectives: [
{type: "extract_with_loot", min_value: 100, points: 200},
{type: "extract_alive", points: 100}
],
extraction_point: {x: 70, y: 1, z: 70},
time_limit: 180 // 3 minutes
}
```
### Phase 3: Asset Generation
**4. Generate Color Palettes**
```javascript
function generateColorPalette(theme) {
const palettes = {
"cyberpunk": {
primary: 0x00ffff, // Cyan
secondary: 0xff00ff, // Magenta
accent: 0xffff00, // Yellow
environment: 0x1a1a2e, // Dark blue-gray
enemy: 0xff0080 // Pink
},
"military": {
primary: 0x4a6741, // Olive green
secondary: 0x8b7355, // Tan
accent: 0xff6b35, // Orange
environment: 0x5a6650, // Gray-green
enemy: 0xb71c1c // Red
},
"horror": {
primary: 0x1b1b1b, // Almost black
secondary: 0x8b0000, // Dark red
accent: 0xffffff, // White
environment: 0x2d2d2d, // Dark gray
enemy: 0x4a0e0e // Blood red
},
"space/sci-fi": {
primary: 0x0a2e4a, // Deep blue
secondary: 0x2a9d8f, // Teal
accent: 0xe76f51, // Orange-red
environment: 0x000814, // Space black
enemy: 0xf72585 // Bright pink
}
};
return palettes[theme] || palettes["military"];
}
```
**5. Generate Textures (Procedural)**
```javascript
function generateTexture(type, color, size = 512) {
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');
if (type === "floor") {
// Grid pattern
ctx.fillStyle = `#${color.toString(16).padStart(6, '0')}`;
ctx.fillRect(0, 0, size, size);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 2;
for (let i = 0; i < size; i += size / 8) {
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i, size);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, i);
ctx.lineTo(size, i);
ctx.stroke();
}
} else if (type === "wall") {
// Brick/panel pattern
ctx.fillStyle = `#${color.toString(16).padStart(6, '0')}`;
ctx.fillRect(0, 0, size, size);
// Add panel lines
const lighterColor = Math.min(color + 0x202020, 0xffffff);
ctx.strokeStyle = `#${lighterColor.toString(16).padStart(6, '0')}`;
ctx.lineWidth = 3;
for (let i = 0; i < size; i += size / 4) {
ctx.strokeRect(i, 0, size / 4, size);
}
}
return new THREE.CanvasTexture(canvas);
}
```
**6. Generate Characters (Geometric)**
```javascript
function generateCharacter(type, color) {
const group = new THREE.Group();
if (type === "player") {
// Simple capsule body
const body = new THREE.Mesh(
new THREE.CapsuleGeometry(0.5, 1.5, 4, 8),
new THREE.MeshPhongMaterial({ color: color })
);
body.position.y = 1;
group.add(body);
// Weapon (for FPS)
const weapon = new THREE.Mesh(
new THREE.BoxGeometry(0.1, 0.1, 0.8),
new THREE.MeshPhongMaterial({ color: 0x333333 })
);
weapon.position.set(0.3, 0.8, -0.5);
group.add(weapon);
} else if (type === "enemy") {
// Hostile NPC
const body = new THREE.Mesh(
new THREE.BoxGeometry(0.8, 1.6, 0.6),
new THREE.MeshPhongMaterial({ color: color })
);
body.position.y = 0.8;
group.add(body);
// Enemy marker (head)
const head = new THREE.Mesh(
new THREE.SphereGeometry(0.3, 8, 8),
new THREE.MeshPhongMaterial({ color: 0xff0000, emissive: 0x330000 })
);
head.position.y = 2;
group.add(head);
}
return group;
}
```
### Phase 4: Music Generation
**7. Generate Music (Suno AI or MIDI)**
```javascript
async function generateMusic(style, concept_name) {
// Option 1: Suno API (if API key available)
if (SUNO_API_KEY) {
const prompt = generateMusicPrompt(style, concept_name);
const musicUrl = await callSunoAPI(prompt);
return musicUrl;
}
// Option 2: 8-bit MIDI fallback
return generate8BitMIDI(style);
}
function generateMusicPrompt(style, concept_name) {
const prompts = {
"fps": `Epic action game music, intense electronic beats, military drums, adrenaline pumping, 140 BPM, game soundtrack, ${concept_name} theme`,
"horror": `Dark atmospheric horror game music, eerie synths, unsettling ambience, tension building, 80 BPM, survival horror soundtrack`,
"cyberpunk": `Synthwave cyberpunk game music, neon aesthetic, retro futuristic, energetic, 130 BPM, electronic game soundtrack`,
"tactical": `Tactical stealth game music, suspenseful, orchestral strings, slow build tension, 90 BPM, espionage theme`,
"roguelike": `Retro roguelike dungeon music, chiptune style, 8-bit adventure, upbeat tempo, 120 BPM, classic game feel`
};
return prompts[style] || prompts["fps"];
}
function generate8BitMIDI(style) {
// Generate simple 8-bit style music pattern
// Using Web Audio API for procedural chiptune
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const patterns = {
fps: {
tempo: 140,
notes: ["C4", "E4", "G4", "C5", "G4", "E4"], // Energetic pattern
rhythm: [0.25, 0.25, 0.5, 0.25, 0.25, 0.5]
},
ambient: {
tempo: 80,
notes: ["C3", "E3", "G3", "B3", "G3", "E3"], // Slower, eerie
rhythm: [1, 1, 0.5, 0.5, 1, 1]
}
};
return createChiptuneLoop(audioCtx, patterns[style] || patterns.fps);
}
```
### Phase 5: Game Code Generation
**8. Generate Complete Game Files**
Using threejs-game skill, generate:
**index.html:**
```html
<!DOCTYPE html>
<html>
<head>
<title>[Game Title] - Demo</title>
<style>
body { margin: 0; overflow: hidden; font-family: Arial, sans-serif; }
canvas { display: block; }
#hud {
position: absolute;
top: 20px;
left: 20px;
color: white;
font-size: 20px;
text-shadow: 2px 2px 4px #000;
pointer-events: none;
z-index: 100;
}
#crosshair {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 20px;
height: 20px;
border: 2px solid white;
border-radius: 50%;
pointer-events: none;
}
#instructions {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.8);
color: white;
padding: 40px;
text-align: center;
border-radius: 10px;
}
.hidden { display: none !important; }
</style>
</head>
<body>
<div id="hud">
<div>Health: <span id="health">100</span></div>
<div>Score: <span id="score">0</span></div>
Auf GitHub ansehen