Skip to content
VibeFather
Sign up free

2 cases built from this template

Same prompt, different [VARIABLES]. Click one to preview it above.

About this template

Space Dogfight Arcade Game is a single-page browser flight game in a closed asteroid field. The first screen is the field itself: a low-poly fighter already sits in a third-person chase view, with a dark glass card beside it naming the squadron, the sector, and the controls. Launching starts the patrol. The player steers, fires pale ice bolts, holds a lock until one homing missile leaves, boosts on a visible cooldown, and rolls for a short shield shimmer. Drones arrive in numbered waves that add a few craft and a little speed, with a pause between waves. At zero shields the run ends, and the retry card shows the wave reached.

The field is near-black, the rock is flat-shaded cold gray, and amber is reserved for the lock ring, the missile, and the boost cue. The fighter is a stubby code-built dart with one spine fin and two fixed canards. Drones are diamond hulls with a thin equatorial ring. A glass overlay carries a regenerating shield bar, a circular radar with the player at the center, and the wave counter. Destroyed craft break into short ice and amber squares. Desktop uses the pointer and the keyboard. A phone uses a stick plus boost, roll, fire, and lock. Small screens draw fewer asteroids and particles. Reduced motion drops camera shake and shortens the bursts. Tones are synthesized after the launch click, and every mesh is drawn in code.

Developers and indie hackers can change six variables: squadron, call sign, sector, drone name, craft name, and who the patrol is for. On-screen sentences follow those words. Speeds, colors, wave sizes, and the HUD stay put, so a second naming keeps the same patrol.

The template prompt

The live demo was built from exactly this text — nothing added. The other cases only change the values of the [VARIABLES].

# Space Dogfight Arcade Game

Build this website exactly as described below. Replace the [VARIABLES] with your own values; keep everything else.

## Brief
Build [BRAND], a single-page third-person arcade patrol through the bounded asteroid volume [SECTOR]. The default call sign is [CALLSIGN], the only enemies are the [FOE], and the fighter type is [CRAFT]. The first screen is the lit field with the code-built fighter already in a chase view and a dark glass title card beside it, plus a short control legend. The player steers, fires pale ice bolts, holds a lock to send one homing missile, boosts on a cooldown, and rolls for a brief shield shimmer. Numbered waves add a few drones and a little speed, with a short breather between them. The run ends only when the player shield hits zero, on a retry card that names the wave reached. Default audience line: [AUDIENCE].

- Audience: Developers and indie hackers who want a finished static three.js flight game, playable with a keyboard and pointer on a desk and with a thumb stick on a phone, and retitled from variables without changing the flight model.
- Goal: Ship one replayable patrol: a title card over a living asteroid field, a chase camera, boost, roll, bolts, a lock-on missile, a regenerating shield, a circular radar, a wave counter, on-screen flight controls, synthesized tones, and a retry card. A second set of names must keep the same speeds, colors, silhouettes, and HUD.
- Tone: Calm, short, and operational, like a dispatcher. US English. No movie-trailer voice and no slogans from existing games.

## Stack
- Framework: Vite 5 + TypeScript + three.js
- Styling: Tailwind CSS 3.4
- Libraries: three (MIT), tailwindcss (MIT), @fontsource/oxanium (OFL), @fontsource/source-sans-3 (OFL), @fontsource/ibm-plex-mono (OFL)
- Build: `npm run build` → static files in `dist/`. No backend, no server code, no external APIs.
- Setup:
  - Scaffold a Vite 5 vanilla TypeScript app. package.json scripts: dev=vite, build=vite build, preview=vite preview. Do not run tsc as part of the build. Install [email protected] (or any later 0.x, MIT), [email protected], postcss, and autoprefixer as needed, plus @fontsource/oxanium, @fontsource/source-sans-3, and @fontsource/ibm-plex-mono. Dev dependencies: vite@5, typescript@5, @types/three. Do not install React, a physics engine, postprocessing, or anything from three/examples.
  - vite.config.ts sets base to './', build.outDir to dist, build.emptyOutDir to true, and build.sourcemap to false. The build is minified. Do not copy src/ into dist/. tsconfig uses strict, noEmit, moduleResolution bundler, and target ES2022.
  - Tailwind 3.4, not v4. tailwind.config.js content is ./index.html and ./src/**/*.ts. Extend fontFamily display to Oxanium, body to Source Sans 3, mono to IBM Plex Mono. Extend colors void #07080C, paper #E7ECF2, dim #9AA3AE, amber #E8A23A, ice #8FCBE3, ink #141820. src/style.css contains the three Tailwind layers and sets html, body, and #ui to height 100%, margin 0, background #07080C, overflow hidden. Write every class as a complete string in index.html. Do not build class names by concatenation. The hidden utility must appear in the HTML source.
  - Import only @fontsource/oxanium/500.css, @fontsource/oxanium/600.css, @fontsource/source-sans-3/400.css, @fontsource/source-sans-3/600.css, and @fontsource/ibm-plex-mono/400.css from src/main.ts. Files are index.html, src/main.ts, src/content.ts, src/tuning.ts, src/audio.ts, src/game.ts, src/style.css, public/favicon.svg, and ASSETS.md.
  - src/content.ts exports BRAND, CALLSIGN, SECTOR, FOE, CRAFT, and AUDIENCE plus every on-screen string. src/tuning.ts exports the gameplay numbers below and nothing else owns those numbers. src/game.ts builds meshes and steps the simulation. src/main.ts owns the renderer, the resize, the rAF loop, input, and DOM updates. src/audio.ts owns Web Audio.
  - All on-screen sentences are functions of the variables. Defaults render as: eyebrow HARROW REACH; heading Cinder Patrol; deck Patrol Harrow Reach. Scatter the Glass Moths.; audience A short patrol for night-shift pilots.; meta Craft Lark · Call sign Kestrel; retry sub The Glass Moths still hold Harrow Reach. When a variable changes, rewrite those sentences and leave the meshes, speeds, and colors alone. document.title is BRAND. Do not print raw tokens.
  - Use one mulberry32 helper. Asteroids use seed 0x0D165607. Stars use seed 0x57A12. Bursts use seed 0xB4757 + wave * 13 + kind. Do not call Math.random. Clamp each frame dt to 0.033. If document.hidden, skip the step and discard the next delta. Suspend audio while hidden.
  - Gameplay constants in src/tuning.ts: SPHERE 148, WARN 140, RELEASE 136, CRUISE 34, BOOST_SPEED 70, BOOST_TIME 0.75, BOOST_CD 2.4, YAW_RATE 1.35, PITCH_RATE 1.05, PITCH_LIMIT 1.05, ROLL_TIME 0.6, SHIMMER 0.4, ROLL_GAP 0.45, BANK 0.38, SHIELD_MAX 100, PLAYER_BOLT_DAMAGE 16, DRONE_BOLT_DAMAGE 18, REGEN_DELAY 1.6, REGEN_RATE 12, HIT_INVULN 0.35, BOLT_SPEED 130, BOLT_INTERVAL 0.13, BOLT_LIFE 1.15, BOLT_CAP 16, LOCK_MIN 8, LOCK_MAX 78, LOCK_CONE_DEG 16, LOCK_TIME 0.65, LOCK_CD 0.4, MISSILE_SPEED 92, MISSILE_TURN 2.2, MISSILE_LIFE 3.4, DRONE_SHIELD 32, DRONE_TURN 0.85, DRONE_FIRE_RANGE 62, DRONE_FIRE_CONE_DEG 12, DRONE_FIRE_CD 1.7, DRONE_BOLT_SPEED 78, SEPARATION 7, BREATHER 2.8, SPAWN_RADIUS 96. Wave count is min(3 + (n - 1) * 2, 9). Drone speed is min(16 * pow(1.06, n - 1), 42). n starts at 1.
  - Before the first presented frame, build the scene, place the fighter in the title pose, snap the camera, and render once so the title card opens over a lit field. If WebGL fails, show the fallback sentence in the card, disable Launch patrol, and do not retry in a loop.

