# One-Shot Prompt

**Theme**: Neon Arcade / Synthwave
**Generated**: 2026-04-24

## Prompt

Write a complete, self-contained Snake game in a single HTML file themed around **Neon Arcade / Synthwave**. The game is called **"Serpentine"**.

### Visual Identity

**Color palette** (5 tones, applied with intention):
- Deep void background: `#0a0a1a`
- Electric cyan: `#00f0ff` (primary — snake body, main text, grid highlights)
- Hot magenta/pink: `#ff2d75` (accent — snake head, food, score glow)
- Laser purple: `#a855f7` (secondary accent — particle trails, UI elements)
- Grid blue: `#1a1a3e` (subtle grid lines, horizon)

**Typography**: Orbitron (Google Fonts) for title and headings; system monospace for score and UI text. The title "SERPENTINE" must use Orbitron 900 weight. Score numbers use Orbitron 700. Controls hints use monospace at smaller size.

**Favicon**: Inline SVG data URI — a small cyan snake emoji-style icon.

### Canvas & Rendering

- HTML5 Canvas element, no DOM grid. All game visuals rendered in canvas.
- Canvas scales responsively: on desktop, target 600×600 logical pixels; on mobile, fill viewport width with 16px padding.
- Retina/HiDPI support: set `canvas.width` and `canvas.height` to logical dimensions × `devicePixelRatio`, then `ctx.scale(dpr, dpr)`.
- `imageSmoothingEnabled = false` for crisp pixel rendering (optional — depends on whether you use pixel art or smooth shapes).

### Background Treatment

- **Perspective grid**: Lines recede to a vanishing point at horizontal center, 15% from top of canvas. Vertical grid lines fan outward from the vanishing point. Horizontal grid lines get closer together as they approach the vanishing point (exponential spacing). All grid lines use `#1a1a3e` at 0.3–0.5 alpha, 1px wide.
- **Horizon glow**: A linear gradient from the vanishing point downward, transitioning from `#0a0a1a` to a slightly brighter `#1a1a3e`, creating the illusion of a glowing city horizon. This gradient sits between the grid and the game board.
- **CRT vignette**: A radial gradient overlay drawn last (after all game elements), dark at edges, transparent at center. Uses `rgba(0,0,0,0.6)` at edges fading to `rgba(0,0,0,0)` at center. This creates depth and draws the eye inward.
- **Trail/afterglow**: Instead of calling `ctx.clearRect()` each frame, draw a semi-transparent overlay of `rgba(10, 10, 26, 0.12)` over the entire canvas before rendering the current frame. This causes previous frames to fade gradually, creating a motion trail behind the snake. Use 0.12 alpha for a dramatic trail; slightly higher (0.18) if the trail is too intense on faster hardware.

### Game Board & Grid

- **Grid**: 20 × 20 cells. Cell size is computed as `MIN(canvasLogicalWidth, canvasLogicalHeight) / 20`.
- **Board offset**: Center the 20×20 grid within the canvas. If the canvas is rectangular (mobile), add vertical or horizontal padding so the grid stays square.
- **Grid lines**: Subtle lines at every cell boundary, drawn in `#1a1a3e` at 0.08–0.12 alpha. These lines should be barely visible — they provide structure without competing with the snake. Do NOT draw thick or bright grid lines; they should feel like a faint blueprint underneath the action.
- **Grid pulse**: When food is collected, briefly increase the alpha of grid lines radiating outward from the food position, creating a ripple effect. Fade lasts ~300ms.

### Snake Visual Treatment

- The snake is an array of segments, each at a grid coordinate `{x, y}`.
- **Body segments**: Rounded rectangles with 2px corner radius, filled with a linear gradient from `#00f0ff` (bright cyan, at the segment center) to `#0088cc` (deeper cyan, at the segment edges). Each segment has `shadowBlur: 10` and `shadowColor: '#00f0ff'` for a neon glow.
- **Tail-to-head gradient**: The tail segments are slightly dimmer and smaller (90% opacity, 90% of cell size). The head segment is the brightest and largest (100% opacity, 95% of cell size). Segments between the tail and head interpolate in both opacity and size.
- **Head shape**: The head is a forward-pointing chevron/arrow — a triangle pointing in the current movement direction, or a rounded rectangle with a distinctive highlight. The head uses `#ff2d75` (hot magenta) fill with `shadowBlur: 15` and `shadowColor: '#ff2d75'`. The head also has two small white "eye" dots near the front edge.
- **Smooth movement**: Snake segments interpolate between their previous grid position and current grid position using a `moveProgress` value (0 to 1) computed from the game tick accumulator. Use `lerp(prevPos, currPos, moveProgress)` for each segment's drawn position. This prevents choppy grid-snapping.
- **Segment connections**: Draw thin glowing lines (`#00f0ff`, 1.5px, `shadowBlur: 4`) between adjacent segment centers to visually connect the body even when interpolation creates small gaps.

