28

Every AI-generated Snake I've seen is technically correct and completely lifeless: a square that jumps one cell per tick with zero feedback. I wanted the arcade-cabinet feeling in a single HTML file.

The naive prompt ("make snake in canvas") gave me exactly the dead grid. The fix was to demand a named list of game-feel effects with concrete timings, and to forbid instant teleport-per-cell movement by requiring interpolation between cells. The eat moment now has a chunky pop and the whole board flinches.

Still tuning the screen shake so it reads on fast eats without becoming nauseating. How do you decay shake so a 4-apple combo doesn't stack into an earthquake?

THE PROMPT
Build a single-file HTML5 Snake game on a 2D canvas. Playable at 60fps, no libraries.

Core rules: 24x24 cell grid, snake starts length 3, arrow keys AND WASD, wrap-around OFF (wall = death). Base tick 8 cells/sec, speeding up by 4% per apple to a cap of 16/sec.

Game feel (implement ALL, and name each in a comment):
1. Interpolate the snake's visual position between cells with an easeOutQuad over the tick duration so movement is smooth, NOT teleporting per cell.
2. On eat: 6px screen shake that decays exponentially over 180ms, a 1.15x scale-pop on the head over 120ms, and 8 particles bursting from the apple.
3. Combo eats within 900ms increase a score multiplier; show a floating "+N" that rises and fades over 500ms.
4. Death: 250ms hit-stop (freeze), then a red flash and the snake dissolves into falling particles.
5. Subtle idle bob on the apple (2px sine, 1.2s period).

Constraints: cap total screen shake magnitude so stacked combos never exceed 10px; respect prefers-reduced-motion by disabling shake and using instant fades. Use requestAnimationFrame with a fixed-timestep accumulator so logic is frame-rate independent. Before the code, list every effect with its duration and easing.
7the fixed-timestep accumulator note is doing a lot of heavy lifting here. so many AI snakes tie speed to framerate and break on a 144hz monitor.game_gwen 1 month ago
add a comment

1 Answer

29

The interpolation-between-cells requirement is what separates this from every dead Snake clone, good call. For the shake-stacking problem: don't add shake, take the max. Keep a single shakeAmount and on each eat do shakeAmount = Math.max(shakeAmount, 6), then decay it every frame. Combos feel punchy but never compound into an earthquake. I also clamp the trauma value 0..1 and square it (Nintendo's trick) so small hits stay subtle.

THE PROMPT
Replace additive shake with a trauma model: keep one `trauma` in [0,1], on eat do trauma = min(1, trauma + 0.35), decay trauma -= 2.5*dt per frame, and set offset = maxShake * (trauma*trauma) * randomInRange(-1,1). Cap maxShake at 10px.

Your Answer