## Variables
- [BRAND] — Squadron name (default: "Cinder Patrol"). Invented two-word squadron name. Never an existing game, studio, ship, or product.
- [CALLSIGN] — Pilot call sign (default: "Kestrel"). One invented word. Not a known pilot, character, or franchise call sign.
- [SECTOR] — Patrol sector (default: "Harrow Reach"). Invented two-word place name used in the deck and the retry line.
- [FOE] — Drone name (default: "Glass Moths"). A plural invented drone name of two words, so 'Scatter the [FOE]' and 'The [FOE] still hold [SECTOR]' stay grammatical.
- [CRAFT] — Fighter type (default: "Lark"). One invented word for the fighter type. The mesh does not change with this word.
- [AUDIENCE] — Who it is for (default: "A short patrol for night-shift pilots."). One short sentence shown under the deck. Keep the same role in a second naming.
- [CREDIT] — keep a small "Template by VibeFather" link to https://vibefather.ai/t/space-dogfight-arcade-game in the footer (default: yes; delete this line to remove it)

The copy under Pages & Sections is written for the default values. If your values differ, rewrite every headline, paragraph, label and image for them — same length, tone and structure. Layout, colors, type and motion stay as described.
Keep all copy, image paths and links in one content file (for example `src/content.ts`), keyed by section, so the content can be swapped later without touching components.

## Design
### Colors
- Void `#07080C` — Page background, renderer clear, and linear fog
- Paper `#E7ECF2` — Primary text and fighter hull
- Dim `#9AA3AE` — Secondary text, canards, spine fin, and idle radar dots
- Amber `#E8A23A` — Lock ring, missile, boost cue, canopy, primary button, low-shield fill
- Ice `#8FCBE3` — Shield fill, ready ring, and the radar player mark
- Bolt `#E7F1F8` — Player energy bolts and ice burst squares
- Drone bolt `#B7C0CA` — Drone bolts only. Cool gray, never red or green
- Rock `#C3CBD4` — Lit asteroid material
- Rock deep `#646C78` — Darkest asteroid material
- Rock mid `#8E98A4` — Middle asteroid material
- Ink `#141820` — Text on the amber button
- Glass `rgba(10, 12, 16, 0.72)` — Title card, retry card, radar, and touch controls
- Line `rgba(213, 220, 228, 0.32)` — Hairline borders on glass panels
- Nozzle `#2C3138` — Engine nozzles

### Typography
- Squadron name and primary buttons: Oxanium (OFL), weights 500/600
- Body, legend, and secondary buttons: Source Sans 3 (OFL), weights 400/600
- Wave, shield, call sign, and radar labels: IBM Plex Mono (OFL), weights 400