### Food Visual Treatment

- **Food shape**: A pulsing neon orb — a circle that oscillates in size between 70% and 100% of cell size using a sine wave over time. Fill color is `#ff2d75` (hot magenta).
- **Concentric ring**: Around the food, draw one or two concentric circles. The inner ring uses `#ff2d75` at 0.4 alpha. The outer ring uses `#a855f7` (laser purple) at 0.2 alpha. These rings pulse outward at a slightly offset phase from the center orb, creating a breathing effect.
- **Glow**: `shadowBlur: 20` and `shadowColor: '#ff2d75'` on the food orb.
- **Spawn animation**: When food spawns, it starts at 0% scale and grows to 100% over 200ms using an ease-out curve. During this growth, the concentric rings expand outward.

### Particle System

- On food collection, spawn 14–20 particles at the food's pixel position.
- **Particle properties**: Each particle has x, y, vx, vy, life (1.0), decay (0.015–0.035), color (randomly `#00f0ff`, `#ff2d75`, or `#a855f7`), and size (1–4px).
- **Physics**: Particles move outward with initial velocity in random directions. Apply slight gravity (`vy += 0.08` per frame). Apply slight friction (velocity × 0.99 per frame).
- **Rendering**: Each particle is a small circle with `globalAlpha = particle.life`. Draw with `shadowBlur: 6` and match `shadowColor` to the particle color.
- Particles are removed when `life <= 0`.
- **Optional effect**: 2–3 larger "spark" particles with higher initial velocity, brighter color (`#ffffff`), and faster decay — these create a brief flash on collection.

### Game Mechanics

- **Movement**: The snake moves continuously in its current direction. Movement updates on a fixed-interval tick (not tied to frame rate).
- **Base move interval**: 150ms per cell.
- **Speed curve**: Each food collected decreases the move interval by 3ms. Minimum interval: 55ms. This creates progressive difficulty without becoming unfair.
- **Input**: Arrow keys and WASD. Input is buffered in a queue (max 2 entries) so rapid key presses are not lost. The oldest queued input is consumed on each game tick.
- **180° reversal prevention**: The snake cannot reverse direction. If the queued input would cause a reversal, it is discarded.
- **Collision**: The snake dies if the head moves into a wall (grid boundary) or into any body segment (including the segment immediately behind the head if it would overlap).
- **Food spawning**: Food spawns at a random empty grid cell (not occupied by any snake segment). If the snake fills the entire grid (400 cells), the player wins.

### Game States

**START screen**:
- Canvas background renders (grid, horizon glow, vignette) with ambient particles drifting.
- Title "SERPENTINE" in Orbitron 900, large (48–56px), drawn in-canvas with `shadowBlur: 12`, `shadowColor: '#00f0ff'`. Below it, a subtitle "CHASE THE LIGHT" in Orbitron 400, smaller, in `#a855f7`.
- Controls hint: "ARROW KEYS / WASD TO MOVE" in monospace, `#1a1a3e` (dim), at bottom.
- CTA: "PRESS SPACE OR TAP TO START" in monospace, `#00f0ff`, with a slow pulsing opacity (sine wave, 0.5–1.0 range).
- A decorative neon border around the game grid area (cyan, 2px, `shadowBlur: 8`).

**PLAYING**:
- Active gameplay. Snake moves, food spawns, score increments.
- Score displayed in-canvas at top-left: "SCORE: N" in Orbitron 700, `#00f0ff` with `shadowBlur: 6`.
- High score displayed at top-right: "BEST: N" in Orbitron 400, `#a855f7` with `shadowBlur: 4`.
- The move interval adjusts dynamically as score increases.

**PAUSED**:
- Triggered by pressing P or ESC while playing.
- Canvas continues to render (background, particles, snake at frozen position, food still pulsing).
- A semi-transparent dark overlay (`rgba(10, 10, 26, 0.7)`) covers the game area.
- Center text: "PAUSED" in Orbitron 700, `#00f0ff` with glow.
- Subtitle: "PRESS P OR ESC TO RESUME" in monospace, `#a855f7`.