### Layout & motion
- Spacing: 4 px base. Desktop title card padding 28 px and HUD inset 24 px. Mobile card padding 20 px, HUD inset 16 px, and safe-area padding on the touch row. Buttons are at least 44 px tall. Touch buttons are 64 px. The stick is 116 px. The page itself does not scroll; only the mobile title card scrolls inside itself.
- Radius: Title and retry cards 16 px. Primary and touch buttons 12 px. The radar is a circle. The shield track is 2 px. World meshes stay faceted. The lock reticle is a circle, not a bracket.
- Motion: Variable dt capped at 0.033 seconds. Render once per frame after at most one simulation step.
- Motion: Chase camera smoothing is 1 - exp(-5.5 * dt). Snap the camera on the title pose, on the frame play starts, and on Fly again.
- Motion: A damaging hit shakes the camera for 0.16 seconds at amplitude 0.14. The title fighter yaws at 0.08 rad/s. The lock ring may pulse 5 percent. The shield fill may pulse while below 25.
- Motion: Boost pulls the camera back 1.6 units and shows eight short speed lines. Missile and bolt motion is the game and always stays.
- Motion: With prefers-reduced-motion, cut shake, title yaw, camera pull, speed lines, missile trail, lock pulse, shield pulse, and particle tumble. Use the small particle budget and multiply burst life by 0.35. Snap overlays. Keep steering, firing, lock, waves, and the retry card.
- Imagery: Draw the fighter, drones, asteroids, stars, bolts, missile, bursts, boundary cage, and favicon in code. No photographs, no generated stills, no HDRI, no downloaded spacecraft, and no people. The first-screen anchor is the lit chase view of the fighter among asteroids, with the glass card beside it on desktop and below it on a phone. Hits are tumbling ice and amber squares. There is no fire, smoke, pilot, or blood.

## Pages & Sections
### [BRAND] (`index.html`)
1. **Title card over the chase view** — States are title, play, and ended. Open on title. Document title is Cinder Patrol from BRAND. Eyebrow, IBM Plex Mono 12 px, tracking 0.2 em, amber, uppercase: HARROW REACH, from SECTOR. Heading, Oxanium 600, 52 px desktop and 36 px under 768 px, paper, wraps at two lines and does not go below 32 px: Cinder Patrol. Deck, Source Sans 3 18 px: Patrol Harrow Reach. Scatter the Glass Moths. Audience line, 14 px dim: A short patrol for night-shift pilots. Meta, mono 13 px dim: Craft Lark · Call sign Kestrel. Controls label, 13 px dim. Desktop legend, hidden under 768 px: Steer with the pointer, the arrow keys, or W A S D. Fire with the left click or Space. Hold the right click or F to lock. The missile launches when the ring fills. Shift boosts. R rolls and shimmers the shield. Mobile legend, hidden from 768 px up: Drag the stick to steer. FIRE shoots. Hold LOCK until the ring fills. BOOST is a short kick. ROLL shimmers the shield. Note, 13 px dim: Tones start when you launch. Button: Launch patrol. If WebGL failed, add: This browser could not start the 3D view. and disable the button. Optional [CREDIT] link once, 12 px dim, under the button, only when a credit value is provided. Canvas accessible name: Third-person flight through a low-poly asteroid field.
   Layout: The canvas is fixed to the viewport and renders the field before the first click. UI root is pointer-events none; the card and buttons set pointer-events auto. Desktop, 768 px and up: a 400 px glass card, 16 px radius, 28 px padding, 16 px from the left, vertically centered, border 1 px solid Line. It leaves the fighter in the open center of a 1440 px width. Mobile: a bottom sheet, left and right 16 px, bottom 16 px, max-height 46 vh, internal scroll, same glass fill, no full-screen dimmer. At 390×844 the fighter sits in the top 46 percent, above the sheet, with asteroids around it. Background behind the canvas is Void. Focus Launch patrol on load. Enter activates the focused button.
   Motion: The card is present on the first painted frame. With motion allowed it fades in over 160 ms. Reduced motion shows it immediately. Launch patrol sets state to play, hides the card, snaps the camera to the play offset, places the fighter at the spawn, and starts wave 1 in that same step.
2. **Field, fighter, drones, and camera** — Axes: Y up. The nose of every craft is its local -Z. Do not aim craft with object.lookAt, which would point +Z at the target. The patrol volume is a sphere of radius 148 centered on the origin. A wireframe sphere of radius 148, SphereGeometry(148, 8, 6), MeshBasicMaterial color #8F98A4, opacity 0.14, is the boundary cage. It is a volume marker, not a planet and not a station. Fog is linear, color Void, near 80, far 220. Stars: 900 points on a sphere of radius 400, seed 0x57A12, PointsMaterial color #C5CED8, size 1.4, sizeAttenuation true, fog false. Indices 400 through 899 are visible only when the viewport is at least 768 px wide. Asteroids: always generate 46 from seed 0x0D165607. IcosahedronGeometry(1, 0), jitter each vertex radially to between 0.72 and 1.22 of its length, recompute normals, flat shading. Reject points closer than 36 to the origin or farther than 142, and reject points within 16 of another rock. Scale 2.4 to 8.6. Three materials only, #C3CBD4, #8E98A4, and #646C78. Each rock spins at 0.04 to 0.18 rad/s on a seeded axis. Indices 20 through 45 are hidden under 768 px. Do not reseed on resize. Asteroids are scenery, not colliders.
   Layout: Fighter, built once from primitives, flatShading MeshStandardMaterial, roughness 0.86, metalness 0.02. Outer group rotation.order YXZ. Inner group holds the meshes. Body: BoxGeometry(0.92, 0.52, 2.5) at (0, 0, -0.15), color #D5DCE4. Nose: ConeGeometry(0.36, 1.05, 4), rotation.x = -PI/2 so the apex points to local -Z, position (0, 0, -1.85), same hull color. Spine: BoxGeometry(0.07, 0.78, 0.85) at (0, 0.55, 0.55), color #9AA3AE. Canards: BoxGeometry(1.25, 0.07, 0.62) at (-0.95, -0.02, -0.35) with rotation.z 0.16, and the mirror at x +0.95 with rotation.z -0.16, color #9AA3AE. Canopy: BoxGeometry(0.42, 0.16, 0.62) at (0, 0.32, -1.15), color #E0A24A, roughness 0.35. Nozzles: CylinderGeometry(0.14, 0.18, 0.32, 6), rotation.x = PI/2, at (±0.26, -0.08, 1.22), color #2C3138. Glow discs: CircleGeometry(0.12, 6) at (±0.26, -0.08, 1.40), MeshBasicMaterial #E8A23A, opacity 0.35. No letters, roundels, second wing pair, ball cockpit, saucer, or beak. Drone, nine cached groups: OctahedronGeometry(0.8) color #C5CED8, TorusGeometry(1.05, 0.045, 5, 16) with rotation.x = PI/2 color #7E8794, and a sensor sphere radius 0.1 at (0, 0, -0.85). The sensor emissive is #E8A23A only while that drone is the lock candidate. No wings and no cockpit. Lights: ambient #A8B2C0 intensity 0.7, directional #F3F6FA intensity 1.35 from (40, 70, 24). No shadows, no environment map. Renderer: ACESFilmic, exposure 1.05, SRGB, clear Void. Pixel ratio min(device, 1.75), or min(device, 1.25) under 768. Antialias on at 768 and up only.
   Motion: Title pose: fighter at (0, 0, 18), outer rotation.y = 0.55, rotation.x = 0. If motion is allowed, add 0.08 rad/s to rotation.y. Play spawn: (0, 6, 24), rotation 0. Desktop camera offset in fighter local space is (0, 3.2, 8.4), look target (0, 0.45, -7), fov 52. Under 768 during title only, offset (0, 5.6, 12.2), look (0, 2.4, -6), fov 60, so the craft clears a 46 vh sheet. Play uses the desktop offset at every width, with fov 62 under 768. Smooth with 1 - exp(-5.5 * dt), and snap on title, launch, and Fly again. During boost, add local (0, 0.15, 1.6) unless reduced motion is on.
3. **Steering, boost, roll, and the boundary** — Speed is 70 while the boost timer is above 0, otherwise 34. Move the fighter along its nose by speed times dt. Positive stickX decreases rotation.y at 1.35 rad/s. Positive stickY increases rotation.x at 1.05 rad/s. Clamp rotation.x to ±1.05 so the chase camera stays upright. Nose direction with yaw and pitch is forward = (0, 0, -1) applied by the outer Euler. Inner rotation.z eases toward -stickX * 0.38. A roll edge, when the roll gap is clear, plays a 0.6 second spin of inner.rotation.z by -2π if stickX >= 0, otherwise +2π, using smoothstep. The neutral roll drops the right canard first. For the first 0.4 seconds of that spin, show a wireframe sphere radius 2.2, color #D5E6F2, opacity 0.25, and ignore damage. Then wait 0.45 seconds before another roll. Boost is an edge. If the cooldown is 0, set the boost timer to 0.75. When it expires, set the cooldown to 2.4. Eight boxes, 0.05 by 0.05 by 0.8, sit behind the nozzles at ice color while boosting, hidden in reduced motion. Nozzle discs go to opacity 1 during boost and 0.35 otherwise. While distance from the origin exceeds 140, ignore the stick and steer yaw and pitch toward -normalize(position) at the same rates until distance is under 136. Target pitch is asin of the desired y. Target yaw is atan2(-desired.x, -desired.z). Take the shortest yaw step. During that override, flash a 2 px inset ice line on the HUD for 0.25 seconds at a time.
   Layout: Desktop steer: if any of W A S D or the arrow keys is down, that keyboard vector replaces the pointer. Otherwise the pointer offset from the viewport center, divided by 28 percent of the width and height, clamped to ±1, with a dead zone of 0.08, is the stick. Pointer above center is nose up. W and ArrowUp pitch up. S and ArrowDown pitch down. A and ArrowLeft yaw left. D and ArrowRight yaw right. Fire is held on Space or primary pointer down on the canvas. Lock is held on F or the secondary button. Prevent the context menu. Boost edges on Shift. Roll edges on R. M toggles tones. Prevent default on Space and the arrow keys. When the touch cluster is visible, ignore canvas pointer steering. The cluster shows when the pointer is coarse or the width is under 768, and only during play. Stick knob travels inside a 36 px radius, values clamped to ±1, dead zone 0.12, up positive. BOOST and ROLL fire on pointerup. FIRE and LOCK stay held from pointerdown until pointerup, using setPointerCapture. Clear held keys on blur and when the document hides.
   Motion: Bank eases with 1 - exp(-8 * dt). The roll replaces the bank until it finishes, then the bank eases back. The boundary flash does not shake the camera. Reduced motion keeps the same steering, boost, and roll, and drops only the speed lines and the camera pull.