**GAME OVER**:
- Triggered by wall or self collision.
- **Screen shake**: On collision, shift the entire canvas rendering by random ±4px offsets for 8 frames (rapid decay), then settle.
- Semi-transparent overlay fades in over 400ms.
- "GAME OVER" in Orbitron 900, `#ff2d75` with `shadowBlur: 14`.
- Final score displayed large: "SCORE: N" in Orbitron 700, `#00f0ff`.
- High score displayed: "BEST: N" in Orbitron 400, `#a855f7`. If this game set a new high score, show "NEW BEST!" in `#ff2d75` with a pulsing glow.
- "PRESS SPACE OR TAP TO RESTART" in monospace, with pulsing opacity.
- On the game over screen, the score text fades in character by character with a 50ms stagger (typewriter effect).

### Transitions

- START → PLAYING: Grid lines briefly pulse brighter (0.15 alpha → 0.3 alpha → 0.1 alpha over 400ms) as the game begins. Title text fades out over 200ms.
- PLAYING → PAUSED: Overlay fades in over 250ms.
- PAUSED → PLAYING: Overlay fades out over 150ms.
- PLAYING → GAME OVER: Screen shake, then overlay fades in over 400ms. Grid lines dim to 0.03 alpha.

### High Score Persistence

- High score is stored in `localStorage` under the key `serpentine_high_score`.
- On game over, compare current score to stored high score. Update `localStorage` if current score is higher.
- Display high score on all screens (start, playing, game over).

### Mobile Support

- **Touch swipe**: Detect swipe direction on the canvas using `touchstart`/`touchend`. Minimum swipe distance: 30px. If the horizontal component is larger than vertical, queue left/right; otherwise queue up/down. Small swipes (<30px) are treated as taps — on START screen, a tap starts the game; on GAME OVER, a tap restarts.
- **Canvas sizing**: On viewports narrower than 600px, canvas fills 100% width minus 16px padding on each side. Height matches width (square grid). On viewports wider than 600px, canvas is 600×600px centered.
- **Prevent default**: Call `e.preventDefault()` on touch events to prevent page scrolling during gameplay.

### Accessibility

- **`prefers-reduced-motion`**: Wrap particle animations, screen shake, food pulse, and trail fade in a media query check (`window.matchMedia('(prefers-reduced-motion: reduce)').matches`). When true, disable particle effects, remove trail (use `clearRect` instead), remove screen shake, and keep food at fixed size.
- **Keyboard playable**: All controls via keyboard (arrows, WASD, space, P, ESC).
- **Focus management**: Auto-focus the canvas element on page load so keyboard input works immediately.

### Ambient Effects (always running)

- **Floating particles**: 15–25 small ambient particles drift slowly across the canvas at all times (even on START and PAUSED screens). These are tiny circles (1px, `#1a1a3e` at 0.3–0.6 alpha) with random slow velocities. They wrap around when they exit the canvas. This keeps the background feeling alive.
- **Synthwave sun**: A large, faint radial gradient circle positioned at the vanishing point (center-top). It uses a gradient from `rgba(255, 45, 117, 0.06)` at center to transparent at edges, with a radius of ~200px. This creates a subtle "sun" behind the grid, reinforcing the synthwave aesthetic. The sun drifts left/right by ±20px on a slow sine wave (period: 8 seconds).

### Code Quality

- Single file: `index.html` with all HTML, CSS, and JS inline. Start with `<!DOCTYPE html>`, end with `</html>`.
- No external images. No external JS libraries.
- Google Fonts CDN link for Orbitron is acceptable.
- Clean, readable JavaScript with clear function names and comments for major sections.
- No console errors. Clean up any intervals or listeners on restart.
- `will-change: transform` on animated CSS elements outside canvas.
- Page `<title>` set to "Serpentine".
- No truncated code. Every line written in full.

### Output

Produce two files:
1. **PROMPT.md** — this prompt document
2. **index.html** — the complete single-file game

## Notes

- The trail effect (semi-transparent overlay instead of clearRect) is the key visual technique that makes the game feel alive. It creates natural motion blur and a neon afterglow.
- The perspective grid is rendered procedurally in the canvas draw loop. The vanishing point is at the horizontal center, 15% from the top. Vertical lines fan out; horizontal lines use exponential spacing.
- All glow effects use Canvas `shadowBlur` and `shadowColor`. Reset `shadowBlur = 0` after each draw call to avoid unintended glow on subsequent elements.
- Speed curve is linear: `moveInterval = max(55, 150 - score * 3)`. This means the game gets progressively faster, capping at a challenging but playable speed.
- Touch controls use absolute swipe direction. A 30px minimum prevents accidental direction changes from taps.
- The game state machine is a simple enum: `START`, `PLAYING`, `PAUSED`, `GAME_OVER`. The render function branches on state and draws the appropriate overlay.