4. **Bolts, lock, and the missile** — Player bolts are boxes 0.08 by 0.08 by 1.6, MeshBasicMaterial #E7F1F8. Pool of 16. While Fire is held, spawn one every 0.13 seconds, the first on the frame Fire becomes true. Spawn at fighter local (0, 0, -2.55). Velocity is the nose times 130 and does not add the ship's speed. Life 1.15 seconds, or remove past radius 170. Move bolts in slices of at most 2 units. A hit is a slice passing within 0.5 + 1.35 of a drone center. Damage 16, integers only. Two bolts empty a drone shield of 32. Drone bolts are boxes 0.1 by 0.1 by 1.2, color #B7C0CA, speed 78, damage 18, pool of 24. A drone fires when it is within 62, the angle between its nose and the player is under 12 degrees, and its 1.7 second cooldown is clear. Six drone bolts empty a full player shield. Player hit radius is 1.15. After a damaging hit, ignore further damage for 0.35 seconds. Shimmer also ignores damage. Do not use green or red for either bolt.
   Layout: Lock, while held, with no missile alive and the lock cooldown at 0: pick the nearest drone between 8 and 78 whose angle from the nose is under 16 degrees. If the candidate changes, progress resets to 0. Otherwise add dt / 0.65. At 1, spawn the missile, clear progress, and set the lock cooldown to 0.4. Releasing lock early clears progress. The center reticle is a 72 px SVG, 56 px under 768, circle radius 28, stroke 2, circumference 175.93, rotated so the dash starts at 12 o'clock. Track stroke is ice at 0.35 opacity. The amber dash offset is the circumference times (1 - progress). Four ice ticks, 8 px, sit at the cardinals. The word LOCK, mono 11 px amber, shows only while a candidate exists. A world torus of radius 1.7 and tube 0.03, color amber, billboards at the candidate and is visible only while progress is above 0. The missile is one cached cone, ConeGeometry(0.12, 0.7, 4), apex toward local -Z, MeshBasicMaterial #E8A23A, plus a small fin box. Only one exists. Speed 92, turn at most 2.2 rad/s, life 3.4 seconds. Aim by rotating (0, 0, -1) onto the direction to the drone, then slerp within the turn rate. If the drone is gone, fly straight. A hit within 0.8 + 1.35 destroys the drone. Keep the last 8 positions as 0.16 amber squares unless reduced motion is on.
   Motion: Lock progress is driven by simulation time, not a CSS animation, so a release resets it on the same frame. With motion allowed the world ring scales by 1 + 0.05 * sin(time * 5). Reduced motion holds the ring at scale 1 and draws no missile squares. Bolts and the missile still move.
5. **Waves, shields, and bursts** — Wave 1 starts in the launch step with min(3 + (n - 1) * 2, 9) drones and speed min(16 * pow(1.06, n - 1), 42). Place drone i at angle (i / count) * TAU + 0.7, radius 96, y = ((i % 5) - 2) * 14. If it is within 36 of the player, push it out to 36. Face the player. Each step, turn the nose toward the player at 0.85 rad/s, move along the nose, then separate from other active drones closer than 7 by (7 - distance) * 4 * dt. Clamp drones to radius 146. They do not ram and they do not hit asteroids. When the last active drone is destroyed, start a 2.8 second breather in that same step. The wave number increments only when the breather ends, then the next wave spawns. There is no final wave. In-flight drone bolts keep moving during the breather. New drones do not fire until the next wave exists. Player shield starts at 100. A drone bolt subtracts 18. After 1.6 seconds without a damaging hit, recover 12 per second up to 100, only in play and only while shield is above 0. At 0, clamp to 0, hide the fighter, spawn the player burst, freeze drone motion, clear remaining bolts, set state to ended, and show the retry card after 0.7 seconds. The wave reached is the current wave number. Fly again sets wave to 1, shield to 100, spawn pose, and play, without opening the title. Title returns to the title pose and hides every drone.
   Layout: Drone shield is 32. A player bolt subtracts 16. A missile sets it to 0. Recycle the group, play the destroy tone, and spawn a drone burst. Bursts use one InstancedMesh of PlaneGeometry(0.26, 0.26), MeshBasicMaterial, transparent, depthWrite false, toneMapped false, pool 120. Desktop budgets: 56 squares for the player, life 0.65 seconds, speed 6 to 14; 28 for a drone, life 0.45, speed 5 to 11. Under 768, or whenever reduced motion is set: 24 and 12 squares, and life times 0.35. Colors alternate #E7F1F8 and #E8A23A. Billboard each square to the camera. Scale by remaining life. Dead instances scale to 0. If the pool is full, still remove the craft. Seed directions with mulberry32. No smoke, no flame color, no debris shaped like a body. On Fly again and Title, return particles to the pool and keep the geometries.
   Motion: Squares tumble from the seeded spin unless reduced motion is on. A player hit, if motion is allowed, adds a camera-right offset of sin(t * 46) * 0.14 * (1 - t / 0.16) for 0.16 seconds and flashes the hull emissive #E7F1F8 for 0.08 seconds. Reduced motion skips both and still subtracts the shield. The ended camera stays on the last chase pose.
6. **HUD, radar, and touch controls** — HUD labels, fixed in src/content.ts: SHIELD, WAVE, LOCK, READY, BOOST, Tones on, Tones off. Call sign renders as KESTREL in uppercase mono 13 px, tracking 0.18 em. Sector under it, 13 px dim: Harrow Reach. Wave block: the word WAVE at 11 px dim, then the number at mono 28 px desktop and 20 px under 768, two digits, then a status line. Status is 3 LEFT with the live drone count, or 1 LEFT, or NEXT WAVE during the breather. Shield label and the integer shield value. Fill width is shield / 100. Color #8FCBE3, or #E8A23A when shield is below 25 and above 0. Boost widget, desktop only: a 76 px ring, radius 26, circumference 163.36. READY is a full ice ring. During the 0.75 second boost the ring is solid amber at opacity 0.9 and the label reads BOOST. During the 2.4 second cooldown an amber arc shrinks from full to empty and the label shows one decimal. Radar: player triangle 8 px, ice, pointing up. Other drones are 4 px dots #C5CED8. The lock candidate is a 6 px amber dot. No asteroid dots and no missile dot. Transform the world offset into the fighter local frame and plot local x to the right and local z downward in SVG, because local -z is forward and SVG up is negative y. Radius 148 maps to the plot radius minus 10 px. Clamp to the rim. The circle itself is the volume edge.
   Layout: HUD is hidden on the title and visible during play and ended. Desktop, 768 and up: call sign top 24 left 24; wave centered top 24; tones button top 24 right 24, height 44, glass, border Line; radar 148 px bottom 24 left 24; shield track 280 by 10 centered bottom 32; boost ring bottom 24 right 24. Under 768: call sign top 16 left 16; wave top 16 center; tones top 16 right 16; radar 88 px at top 72 left 16; shield bar left 16 right 16 at bottom 168; hide the desktop boost ring. Reticle stays centered. Touch row, only during play on a coarse pointer or under 768: bottom 16, left 16, right 16, stick 116 px on the left, 2 by 2 grid on the right with 8 px gaps. Visible labels BOOST, ROLL, FIRE, LOCK. Accessible names Steer, Boost, Barrel roll, Fire, Lock. Each button is at least 64 px. The BOOST button shows the cooldown as a conic-gradient of #E8A23A over a dim track, and an ice border when ready. A held FIRE button uses an ice border. A held LOCK button uses an amber border. Glass panels use the glass fill. From 768 up they also use backdrop-blur. Under 768 use the same fill at 0.86 opacity and no blur. A polite live region announces Patrol started. Wave 1. on launch, Wave N. when a wave spawns, and Shields down. Wave reached N. on the retry. Do not announce each hit.
   Motion: Shield pulse below 25, between opacity 1 and 0.55 at 2 Hz, only if motion is allowed and shield is above 0. Radar dots move with the simulation and do not tween on their own. Overlays do not travel. Reduced motion snaps the tones and retry visibility and holds the shield fill at full opacity.
7. **Retry card, tones, and both viewports** — Retry card copy, from the variables and the wave integer: eyebrow KESTREL · HARROW REACH; heading Shields down; line Wave reached 4. using the real wave; subline The Glass Moths still hold Harrow Reach.; primary Fly again; secondary Title. Focus Fly again when the card opens. Fly again does not reload the page. Title does not reload the page. Tones stay off until Launch patrol, which creates or resumes the AudioContext inside that click. Master gain 0.16. If the constructor throws, leave sound off and do not log in a loop. Button text is Tones on when audio will play and Tones off when muted. M matches the button. Persist the mute flag in localStorage under tones- plus the squadron name in lowercase with spaces turned into hyphens. Ignore storage failures. Cues, no audio files: player bolt sine 940 Hz for 30 ms at gain 0.04; lock tick sine 520 Hz for 20 ms at most every 100 ms while progress increases; missile launch square 160 Hz for 80 ms then sine 880 Hz for 50 ms; player hit a 120 ms noise buffer through a bandpass at 400 Hz, gain 0.06; drone destroyed noise 80 ms; player destroyed noise 220 ms with a lowpass falling from 1200 Hz to 200 Hz; breather start sines 523, 659, and 784 Hz, 70 ms each; boost sine 98 Hz for 80 ms; roll sine 320 Hz for 40 ms then 640 Hz for 50 ms. Build the noise buffer once from mulberry32(0xA0D10). Silence while muted, hidden, or on the title before launch.
   Layout: The retry card matches the title card: 400 px on the left, vertically centered, from 768 up; a bottom sheet max 46 vh under 768. Hide the touch cluster while it is open. Leave the HUD visible underneath with shield 0 and the wave number. Hide the reticle. Target a clean frame at 1440×900 and at 390×844 with no horizontal overflow, no page scroll, and no console errors. Honor safe-area insets on the touch row. Touch-action none and overscroll-behavior none on the body. Resize updates the camera aspect, the pixel-ratio cap, and asteroid and star visibility. If the mean frame time over 180 frames exceeds 22 ms, once, set the pixel ratio to 1 and hide star indices above 300. Do not remove waves, bolts, or touch controls in that cut.
   Motion: The retry card fades in over 160 ms after the 0.7 second burst, or snaps in when reduced motion is set. The 0.7 second wait pauses while the document is hidden. Fly again and Title snap the camera and do not play a transition. Reduced motion is separate from the performance cut: the patrol stays playable, and only the extra shake, trails, pulses, and long bursts drop.

## Assets
- image: No image files and no generated stills. Draw the fighter, drones, asteroids, stars, bolts, missile, bursts, and boundary cage in three.js. Add an original public/favicon.svg: a 32 viewBox, Void background, and an amber diamond stroke with no letters and no wings. Link it with a relative href ./favicon.svg. In ASSETS.md state that the scene is code-drawn and list the favicon as original.
- icon: Do not install an icon package. Touch controls and the tones button are text. The radar player mark is an SVG triangle. List no third-party icons in ASSETS.md.
- font: Self-host Oxanium, Source Sans 3, and IBM Plex Mono through the Fontsource packages named in the stack (OFL). Import only the weights listed. In ASSETS.md record the local woff2 files, the npm package pages, and the OFL license. Do not request fonts from any CDN.
- video: No video and no audio files. Cues are synthesized with Web Audio after Launch patrol unlocks the context.

## Don'ts
- No backend, accounts, database, analytics, external APIs, submitting forms, or remote assets. The mute flag is the only localStorage value, under a key built from BRAND.
- No CDN scripts, fonts, or images. Self-host fonts, import three from the installed package, use relative paths, and emit minified files to dist/ with source maps off and without copying src/ into dist/. Keep dist under 20 MB. Vite base is './'.
- The only page is index.html. Do not add a marketing page, a price, or a bare directory link. The document title is BRAND. The first screen is the lit chase view with the title card beside or below it, never type on a flat field.
- Do not use Star Wars, Star Fox, Wing Commander, TIE Fighter, X-Wing, Elite, Star Citizen, Freelancer, Freespace, EVE, Homeworld, No Man's Sky, or Descent names, logos, ships, or targeting-computer layouts.
- Do not build an Arwing, X-wing S-foils, a TIE ball cockpit, hexagonal solar wings, the Millennium Falcon, Elite's Cobra, or any other signature fighter silhouette. The fighter is the stubby dart specified here: one spine fin and two fixed canards.
- Do not use the phrase "do a barrel roll" or franchise slogans, call signs, or pilot names. The roll control label is ROLL and its accessible name is Barrel roll.
- No green-versus-red lasers, trench runs, Death Star geometry, or insignia of Lucasfilm, Nintendo, NASA, or SpaceX. Player bolts are #E7F1F8 and drone bolts are #B7C0CA.
- No gore, bodies, blood, burning pilots, or realistic fireballs. A destroyed craft becomes ice and amber squares only.
- No commercial fonts and no restricted libraries, including Aceternity UI, Tailwind Plus, and anything CC BY-NC. Faces are Oxanium, Source Sans 3, and IBM Plex Mono, self-hosted.
- No downloaded spacecraft models, HDRIs, stock photos, placeholder-image services, or icon fonts. No people and no portraits.
- The reticle is one circle and four ticks. Do not add a bracketed targeting computer, a distance numeral, or a nameplate. The radar shows the player, drone dots, and the lock dot only.
- Do not add wingmen, capital ships, stations, mines, a score, a second missile, or asteroid collision. Asteroids are scenery.
- Do not hard-code Cinder Patrol, Kestrel, Harrow Reach, Glass Moths, Lark, or the default audience line outside src/content.ts, and do not leave raw variable tokens on screen.
- Do not mention VibeFather except the optional [CREDIT] link. Do not invent calendar dates, prices, or online player counts. All copy is US English.
- No Math.random, no shadow maps, no three/examples imports, and no physics engine. Honor prefers-reduced-motion without stopping the patrol. At 390×844 and 1440×900 the card, HUD, and touch controls must be usable with no horizontal overflow and no console errors.
- If WebGL fails, show the fallback sentence and do not throw in a loop. Freeze the step while the document is hidden.

---
— Prompt by VibeFather · https://vibefather.ai/t/space-dogfight-arcade-game · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown

Free for personal projects under CC BY-NC 4.0. Commercial use comes with Pro.

DESIGN.md

The design system on its own — colors, type, spacing and motion. Apply this look to a project you already have.

---
name: "Space Dogfight Arcade Game"
colors:
  void: "#07080C"
  paper: "#E7ECF2"
  dim: "#9AA3AE"
  amber: "#E8A23A"
  ice: "#8FCBE3"
  bolt: "#E7F1F8"
  drone_bolt: "#B7C0CA"
  rock: "#C3CBD4"
  rock_deep: "#646C78"
  rock_mid: "#8E98A4"
  ink: "#141820"
  glass: "rgba(10, 12, 16, 0.72)"
  line: "rgba(213, 220, 228, 0.32)"
  nozzle: "#2C3138"
typography:
  squadron_name_and_primary_buttons: { family: "Oxanium", weights: [500, 600] }
  body_legend_and_secondary_buttons: { family: "Source Sans 3", weights: [400, 600] }
  wave_shield_call_sign_and_radar_labels: { family: "IBM Plex Mono", weights: [400] }
spacing: "4 px base. Desktop title card padding 28 px and HUD inset 24 px. Mobile card padding 20 px, HUD inset 16 px, and safe-area padding on the touch row. Buttons are at least 44 px tall. Touch buttons are 64 px. The stick is 116 px. The page itself does not scroll; only the mobile title card scrolls inside itself."
radius: "Title and retry cards 16 px. Primary and touch buttons 12 px. The radar is a circle. The shield track is 2 px. World meshes stay faceted. The lock reticle is a circle, not a bracket."
---

# Space Dogfight Arcade Game — Design System

Apply this design system to an existing project. It describes the look and feel only; for the full site, use prompt.md.

## Colors
- **Void** `#07080C` — Page background, renderer clear, and linear fog
- **Paper** `#E7ECF2` — Primary text and fighter hull
- **Dim** `#9AA3AE` — Secondary text, canards, spine fin, and idle radar dots
- **Amber** `#E8A23A` — Lock ring, missile, boost cue, canopy, primary button, low-shield fill
- **Ice** `#8FCBE3` — Shield fill, ready ring, and the radar player mark
- **Bolt** `#E7F1F8` — Player energy bolts and ice burst squares
- **Drone bolt** `#B7C0CA` — Drone bolts only. Cool gray, never red or green
- **Rock** `#C3CBD4` — Lit asteroid material
- **Rock deep** `#646C78` — Darkest asteroid material
- **Rock mid** `#8E98A4` — Middle asteroid material
- **Ink** `#141820` — Text on the amber button
- **Glass** `rgba(10, 12, 16, 0.72)` — Title card, retry card, radar, and touch controls
- **Line** `rgba(213, 220, 228, 0.32)` — Hairline borders on glass panels
- **Nozzle** `#2C3138` — Engine nozzles

## Typography
- **Squadron name and primary buttons** — Oxanium (OFL), weights 500/600. Self-host the font files.
- **Body, legend, and secondary buttons** — Source Sans 3 (OFL), weights 400/600. Self-host the font files.
- **Wave, shield, call sign, and radar labels** — IBM Plex Mono (OFL), weights 400. Self-host the font files.

## Spacing & shape
- Spacing: 4 px base. Desktop title card padding 28 px and HUD inset 24 px. Mobile card padding 20 px, HUD inset 16 px, and safe-area padding on the touch row. Buttons are at least 44 px tall. Touch buttons are 64 px. The stick is 116 px. The page itself does not scroll; only the mobile title card scrolls inside itself.
- Radius: Title and retry cards 16 px. Primary and touch buttons 12 px. The radar is a circle. The shield track is 2 px. World meshes stay faceted. The lock reticle is a circle, not a bracket.

## Motion
- Variable dt capped at 0.033 seconds. Render once per frame after at most one simulation step.
- Chase camera smoothing is 1 - exp(-5.5 * dt). Snap the camera on the title pose, on the frame play starts, and on Fly again.
- A damaging hit shakes the camera for 0.16 seconds at amplitude 0.14. The title fighter yaws at 0.08 rad/s. The lock ring may pulse 5 percent. The shield fill may pulse while below 25.
- Boost pulls the camera back 1.6 units and shows eight short speed lines. Missile and bolt motion is the game and always stays.
- With prefers-reduced-motion, cut shake, title yaw, camera pull, speed lines, missile trail, lock pulse, shield pulse, and particle tumble. Use the small particle budget and multiply burst life by 0.35. Snap overlays. Keep steering, firing, lock, waves, and the retry card.

## Imagery
Draw the fighter, drones, asteroids, stars, bolts, missile, bursts, boundary cage, and favicon in code. No photographs, no generated stills, no HDRI, no downloaded spacecraft, and no people. The first-screen anchor is the lit chase view of the fighter among asteroids, with the glass card beside it on desktop and below it on a phone. Hits are tumbling ice and amber squares. There is no fire, smoke, pilot, or blood.

## Tone
Calm, short, and operational, like a dispatcher. US English. No movie-trailer voice and no slogans from existing games.

---
— Prompt by VibeFather · https://vibefather.ai/t/space-dogfight-arcade-game · CC BY-NC 4.0 (non-commercial; commercial use needs a VibeFather Pro license) · Request removal: https://vibefather.ai/takedown

Make it yours

  • A studio launching an internal game jam: set BRAND to the team name and SECTOR to the office wing, then keep the default FOE for a light, playable break page.
  • An indie developer shipping a browser demo: set CRAFT to your ship name and CALLSIGN to the player handle, and rewrite AUDIENCE to name the demo's pitch.
  • A tabletop or board game club: set FOE to the faction the club plays against and SECTOR to the campaign region, then point the retry card at the club's next session.
  • A personal portfolio for a game developer: set BRAND to your handle and AUDIENCE to a one-line role, and keep the wave counter as a live playable sample.

Space Dogfight Arcade Game: questions and answers

What can I rename in the Space Dogfight Arcade Game template without breaking the game?

The Space Dogfight Arcade Game template exposes six variables: BRAND for the squadron name, CALLSIGN for the pilot, SECTOR for the patrol sector, FOE for the drone name, CRAFT for the fighter type, and AUDIENCE for the line under the deck. On-screen sentences rewrite themselves from those words, while speeds, colors, wave sizes, and the HUD stay exactly as they are.

How do the waves and the shield work in the Space Dogfight Arcade Game?

Waves in the Space Dogfight Arcade Game are numbered and grow from a base count up to nine drones, adding a little speed each time with a short breather between them. The shield starts full, regenerates after a delay when you stop taking hits, and the run ends only at zero shields, where the retry card shows the wave you reached.

What controls does the Space Dogfight Arcade Game use on desktop and on a phone?

Desktop play in the Space Dogfight Arcade Game uses the pointer and the keyboard to steer, fire bolts, hold a lock for one homing missile, boost on a cooldown, and roll for a shield shimmer. A phone swaps in a thumb stick plus boost, roll, fire, and lock buttons, and small screens draw fewer asteroids and particles to keep the field readable.

How do I host a Space Dogfight Arcade Game built from this prompt?

The Space Dogfight Arcade Game builds to static files with no backend, no server code, and no external APIs, so any static host serves it. Run the build, then upload the output folder. The renderer clears to the near-black field color and the page does not scroll, so there is nothing server-side to configure beyond serving the files.

Is the Space Dogfight Arcade Game prompt free to use for my own project?

The Space Dogfight Arcade Game is a free template, and free prompts and every DESIGN.md are licensed for personal, non-commercial use under CC BY-NC 4.0. Commercial or client work needs Pro, which also covers the source code of the demos. The brief, stack, and variables are shown publicly on the template page.

How do I build a space dogfight arcade game with AI?

Copy the prompt from this page or run npx vibefather add space-dogfight-arcade-game, replace [FOE], [BRAND], [CRAFT] and [SECTOR] with your own content, and paste it into Claude Code, Codex, Cursor or another AI coding agent. The live demos were built from exactly that text.

Which AI model built the Space Dogfight Arcade Game demo?

The Cinder Patrol squadron case was built by Grok 4.7 in Grok Build; the Saltglass Wing patrol case was built by Grok 4.7 in Grok Build. Each build used the published prompt with nothing added.

What tech stack and pages does the Space Dogfight Arcade Game template use?

Space Dogfight Arcade Game is a single-page site built with Tailwind CSS, Plain HTML and Three.js, with 3d / webgl and micro-interactions. The prompt fixes the stack so every AI tool builds the same kind of project, and the result runs as a static site you can host anywhere.

Can I use the Space Dogfight Arcade Game template for a client or a business?

The Space Dogfight Arcade Game prompt and DESIGN.md are free for personal, non-commercial projects under CC BY-NC 4.0. Client work and commercial use need VibeFather Pro, which also includes the source code of the live demo.

Does the Space Dogfight Arcade Game template work on mobile?

Yes. Every Space Dogfight Arcade Game build was tested on a phone-sized screen as well as desktop before it went live, checking layout, text size and touch targets. Open the live demo on your phone, or switch the preview on this page to mobile view, to check it yourself.