Hamburger breakoutOne-line
Claude Haiku 5.5
by AnthropicReasoningRan out of tokens
How it went
- Total time
- 9 min 13 s
- Cost
- $0.064
- Output tokens
- 128,000
- Spent thinking
- 128,000 tokens
- Speed
- — tok/s
- Console errors
- —
- First token after
- 1.6 s
- First visible text after
- —
- Prompt tokens
- 542
- Code size
- 0 B
- Finish reason
- length
- Served by
- Claude Platform on AWS
- Model id
anthropic/claude-haiku-5.5- Reasoning sent
{"effort":"max"}- Max output
- 128,000 tokens
- Generated
- Nov 10, 2026
What it was asked
The prompt
“i want a breakout game where the paddle is a hamburger and every brick you break explodes into tons of little hearts”
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task. Output rules: - Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block. - Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task. - Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw. - The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar. - Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction. - Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session. - Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing. - The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message. - The code must run with zero errors in the console of the latest Chrome.
Reasoning trace (128,000 tokens)
I'm working out what the user needs: a breakout game where the paddle is a hamburger and broken bricks burst into lots of little hearts. The output has to be one complete HTML file with everything inline, no external resources, and no localStorage, and it should look right at 1280x800. Still working through the breakout setup: the paddle needs to read as a hamburger, the bricks should burst into little hearts, and the game has to start in an AI demo mode that waits for a click or keypress. I'm getting the demo's start behavior sorted: the game should open with a "Click or press a key to start" overlay while the AI plays in the background, with the overlay possibly semi-transparent so the action stays visible. Since the screenshot lands about three seconds after load, I want the ball launched early and bricks breaking, with the hearts bursts showing, well before then. Checking the timing for the first few seconds: the ball should reach the bricks in roughly 1.5 to 2 seconds, so the first hearts burst lands well inside the screenshot window. I'm weighing where the "Click or press a key to start" message should sit, since a full-screen overlay would hide the demo play. A small semi-transparent banner near the bottom or center seems better, so the game stays visible behind it, and I'm considering a title above it as well. I'm laying out the playfield now: a portrait logical area around 480x720, centered, with side panels on wide screens for the title, score, lives, and instructions. On narrow phones it would shrink to roughly 355px wide while keeping the same proportions. I'm planning the game states now: a demo state that waits for a click or keypress, a playing state under user control, and a game-over state. In demo mode the AI should restart itself when it loses its lives, while a real game restarts only after the player's input. Now I'm settling on the demo's ending: after a game over in a real game, it drops back to attract mode, with the AI playing again and the "Click or press a key to start" prompt showing. Now I'm sketching the hamburger paddle: a golden-brown dome bun with sesame seeds on top, then lettuce, tomato, patty, cheese, and a flat bottom bun, all drawn on the canvas. The paddle is roughly 96 units wide, with the layers stacked into a height of around 34 units. I'm settling the paddle's collision: the ball should bounce off the top bun, so I'll use a rectangle that covers the top portion of the burger and let the rest of the stack sit below it as visual only. Next I'm writing the ball's design, and it can be a simple glowing ball since the user only asked for the hamburger paddle and the hearts. I'm also settling how the paddle bounces: the ball only bounces when it's falling and crosses the top of the burger within its width, so it never gets under the paddle. I'm weighing the ball's look next. A small bright cream-white ball with a soft glow would stand apart from the hearts, which are red-pink, so I'm leaning away from tomato red and pickle green. I'm picking the brick palette now: soft pastels like pink, coral, peach, butter yellow, mint, and lavender, with some tougher bricks that need two hits and show a lighter, cracked state. I'm deciding how the hearts should look: they'll mostly take on the brick's own color with some variation, plus a share of pink and red ones. Each broken brick should throw off somewhere between 28 and 45 of them, and since a few dozen bricks breaking could mean well over a thousand particles, I want to pre-render the heart shape rather than rebuild it every frame. I'm settling on the particle system for the hearts: pre-rendering a heart sprite in a few colors so each burst can be drawn cheaply with rotation and scale. Each heart starts from the brick's center with a random direction and speed, then falls under gravity with some drag, spinning and pulsing in size before fading out over a second or two. Still writing the heart particles, with a heartPath helper built from bezier curves so each burst can be drawn cheaply. Still writing the heart shape, sketching out a bezier-based path so the hearts can be drawn cheaply. Still writing the heart shape, I'm checking the bezier control points for a symmetric heart about 100 units wide and 70 tall. Still writing the heart shape, I'm defining a drawHeart helper that scales a normalized bezier path to any size. Still writing the heart shape, I'm weighing a Path2D built from an SVG path string instead of hand-coding the bezier calls, since I can prebuild it once and fill it with a transform for each particle. Still writing the heart sprites, I'm considering prerendering each color to an offscreen canvas and drawing them with drawImage plus rotation, since filling a Path2D for every particle every frame would cost too much. I'm picking the heart colors now: a set of pinks and reds, with white and light pink for contrast, and the brick's own hues mixed in. Rather than drawing every heart from scratch, I'll cache one pre-rendered sprite per color and reuse it for each particle. I'm also avoiding per-particle shadows, since a few large translucent glow circles at the explosion center should give the same feel much more cheaply. Now I'm settling the brick explosion: each broken brick gets a shockwave ring that expands and fades, and I'm considering a subtle screen shake on larger breaks. For collisions I'll use standard rectangle checks, working out which side the ball hits so it can bounce correctly. Now I'm settling the physics: a fixed time step keeps the ball's movement steady, and I'm checking that at around 350 px/s on a 640-tall field, the first bricks should break within the three-second screenshot window. Still working on the collision code, I'm checking whether the ball's center plus radius overlaps the brick, then comparing the overlap depths to decide which side it hit. Still on the collision code, I'm settling the paddle bounce: when the ball is falling and reaches the top of the paddle within its width, the hit position sets the outgoing angle up to about 60 degrees, with a minimum vertical speed so it never stalls sideways. I'm also covering the walls, where the ball bounces off the sides and top, and a miss past the bottom costs a life. Lives will show as heart icons in the HUD, and bricks add to the score. Now I'm laying out the levels: a few patterns with different color arrangements, including a heart-shaped one for level three, and a grid of 10 columns by 8 rows in the 480px field. Now I'm laying out the brick grid: 10 columns at about 41 px wide with 4 px gaps, seven rows starting near the top, which leaves the paddle clear at the bottom. Level progression will show a short "Level clear!" message, then reset the ball to the paddle and load the next layout, and demo mode follows the same flow. For tougher bricks, I'm considering a lighter color and a crack line after the first hit. Now I'm weighing a softer hit for the tougher bricks: a single hit flashes them and throws off a handful of tiny hearts, and only the final break sends up the full burst of 36 to 48. I'm weighing whether to add sound on brick breaks with Web Audio, but the AudioContext might need a user gesture first, so I'm not committing to it yet. I'm weighing a sound layer too: short synthesized blips for brick pops, paddle hits, and lost lives, with the AudioContext created only after the first click so the browser doesn't block it. I'm also thinking about a small mute toggle, though it would add UI I'm not sure is worth it yet. I'm deciding whether to add a mute toggle, since the sounds could get annoying, and I'm weighing the extra code against the file size, which I'd guess lands around 600 to 800 lines. I'll create the audio lazily on the first click or keypress and wrap it in a try/catch so it can't throw errors. Now I'm laying out the start flow: the game opens in an attract mode where the demo AI moves the paddle and the ball launches on its own, with a pulsing "Heartburger" title and a hint to click or press a key. The first click or keypress switches to real play with a fresh game at level one, score zero, and three lives. I'm settling how the ball behaves at the start: in player mode it stays on the paddle until a click, space, or up arrow launches it, while in demo mode the AI launches it almost immediately so the attract screen is never still. Now I'm settling the start flow and the controls: a click or keypress during the attract screen begins a new game, and after a lost ball the ball waits on the paddle until the player launches it. Mouse movement will drive the paddle position through the page, mapped into the game's logical coordinates. I'm settling the controls: the paddle follows the mouse or touch directly, with arrow keys or A/D as an alternative, and space or up launches the ball. I'll set `touch-action: none` on the canvas so dragging on mobile doesn't scroll the page, while keeping the layout from scrolling at all. Now I'm sketching the page layout: the body fills the viewport with no scrolling, and the playfield sits centered with a HUD bar above it, showing score, hearts for lives, level, and the sound toggle. I'm sketching a desktop layout with three columns: a left panel for the title and how-to-play text, the playfield in the middle, and a stats panel on the right so the sides don't sit empty. I'm thinking about a single top bar spanning the full width, with the title on the left, stats in the middle, and the sound toggle on the right, with the canvas centered below and scaled to fit the remaining height. On mobile the bar would wrap into two rows, title first and then stats. Now I'm working out the canvas sizing: the field keeps its 3:4 proportions and fits whatever height is left under the top bar, with the drawing scaled so the logical coordinates stay fixed. I'm sizing the playfield for a 1280x800 window: about 708px of height is left after the top bar and padding, which gives a field around 531px wide. On a 375px phone the top bar may wrap to two rows, but the height still isn't the limiting factor there. I'm also considering drawing the lives as inline SVG hearts in the DOM instead of emoji, since emoji rendering varies between platforms. Writing the heart icon as an inline SVG path... Now I'm settling on a session-only best score kept in memory, since localStorage isn't allowed, and I'm weighing whether the "click or press a key to start" message should be an overlay over the canvas or sit somewhere that doesn't hide the playfield in the screenshot. I'm deciding where the "click or press a key to start" message goes, since a card in the middle of the field would cover the bricks and the falling hearts. I'm considering a semi-transparent card, slightly smaller than the field, with a pulsing line of text, so the demo stays visible behind it. I'm weighing where the "click or press a key to start" message goes: a small semi-transparent card in the middle of the field, around 260x110, so the bricks above stay visible, with the title sitting in a larger display inside the attract overlay. I'm settling on a centered attract card with a title, a short tagline, and a pulsing "click or press a key to start" line, semi-transparent so the demo keeps playing behind it. Once the player starts, the card fades out, and after a game over it will show the score and a prompt to play again. I'm settling the attract card's messaging: when the game ends, the card will show the score with a "click or press a key to play again" prompt, and the demo will restart on its own after a short pause so the screen never sits empty. I'm planning the demo AI so it plays well most of the time but misses now and then, which keeps the attract screen lively. It'll predict where the ball will cross the paddle line, bouncing off the walls, and move toward that spot with a small random error. I'm working out the demo AI's aim: it predicts where the ball will cross the paddle line, folding its path off the side walls, and then adds a random error so it sometimes misses. I'm picking a dark plum background so the pastel bricks and pink hearts stand out, and I'm sketching a 10-column grid of up to nine rows for the level layouts. I'm settling on a deep plum background, with a radial gradient fading to near-black at the bottom, so the pastel bricks and pink hearts glow against it. I'm weighing the brick palette next: a sunflower yellow, a peach orange, and a pink that might be too close to the hearts. Now I'm picking the brick colors: a sky blue, a mint green, and a lavender, each tinted toward white so they sit well against the plum background. For the hearts, I'm mostly matching the brick's own color, with a smaller share drawn from a few pinks and white so the field doesn't go flat. I'm settling the tough bricks next: they'll look like sesame-topped buns in a toasted tan, which fits the hamburger theme, and I'll mark them with a few small seed dots. I'm laying out the levels as small string grids, each cell a brick color or a tough brick: a rainbow-rows layout first, then a checkered one that alternates with the tougher bricks, and then a heart-shaped mask for level three. Now I'm generating the heart-shaped level mask cell by cell: for each grid position I map the column and row to coordinates and test whether it falls inside the heart curve. I'm checking the heart shape against the implicit curve, mapping each grid row to a y value from top to bottom and each column to an x value across the width, then testing whether the cell lands inside the heart. I'm sketching the level layouts on a 10-column grid, with a rainbow rows layout, a checkered one mixing in tough bricks, and a heart-shaped mask for level three. For the heart I'm testing each cell against the implicit heart curve, and I'll keep the grid at 10 columns by 8 rows. Level four will be a pyramid with tough bricks in the middle. Next I'm setting the level 5 and beyond to use a procedural random pattern whose density rises with each level, with ball speed starting at 330 px/s, growing 20 per level, and capping at 520. The brick grid starts 20 px in from the left and 70 px down, with a 4 px gap, and the paddle sits at y = 584. Now I'm sizing the paddle as a burger, about 92 units wide and 40 tall, and drawing it from the bottom up: a golden bottom bun with rounded corners, then a dark brown patty just above it. Still writing the burger paddle: grill marks on the patty, then a wavy cheese layer, a tomato slice, and a wavy lettuce layer, all stacked under the top bun. Still sorting out the burger paddle's collision box: the top bun dome is the surface the ball actually hits, while the lower layers sit below it and can't be reached. I'm checking the paddle collision: the ball should bounce only when it's moving downward and its edge reaches the top of the bun dome, with a little tolerance so a fast ball can't tunnel through. On a hit I'll snap it back above the paddle and reflect its vertical speed, with the horizontal component set by the angle of contact. Still writing the paddle's movement code, which will ease the burger toward the mouse position over time. I'm wiring up the paddle's smooth follow-the-mouse movement and the keyboard acceleration, then adding a short fading trail behind the ball for a bit of glow. For the hearts, each brick bursts into 36 to 48 of them, scattered in every direction with a slight upward bias and speeds between 80 and 300 px/s, and they'll fall under gravity afterward. Still writing the particle draw loop: I'm setting the transform for each heart by hand instead of saving and restoring state per particle, since that's cheaper with about 1,500 hearts on screen. Still writing the particle transform: I'm building a matrix per heart from its rotation and scale, folding in the base device-pixel scale, so each one draws without save and restore. Still writing the particle transform: I'm setting a per-heart matrix from rotation and scale, folding in the base device-pixel factor, and drawing each sprite at the origin. I'm checking the heart sprite's resolution against its on-screen size, and the 64px sprite scaled down to about 14px should look smooth. Brick breaks will also get a brief white flash that fades over 0.15 seconds before the brick is removed and its hearts spawn. I'm adding a shockwave ring that expands from the brick's center and fades out, plus a brief pink radial glow at the same spot. I'll also pop a "+10" score text up from the brick with a fade, using a bold system-ui font. Brick count is 60 per level, roughly 36 hearts each, and I'm thinking about capping total active hearts at 1800 once the burst volume gets large. Now I'm getting into the main loop: a requestAnimationFrame cycle that caps dt at 1/30 so a backgrounded tab can't cause a huge jump. I'm also planning a state machine, starting with an attract mode. Still setting up the game state: a single object holding the level, score, lives, bricks, ball, paddle, particles, popups and rings, with a level state that moves between playing, serving and over. I'm setting up the game flow: the demo starts with the ball launching automatically after half a second, and pressing start for a real game resets everything and launches the ball right away so the player doesn't have to press a second time. Next I'm wiring up input: pointer or key presses during the attract demo will start a real game, and in user play a click launches a stuck ball. I'm also making sure the key listener sits on the window so input still registers after the canvas loses focus. I'm handling the end-of-game flow: when lives run out in demo mode, the attract loop restarts after about 1.2 seconds, while the overlay keeps prompting for a start. For a user game over, I'll show the score with a play-again prompt for roughly 2.5 seconds, then hand control back to the demo. I'm laying out the end-of-level and life-loss flow: clearing all bricks triggers a short "level clear" moment with a big burst of hearts, and losing the ball costs a life and sends the game back to serve. I'm settling the overlay card: a bold title with a short tagline, a pulsing "click or press a key" prompt that changes to a score line after a game over, and a small hint about moving and launching underneath. I'm settling how the overlay and input fit together: the overlay will ignore pointer events so clicks fall through to the stage, which will handle starting the game, while keyboard input stays on the window so it still registers without focus on the canvas. I'm settling the input handling: keyboard controls stay on the window so they still work, the paddle follows the mouse only once a real game is running, and the held left and right keys drive movement during play. Now I'm settling on a light, dotted background for the field, drawn once onto an offscreen canvas and reused each frame so it doesn't have to be redrawn every time. I'm settling the background: instead of redrawing a heart pattern every frame, I'll pre-render it once onto an offscreen canvas at the current resolution, so each frame only needs a single draw. Still writing the background pass: I'm pre-rendering the field at the scaled backing-store resolution so each frame only needs a single draw, then resetting the transform for the logical drawing. Drawing the bricks directly each frame seems fine: about 60 of them, so a rounded rect with a highlight strip costs very little, and I can skip pre-rendering sprites for each color and type. Still writing the drawing code: bricks are rounded rectangles with a light top strip and a darker bottom edge, and the ball gets a glow behind a bright core. I'm also keeping a short trail of the last ten ball positions. I'm laying out the hamburger paddle in relative coordinates, with a base width of 92 and a total height of 46. The top bun is a dome drawn with a bezier curve from its bottom corners up over the top. Working out the dome for the top bun: I'm using a cubic curve with both endpoints at the bottom of the dome and control points above them, and checking where that curve actually peaks. I'm checking the dome math: with the endpoints at 17 and both control points at -4, the curve peaks at about 1.25, so the top bun rises roughly 16 units above its base. Still writing the paddle: I'm placing seven sesame seeds along an arc across the top bun, each a small rotated ellipse in cream. Still writing the paddle: I'm adding a wavy lettuce band just under the bun, slightly wider than it, with a green fill and a darker outline. I'm planning a helper that draws the wave along its top edge. Still building the hamburger: a red tomato slice sits just under the lettuce, a rounded band slightly narrower than the bun, and then a cheese layer with a wavy drip edge that gets a darker outline. Still writing the paddle's lower layers: a dark brown patty a few units inside the bun's width, with faint grill marks across it, then a bottom bun with a darker base. The whole burger is about 46 units tall, so the dome top becomes the collision line for the ball. Still on the collision code: I'm checking each live brick for overlap with the ball's bounding box, and skipping any brick the ball clearly misses on either axis. Still on the collision code: I'm finishing the brick response, comparing how far the ball has pushed into the brick from each side and treating the smaller overlap as the side it hit, then reversing that velocity component and nudging the ball out. Still on the collision handling: once the ball's overlap says which side it struck, I'm reversing the matching velocity component and pushing it clear, then registering the hit on the brick. Still on the brick response: when the ball is clearly hitting a brick, a destroyed brick triggers its burst and adds to the score, while a damaged one just flashes. The ball keeps its speed through reflections and creeps a little faster with each break, up to a cap. I also want to make sure it never gets stuck bouncing almost flat, so I'm checking that the vertical speed stays at a reasonable share of the total. Still on the physics: I'm clamping the ball against the walls and the top, then handling a ball that falls past the paddle as a lost life, with the demo launching the serve at a random slight angle after a short wait. Still writing the AI: when the ball is heading down, I'm predicting where it will cross the paddle line, and when it's heading up I'm just drifting toward its current x with a little noise so the movement looks natural. Now I'm working out the AI's aim: it will use the same predicted landing point when the ball is coming down, and when the ball is going up it'll just head for the center with a bit of drift. I'm also setting the paddle's top speed high enough, around 700 px/s, so it can keep up with the ball and the demo still looks good. Now I'm setting up the level layouts as rows of characters, where a dot is an empty cell, digits pick a normal brick color, and a T marks a tough brick that takes two hits. Tough bricks will show a dark zigzag crack after the first hit so the player can see the damage. Now I'm sketching out the level layouts as rows of characters, starting with a plain rainbow of six colored rows that might be too bland. I'm also considering a checker pattern of tough bricks, but that could be too hard for early levels, so I'll mix in a honeycomb-style offset layout and maybe a heart-shaped mask later. Still laying out the level data: I'm reviewing the heart level, which would fill pink bricks inside a tough outline, and sketching a burger-stack layout with a tough top bun row. Still laying out the level data: I'm sketching the remaining layouts, a honeycomb-style pattern with the bottom row of tough bricks and a pyramid-like arrangement. Still writing the level generator: I'm finishing the random layout fallback for later levels, then working out a heart-shaped mask by testing each grid cell against a heart equation to decide which cells become bricks. Still on the heart mask: I'm testing each grid cell against the heart equation to see whether it lands inside the shape, and the top row checks out as outside near the center. Checking the heart shape row by row: the top row falls outside the curve, and the second row sits right on the notch, barely inside at the center. Checking the heart outline row by row, the cells near the center of the second row land inside the curve, so the notch is what stays empty. Now I'm checking the heart outline row by row, and the second row's cells near the center fall inside the curve while the outer ones don't. Now I'm checking the heart outline's third row, and the cells near the center fall inside the curve while the outer ones spill past it. Still checking the heart outline row by row: the fourth row's cells near the center fall inside the curve, while the outer ones on either side spill past it. Now I'm checking the heart outline's fifth row, where the cells near the center still fall inside the curve but the outer ones past about ±0.45 have to be tested against the wider part of the shape. Still checking the heart outline row by row: the fifth row's cells near the center land inside the curve, and the ones at about x = -0.75 fall just outside it. Still checking the heart outline row by row: the sixth row's cells near the center fall inside the curve, and the outer ones at about x = ±0.45 and beyond still need testing against the curve. Checking the heart's bottom row: at the center x=0 it's still outside the curve, so the shape ends one row earlier and the last row can stay empty. Working through the heart's row layout: the top row is empty, the notch row fills six cells near the center, and the widest rows reach eight cells before tapering down to a two-cell tip. Still checking the heart shape: the top notch is barely visible because row 1 is so close to the curve's peak, so a bigger grid with more rows might separate the lobes better. Now I'm trying a finer grid for the heart level, with 9 rows instead of 8, so the top notch separates the two lobes better. The bottom tip at about y = -1 would fall between the second-to-last and last rows, so I need to test whether those cells land inside the curve. Hand-designing a heart bitmap instead of using the implicit formula should give a cleaner shape with a clear notch at the top, so I'll go with that. Still sketching the heart bitmap by hand, now trying a 10-column pattern that stays symmetric around the center. Still hand-building the heart bitmap, I'm checking which columns fill each row so the shape stays symmetric around the center. Still sketching the heart bitmap, now mapping out a taller version with more rows so the level has more bricks. Still laying out the heart bitmap, I'm settling on an 8-row version with two full-width rows through the middle, and the notch at the top stays open. Still settling the heart level: I'll mix pink and peach bricks for the body and mark the top lobes as tough ones, with the pink hearts giving the bursts a fitting look. Now I'm settling on the level layouts, trying a diagonal rainbow where each brick's color follows its row plus column, so the six colors form stripes across the grid. Still writing out the level layouts: I'm setting up a checker pattern with tough bricks on the even cells and colored bricks on the odd ones, and I'll follow it with the heart level and a striped layout. Now I'm sketching the rest of the level layouts: a pyramid that widens row by row with tough bricks in the lower tiers, and then a set of random procedural layouts for the later levels. Still writing the level setup: I'm adding a speed ramp that starts at 340 and caps at 520 as levels go up, then defining the palette with yellow, peach, pink, sky, mint, and lavender bricks plus a gold tough brick with a darker base. Still on the explosion effect: the particles will be colored either in the brick's own color or from a set of pinks and white, picked at random, and I'm adding a small white highlight on each heart to give it some shine. Still writing the heart sprite: I'm setting up a canvas and centering the origin so the heart path can be drawn, then I'll add a small translucent white ellipse on the top-left lobe for a glossy highlight. Still working out the heart's curve, I'm measuring how far the left lobe reaches on its way down to the tip. Still working out the heart's curve: the left lobe bottoms out near x ≈ -30, and I'm checking the top dip of the curve, where the y-values drop to about -22 at t=0.7. Still working out the heart sprite's bounds: the left lobe reaches about x ≈ -30 and the top dips to roughly y ≈ -22, so the shape spans about 61 by 52 units. I'm centering it near (0, 4) and planning to scale the sprite to fit. Still sizing the heart sprite: the shape spans about 61 by 52 units, so a 0.95 scale keeps it inside a 64-pixel canvas. Still writing the particle transform: I'm working out the scale factor so the sprite's heart comes out at roughly the particle's size. Writing the heart sprite drawing code... Now I'm setting up the HUD layout, starting with the top bar on the left. Now I'm setting up the HUD, starting with a gradient "Heartburger" logo and a small inline SVG hamburger icon beside it. Now I'm adding a speaker icon for the sound toggle, with a text "OFF" label when muted, and I'm keeping emoji out of the interface. Lives will be drawn as SVG hearts instead of a heart character, since that glyph might not render everywhere. Now I'm writing the overlay markup: a centered card with a title, a pulsing start message, and a control hint, all inside a relative stage container with the canvas. On touch devices the hint should say to drag instead. Now I'm placing the "Launch" hint above the paddle in the canvas, and I'm leaving the top of the field clear since the HUD already covers it. For the level-clear celebration, I'm planning a fountain of about 160 hearts rising from the middle of the field. Writing the brick-burst function next, with the hearts spawning from the center of each brick. Now I'm setting up the burst itself: each brick throws out somewhere between 34 and 48 hearts, launched at random angles with a moderate speed and a slight upward lift. Sizes skew small, lifetimes run around 1 to 2.5 seconds, and each heart spins while gravity and drag slow it down. I'm also adding about eight tiny, fast sparkle hearts so the total lands near 45. Now I'm getting into the sound effects: a short sine pop for each brick break, a triangle blip for paddle hits, a quiet tick off the walls, a falling sawtooth when a life is lost, and a little arpeggio on level clear. I'm wrapping the audio in try/catch and only creating the audio context after a user gesture, with sound off in the demo. Now I'm wiring up the input handling: a pointer press on the stage starts the game from the attract screen, or launches the ball if it's stuck to the paddle. Keyboard works the same way, with Space or Up launching the ball during play. Now I'm wiring up the keyboard and pointer controls, making sure the paddle follows touch drags and mouse movement across the stage. Next I'm wiring up the paddle position: it follows the pointer's logical x-coordinate, clamped so it stays inside the field, and it rides along with the ball while the ball is stuck. Now I'm settling the game's state machine: a serve phase where the ball sits on the paddle (auto-launching after 0.6 seconds in the demo), a play phase while the ball is moving, a clear phase that waits 2.2 seconds before the next level, and an over phase that lasts 2.5 seconds for a real player or 1.2 seconds in the demo before returning to the attract screen. Losing a life during play sends the game back to serve if lives remain, otherwise to over. Now I'm working out how the game's serve and launch flow should work for a real player: the first start input launches the ball immediately, and later serves wait for a tap or Space/Up. Now I'm setting up the brick appearance: each brick scales in from zero with a slight stagger, and I'll only animate it while it's still growing. Bricks get a rectangle, a color, hit points, and flags for flash and cracking, with tough ones getting a special color. Still writing the ball launch: it gets a random angle within about 14 degrees of vertical, and the speed follows the level's base, creeping up with each brick broken. Now I'm settling the paddle dimensions: a width of 96 so the burger reads clearly, sitting near the bottom of the field with its dome top at about y 572. Now I'm settling the brick grid: a lot of empty space will sit between the bricks and the paddle, which leaves room for the ball to bounce and the hearts to fly. Maybe the bricks should be a bit taller and sit a little lower, so the wall has more presence. Now I'm settling the paddle's AI: it works out a target and eases the paddle toward it each frame, with a proportional speed capped at 620 pixels per second. Now I'm working out how the AI picks its target: while serving it drifts the paddle around the center with a slow sine wobble, and when the ball is coming down it predicts where the ball will cross the paddle line, folding that x back inside the field walls. Next I'm checking the wrap-around math for the ball's x-position: fold the predicted coordinate back into the field walls so it reflects correctly. Then I'll add a small random error to the AI's aim after each paddle hit so it doesn't play perfectly. Now I'm sorting out the AI's tracking and the keyboard and mouse controls. For the user, the paddle eases toward the pointer and keys push it sideways, and I still need to tidy up the HUD and score updates. Now I'm deciding the overlay text for the attract screen: a short tagline like "Break the bricks. Shower in hearts.", then a pulsing prompt to click or press a key to start, and a smaller hint line about dragging or the arrow keys. Now I'm writing out the attract-screen overlay copy: after a game over it shows the points, a prompt to click or press a key to play again, and the same control hint underneath. The card hides once play starts, and I'm considering a more translucent backdrop so the demo stays visible behind it. Now I'm settling the page styling: a dark card with a pink accent border and glow, a deep plum field background, and CSS variables for the background, panel, pink, gold, and text colors. Now I'm setting the top bar to match the canvas width, with the title and stats wrapping on narrow screens. I'm weighing a side-by-side layout instead: title and how-to-play on the left, the field in the middle, stats on the right. That would keep the top bar from getting cramped at 531 pixels wide, with a stacked fallback for phones. Still laying out the page: a three-column grid with side panels for the title, instructions, and stats around the centered field, and the panels collapsing into a stacked layout on narrow screens. Now I'm laying out the responsive structure: on wider screens a three-part grid with the stage in the middle and panels on either side, and on narrow screens a single column with a compact header sitting above the stage. Now I'm laying out the header and stage for the responsive design: the title and a short tagline on one side, stats and a sound toggle on the other, collapsing into a stacked header above the field on narrow screens. Next I'm setting up the page layout: the header on the left with the title and tagline, the field in the middle, and the stats on the right. On narrow screens the stats strip will sit below the header, with the stage underneath. Now I'm working on the page layout for the game, planning for the stage to fill whatever space is left after the header and stats, with the canvas scaled to fit that area using a ResizeObserver and a window resize fallback. Still writing the page CSS: the body gets a full-height, hidden-overflow layout, and the app grid uses fixed side columns around a flexible center for the field. Now I'm checking the stage sizing: at 1280x800 the center column leaves the field about 573 by 764 pixels. On a phone the header and stats stack above a stage that still fits the field. I'm deciding that the header stays on top on phones and the tagline stays small. I'll hide the how-to text on mobile to save room, since the overlay already shows the controls. On a short desktop the stage still gets a usable height, and on a tiny landscape phone the field just gets smaller, which is acceptable. For desktop I'm planning the stats as a vertical column with large numbers, with the title and instructions on the left. Next I'm setting up the stats column and the sound toggle, with a compact mobile version of the stats row that fits on a 375-pixel-wide phone. Still writing the page CSS for the stats column and the mobile stats row. I'm working out how the desktop side panel stacks four stat blocks with the sound button underneath, and I'm making sure nothing forces a horizontal scroll. Still writing the canvas sizing: the stage measures its own box, scales the field to fit, and sets the backing store to match the device pixel ratio. Still making sure the canvas sizing doesn't loop back on itself: the stage is measured, the canvas gets fixed pixel dimensions, and the grid column is 1fr, so the field should stay within its allotted width. Now I'm fixing the stage row at the grid's flexible height, so the stage box can't grow past the window. The canvas gets centered inside a field container, with the overlay pinned to that field rather than the whole stage. Now I'm setting the canvas to the device pixel ratio and drawing everything in logical units, with a prerendered heart background that scales to the field. Still writing the particle code: I'm planning the particles as plain objects, with gravity and drag applied to each one every frame. Still working on the particles: each one falls under gravity and loses speed to drag, and I'm tracking its age, rotation, and spin. It fades out over its last third of a second and pops in briefly as it appears. Still writing the particle code: each burst also gets flash glows, shockwave rings, and popup text, all tuned to the same logical coordinates. Still writing the particle code: the popup text drifts upward and fades over its last 0.4 seconds, with a big "LEVEL 2" style title alongside it. Bricks count down their flash timers and animate in as they appear, and the ball stays stuck to the paddle until serve. I'm clamping the timestep to 0.033 seconds and about to split the ball's motion into substeps. Still writing the ball code: the collision check runs in small substeps so the ball doesn't tunnel through bricks, and its trail records the position once per frame. Now I'm writing the paddle as a hamburger drawn relative to its position. Next the level clear: when the last brick goes, the game shows a celebration burst of hearts rising from the bricks and a big "LEVEL 2" popup, then starts the next level. Game over is next: when the last life goes, the phase switches to over for about 2.6 seconds before the demo takes over. I'd like the overlay to still show the score and a "press a key to play again" prompt, so the card doesn't just reset to the default start message. Working on the card's state now: it'll show only during the attract phases, switching between a start prompt and a "play again" one after a player's game ends. Once the user starts a new game, the card goes hidden. Still working on the timing for the opening: I'll let the demo start a game and wait about 0.6 seconds before the ball launches from the middle of the bottom, climbing upward at roughly 340 pixels per second. Now I'm settling the timing for the opening: the ball should travel about 290 pixels up to the bricks, which takes roughly a second, so I'll drop the base speed to 330 pixels per second. The first break should come around the one-second mark, with the hearts spreading and more bricks going within the next half second, so the demo looks busy in the first few seconds. Now I'm writing the HTML document head and the page markup for the breakout game. Still writing the HTML head and the page markup: a title, the intro header with the logo and tagline, and the stage holding the canvas and an overlay card. Still writing the HTML markup: the intro header, the stage with its canvas and overlay card, and a stats sidebar with score, best, level, lives, and a sound button. Still writing the page layout: the intro column goes on the left and the stats on the right, with the stage in the middle. At 1280 wide the centre column works out to about 684 pixels, so the field scales against its height and stays inside the window. Still writing the layout: on narrow screens I'm switching to a single column with the stats row sitting above the stage, and I'm setting the app height to the full viewport. Still writing the stylesheet: the stats column stacks vertically on desktop and switches to a row on mobile, with the lives shown as small hearts. I'm also sizing the overlay card and setting the title and tagline font sizes for each layout. Still writing the SVG for the logo: a small burger icon with a curved top bun, a green lettuce strip, a brown patty, a yellow cheese layer, and a bottom bun. Setting up the game's constants and grabbing the canvas, field, and card elements, then starting the IIFE that holds all the logic. Still writing the game script: I'm setting up the canvas references, a background canvas for the heart pattern, and the scale factor, plus a palette of six colours for the bricks. Still writing the game script: I'm defining the palette of colours for the bricks and the heart effects, then working out the layout patterns for each level. Still writing the level layouts: I'm defining the heart shape as a grid of rows, with tough bricks on the top lobes and pink hearts filling the body. Still working out the level layouts: the fourth one is a burger stack, with a bun on top and the rest of the rows built up from there. Still working on the brick layouts: I'm settling on the burger stack with a tough bun on top, then cheese, lettuce, and tomato bands, though the patty row doesn't have a matching colour in the palette yet. Now I'm defining the level layouts, starting with a burger stack: a bun on top, then cheese, lettuce, and tomato bands, with a bottom bun to close it off. Still writing the level layouts: I'm building the pyramid by widening each row out from the centre, with every third row a tough brick. Next comes a procedural fallback for later levels, using more rows, random colours, and a rising share of tough bricks, and a helper that maps the layout codes into actual bricks. Now I'm deciding how the brick layouts get picked: the designed levels run in order for the first five, and after that I'll mix in designed layouts about a third of the time with random ones, and I'm turning each row into actual brick objects. Still writing the brick-building loop: each non-empty cell becomes a brick with its position, colour, and hit points, with tough bricks taking two hits. Still writing the brick-drawing code: each brick scales up with a little overshoot during its first moments on screen, and collisions are only checked once it has finished appearing. Still writing the brick-drawing code: each brick gets a gradient running from a lighter shade at the top down to a darker one at the bottom, and I'm drawing it as a rounded rectangle at its scaled size. Still writing the brick-drawing code: each brick gets a flat base colour, a thin white highlight along its top edge and a faint shadow along its bottom, which gives the pastel candy look. Tough bricks get a cream-coloured sesame seed effect when they're at full health, and a dark crack line once they've taken a hit. Still writing the game script: I'm defining a burst helper that spawns a cluster of heart particles with random angles and speeds, scaled by a multiplier. Still writing the particle burst helper: each particle gets a random angle and speed, mostly small sizes, a random spin, and a colour that's either the brick colour or a heart colour, then the list gets trimmed. Next I'm setting up the particle physics: gravity pulls each heart down, and drag slows it so it reaches a steady fall speed. I'm also adding a gentle side-to-side flutter so the hearts drift instead of dropping straight. Still writing the particle sprite: a heart shape drawn on an offscreen canvas, filled with the given colour and then given a gloss highlight. Still writing the particle sprite: I'm finishing the gloss highlight on the heart, placing it on the upper-left lobe in path units, then adding a faint dark edge and caching the result. Still writing the particle sprite: I'm checking the heart outline's lobes against the gloss placement and confirming the path shape is right. Still writing the heart particle sprite: I'm working out the scale from the sprite's pixel size to the particle size, and placing the heart's centre so the particle position lines up with it. Still writing the particle draw code: I'm setting up the transform so each heart rotates and scales around its position, then drawing the cached sprite at that spot. Still writing the particle draw code: I'm sizing the sprite so the drawn heart matches the particle's size, and I'm checking how the transform and alpha get applied per particle. Still writing the burger paddle: I'm defining its draw function with a squish factor that compresses it vertically and widens it slightly, anchored at the bottom centre. Still writing the burger paddle: I'm wrapping the drawing in a save, scaling it around the bottom centre, then restoring, with the top bun's curve starting from the paddle's upper left. Still writing the burger paddle's top bun: I'm shaping its dome with a bezier curve, filling it with a golden gradient, and checking the control points so the peak comes out centred. Still writing the burger paddle's top bun: I'm checking the dome's peak against its endpoints, which puts the top only a fraction of a pixel above the bun's edge. Still writing the burger paddle's top bun: I'm placing the sesame seeds along the dome, spacing them by where each one sits horizontally and tracing the curve's height at that point. Still placing the sesame seeds along the top bun: I'm spacing them across the dome, sitting each one just under the curve's edge and tilting it slightly by its position. Still writing the lettuce band under the burger's bun: I'm sketching a wavy top and bottom edge across the paddle's width, using a sine wave to make the leafy look. Still writing the burger's lettuce band: I'm wrapping a wavy shape across the bun's base with a sine ripple on both edges, filling it green with a lighter highlight along the top. Next I'll add the tomato slice under it as a rounded rectangle. Still writing the burger's tomato and cheese layers: a rounded red tomato slice with a light top highlight, then a wavy yellow cheese band with drips along the bottom edge. Still writing the burger's patty and bottom bun: I'm adding a dark rounded patty with a lighter top sheen and a few grill marks, then starting the bun's curved base. Still writing the paddle's collision: the top sits a pixel below the dome's peak so the ball doesn't visually overlap it, and I'm weighing whether a plain rectangle is good enough. Still writing the ball: I'm making it a small cream sesame seed that rotates to match its flight direction, with a glow behind it so it stays easy to see. Still working on the ball: I'm making it a cream sesame seed, an oval rotated to line up with its direction of travel. Still writing the pointer handling: I'm adding the pointer-down handler so a tap starts the game or launches the ball, and the pointer-move handler to steer the paddle toward the cursor. Still writing the keyboard handling: I'm wiring the arrow keys and A to steer, and Space or Up to launch the ball during serve, with the first keypress starting the game from the attract screen. Still writing the game's mode and state setup: I'm defining the attract and user modes, the serve and play phases, and a timer to drive the transitions. Still writing the game setup: I'm resetting the score, lives and level, centring the paddle, and loading level one with the ball waiting on the paddle. Still writing the game's launch and speed logic: the ball gets a random angle up to about 24 degrees off vertical when it leaves the paddle, and its speed scales with how many bricks have been cleared. Still writing the game's launch speed logic: I'm rescaling the ball's velocity each frame to the current target speed, and enforcing a minimum vertical component so it never gets stuck flying flat. Next up is the lives check and what happens when the game ends: a lost life updates the HUD and pops a red "-1", and at zero lives the phase moves to over with a short timer, after which a user game returns to attract mode. Now I'm wiring the lost-life and level-clear checks: when a ball falls past the bottom I'll drop a life, and at zero lives the game shifts to its over phase with a short timer before returning to the attract screen. Clearing the last brick will trigger a celebration, then the next level loads after a short delay. Still working out the clear phase: I'm deciding to keep the ball moving through the empty field while the level banner shows, and if it drops off during that phase, to reset it onto the paddle instead of costing a life. Now I'm working out the card: it stays hidden in user mode, and in attract mode it's shown with a message that depends on the card state. I'm settling the card's visibility: it should show in attract mode, and also when a user's game ends, so the result appears straight away instead of after the timer. I'll track that as a separate condition rather than tying it to the mode. I'm settling the click-to-restart behaviour: a press during the game-over pause should start a fresh user game straight away, rather than waiting out the timer. Now I'm working out the HUD: the score, lives and level readouts, and how they update when a life is lost. Still writing the HUD and sound: I'm building the lives as three heart icons that dim as they're lost, and setting up a Web Audio context that only plays tones in user mode. Still writing the sound effects: I'm wiring up a small tone helper that builds an oscillator and gain envelope on the audio context, and it only plays when the game is in user mode. Still writing the sound effects: I'm adding a delay parameter to the tone helper so the level-clear arpeggio can be stacked in sequence. Next I'm settling how the sound and explosions fire: the audio context only gets created on the first user gesture, and tones only play in user mode, so the demo stays silent with no warnings. Brick breaks get a full heart burst, and a tough brick that takes a hit but survives gets a smaller one. Still working on the background: I'm laying a vertical gradient from deep plum to near-black, adding a soft pink glow at the top centre, and drawing a faint scatter of small hearts in staggered rows. Now I'm working on the background: I'll stamp a faint scatter of the heart sprite at low alpha, around 30 pixels on the logical grid, so it reads as texture behind the bricks without competing with them. Next I'm styling the status card: absolutely centred over the field, semi-transparent dark plum with a soft pink border and a light blur behind it, so the message reads clearly over the game. Still writing the card's styling: the message gets a gentle pulse, and I'm checking whether the "Click or press a key to start" line will wrap on a narrow field. Styling the card now: a kicker line, the main prompt, and a smaller hint underneath. The prompt's font size scales with the viewport so it still fits on narrow screens. Now I'm settling the card's styling and layout: a kicker line, the main prompt, and a smaller hint, with the prompt's size scaling to the viewport so it still fits on narrow screens. For the game-over state, the kicker shows the score and the message asks for a click or key press to play again. Still writing the page layout: a three-column grid with the intro on the left, the game stage in the middle, and the stats on the right. Still writing the layout: the intro, stage and stats columns each get their own grid area and are vertically centred, and the field gets rounded corners, a pink glow and a faint outer ring. Still writing the stylesheet: I'm adding a mobile breakpoint that stacks the intro, stats and stage into rows, with the stats laid out side by side. Still writing the stats panel: I'm laying out each stat as a rounded tile with a small label and a large value, with the lives shown as a row of hearts. The sound toggle is a full-width button on desktop and a compact one on mobile, and I'm adding the score, best, and level markup to the sidebar. Still writing the stats panel markup: a label and value for score, best and level, lives as a hearts row, and a sound toggle. On mobile I'm thinking about keeping the four stats in one row and getting the sound button into the header instead. Still writing the mobile stats: a four-column grid for score, best, level and lives, with the sound button as a narrow last column, and I'm checking that the values fit within about 65 pixels each at 375 wide. Still writing the stats styling: the stat tiles get a small uppercase label and a bold value, and on mobile the sound button sits at the end of the same row. Still writing the intro markup: the key-controls note, the demo line, and the mobile rule that hides the how-to list. Still writing the game constants: the canvas is 480 by 640, with a ten-column brick grid, a 96-pixel-wide paddle near the bottom, and a 7-pixel ball radius. Still writing the constants: the brick grid is set with margins and gaps, and I'm working out the row positions and the paddle's vertical placement. Still writing the level layouts: the first is a diagonal rainbow of bricks, and the second alternates tough bricks with coloured ones in a checkerboard pattern. Still writing the level layouts: I'm filling in the pyramid pattern row by row, widening each row so the bricks form a stepped shape. Still working out the level layouts: I'm checking the pyramid rows, where each row's width is set by its distance from the centre, and the third row picks up the tough bricks. Still writing the level layouts: I'm adding a random layout generator that picks from a shape pool, with the rows built from the same width-by-distance pattern as the pyramid. Now I'm filling in the random layout generator, which builds a few rows of bricks with random gaps, tough bricks mixed in more often as the level rises, and a row count that grows slowly. Now I'm building the brick list from the level layout, skipping empty cells and marking the tough bricks, and I'm mapping each remaining cell to its colour. Still writing the game code: each brick is an object with its position, size, colour and a hit count, and the tough ones take two hits. Their entrance animation is staggered by row and column, so the grid builds up in a wave. Still writing the ball physics: each frame the ball moves in small sub-steps so it can't tunnel through bricks, and it stays on the paddle until launched. Still writing the ball's collision handling: walls bounce it back, and when it meets the paddle its angle depends on where it lands. Still writing the ball's paddle collision: I'm checking that the ball is falling and crosses the paddle's top edge within a small band, so it doesn't re-trigger while sitting on the paddle. Still writing the paddle hit logic: I'm checking that the ball is falling and crosses the paddle's top edge within a short band, so the bounce only happens once. The hit angle scales with where it lands, up to about 60 degrees at the edges. Still writing the brick collision: I'm checking which side of the brick the ball's centre is on, using the brick rectangle grown by the ball radius, so I know which way to bounce it. Still writing the brick collision: I'm finding the closest point on each brick to the ball's centre, and if that point is within the ball radius, I'll bounce it off whichever side it hit more directly. Still writing the collision check: I'm finding the closest point on the brick to the ball's centre, and if the ball is inside the brick itself, I'll pick the nearest edge to decide which way to bounce it. Still writing the collision code: when the ball's centre sits inside a brick, I'm picking the nearest edge to push it out and flip the matching velocity component. Still writing the collision code: the ball is pushed out of the brick along the contact normal, and the velocity is reflected only when it's moving into the brick, so I'm also planning to stop checking other bricks once one has been hit in that substep. Still writing the brick hit handler: each hit drops the brick's hit count and flashes it, and a tough brick that survives just gives a small burst and a bit of score. When it finally breaks, I'm spawning a larger burst in its colour and checking whether that was the last brick on the level. Still writing the game code: the bricks now pay out different scores, with normal breaks worth 10 and the tough bricks worth 5 on a hit and 20 when they finally break, and each break spawns hearts in the brick's own colour. I'm also planning a white "+10" popup at the brick's centre. Still writing the paddle movement: the AI paddle eases toward the ball with a speed cap, and the player's paddle follows a target that moves with the keys, then gets clamped to the canvas. Still writing the paddle movement: in user mode the target moves with the keys and the paddle eases toward it, and it stays put when nothing is pressed. Still writing the AI paddle: when the ball is heading down, it predicts where the ball will cross the paddle line and aims there with a small error, and when the ball is going up or the game is idling, it just drifts or sways near the centre. Still writing the AI paddle: the predicted landing spot gets bounced off the side walls by a small folding function, and the aim gets a random offset that I'm planning to make larger in later levels. Now I'm working out the AI's error margin, which grows a little with each level so it misses more often later. The paddle speed is capped at 620 px/s, which should still be fine at the faster ball speeds. Next I'm handling the serve and clear phases: the demo launches the ball on a timer, while the user has to press a key to launch, and the level-clear timer moves to the next level in both modes. Still writing the game-over and card flow: when a user game ends I'll switch back to attract mode, and I'm keeping the last user score around so the card can show it. The card logic is next: it stays visible whenever the game is in attract mode, showing the last user score with "play again" after a player game, and "start" otherwise, including during the demo's own game over. Now I'm setting up the card logic: it should show whenever the game is over during a user game, with the final score and a prompt to play again. I'll recompute the card text only at state changes like starting a game or losing the last life, rather than every frame. Still writing the card text logic: the start screen shows a game-over message with the last user score when there was a previous game, and otherwise a start prompt, with the HUD updating whenever score, best, level, or lives change. Still working on the pointer input: I'm attaching the pointer events to the canvas itself rather than the whole stage, so the paddle only reacts while the cursor is over the play field. Now I'm sorting out the canvas sizing: the stage's available width and height get trimmed a little, and the scale is picked so the fixed play area fits inside them without distorting. Still writing the canvas sizing: I'm working out the CSS and backing-store dimensions from the scale and device pixel ratio, and I'll redraw the background once they're set. Next I'm checking how the stage's clientWidth and the grid rows behave: the stage keeps its own size, so resizing the field inside it shouldn't feed back into the layout, though in the mobile layout I need to make sure the field can't stretch the row. Now I'm checking the layout rules for the desktop and mobile grids, making sure the stage fills the space without scrollbars, and that the field sits cleanly inside it. Still writing the background drawing: I'm filling a vertical gradient, then adding a soft radial glow near the top. Still writing the background pattern: I'm laying a faint grid of small hearts across the backdrop, staggering every other row, at low opacity. Still writing the background sprite: each heart gets drawn at about 20 logical pixels, centred on its grid point. I'm checking that the sprite's visual centre lines up with where I'm placing it, so the pattern sits evenly. Now I'm moving on to the main render function, which will draw the game each frame. The last piece was the background sprite check, and I'm going to add a dark vignette over the corners of the backdrop as a finishing touch. Now I'm drawing the frame: the background goes down first, then the bricks, the ball, the burger paddle, and finally the hearts on top so the explosions read clearly. Now I'm setting the hint text: in user mode during the serve phase, a pulsing white prompt tells the player to tap or press Space to launch, and attract mode shows nothing there. I'm also adding a big "Level n" banner at the start of each level, lasting about 1.8 seconds, which will even show "Level 1" on page load. Still writing the popup code: each popup fades in and out over its lifetime, and the big level banners also scale in a little as they appear. Still writing the particle update: each heart gets its age advanced, gravity applied, and drag so it slows as it drifts, and the expired ones are dropped from the list. Still writing the particle cleanup: dead hearts are skipped during the pass, so the list compacts in place, and if it grows past the cap I drop the oldest ones first. Next I'm working out each heart's scale over its lifetime, with a quick overshoot as it pops in and a fade-out near the end. Now I'm checking the ball's draw routine, which skips the drawing when the game is over. Still writing the ball's trail: I'm drawing fading pink dots behind it, with each older point a little more transparent. Still writing the ball's trail and glow: after the trail dots, I'm drawing a radial gradient glow around the ball, then rotating the coordinate system so the seed shape lines up with its direction of travel. Still writing the glow and seed: a radial gradient around the ball, then the seed drawn as a plain ellipse with a pale fill. Next I'm adding the lives display in the HUD, rebuilding its heart icons only when the lives count changes. Still writing the lives display: I'm building the heart icons as small SVGs, filled for remaining lives and dimmed for lost ones, and only rebuilding them when the count changes. Still writing the SVG heart icon for the lives display, then I'm moving on to the mobile sizing and the sound toggle button. Now I'm settling the click behaviour: after the sound button is pressed I'll blur it so a later Space press doesn't toggle it again, and I'm checking how the pointer acts in each phase. Serve launches the ball, attract and game-over start a new game, and play and clear ignore the click. Now I'm writing out the complete file, starting with the page styles and the body background. Still writing the page layout: a three-column grid with the intro on the left, the play stage in the middle, and the stats on the right, with the logo starting to lay out in a row. Still writing the page styles: the logo gets a flex row with a drop-shadow on its icon, and the title uses a pink-to-gold gradient text fill. I'm also setting up the tagline and the list of how-to-play steps. Still writing the page styles: the navigation rules are finished, and I'm moving on to the list items, which get a translucent panel and a gold bold label. Still writing the stat cards' styles: each card gets a translucent panel with a rounded border, and the lives row uses small heart icons that dim when a life is lost. Now I'm styling the playfield wrapper: rounded corners, clipped overflow, and a soft pink glow around it. Still writing the card styles: a centred panel with a dark translucent background and a border, sized to fit the stage. Still writing the card styles: the message panel gets a rounded border and a soft shadow, and the msg text is set to a bold pink-white that pulses in. Still writing the stylesheet: the layout collapses into a single column on narrow screens, with the stats becoming a row of compact cards and the how-to-play list hidden. Still writing the mobile styles: the stats row is set to a compact grid, and the sound button stretches to fill its cell. Still writing the mobile styles: the stat grid and the sound button are set, and I'm checking whether the tag line can stay on small screens. The hearts row goes flex, and the lives stat should fit comfortably at 375px. Still writing the intro markup: a logo row with a burger icon and the Heartburger title, then a tagline and a short how-to-play list. Still writing the markup: the header, the playfield with its canvas and message card, and I'm starting the stats column with the score and best readouts. Still writing the HTML markup: the stat readouts for level and lives are in place, and I'm adding the sound toggle button at the bottom of the stats column. Still writing the JavaScript: the game field is a fixed 480 by 640 logical grid with ten brick columns, and I'm setting up the constants for the brick sizes and the top offset. Still writing the game constants: the logical field is 480 by 640 with ten brick columns, and I'm setting the paddle width, the ball radius, gravity, and a cap on particles. Still writing the game constants and the utility helpers, with the canvas and DOM handles being looked up. Still writing the JavaScript: I'm setting up the helper functions, including a random-range helper and an ease-out curve for the heart pop-in. Still writing the heart sprite: a small offscreen canvas that paints a pink heart with a white highlight, cached per colour. Still writing the heart sprite's gloss and outline, then I'm setting up the cache so each colour is drawn once. Still writing the brick layout: a helper builds the rows, and I'm working out how each brick's position and colour get set from the grid. Still writing the brick layouts: each one is a list of row strings with a character per column, and I'm building the grid helper that fills them. Still writing the random layout helper: the row count grows with the level, capped at eight, and I'm working out the tough-brick character next. Still writing the random layout helper: I'm setting the bricks for each row by a roll, with some empty gaps, some tough bricks, and the rest coloured, and the tough share grows with the level. Still writing the brick builder: each character in a row string becomes a brick with a position, colour, and a tough flag, and I'm setting its appear timer so the wall fills in row by row. Still writing the game state: I'm setting up the brick and particle lists, the ball and paddle positions, and the mode the game is in. Still writing the game code: after the constants and helpers, I'm setting up the state for the bricks, particles, the ball and paddle, and the current mode. Still writing the game loop's setup: after the level loads, the ball is reset and the phase is set to serve, and the popups are being cleared for the new level. Still writing the game's launch code: the ball gets a random angle within a small spread and a speed that depends on the level, and I'm finishing the setup so it moves off the paddle. Still writing the launch code: the ball's speed is tied to the level and to how many bricks are gone, and I'm normalising its velocity so the speed stays steady. Still writing the ball update: I'm guarding against a near-zero vertical speed and then setting up the per-frame movement. Still writing the ball update: I'm setting the step count from the speed, moving the ball in small increments, and bouncing it off the side walls. Still writing the game loop: the ball moves in small steps scaled to its speed, bouncing off the walls, the paddle, and any brick it reaches, and it gets removed if it falls past the bottom. Still working out the ball's bounce-and-collision loop, and I'm checking whether bricks still animating in need to be skipped, though the ball is stuck during serve anyway. Still writing the paddle bounce: the hit position on the paddle sets the bounce angle, and I'm reading the speed for it. Still writing the paddle bounce: the new velocity comes from the hit angle and current speed, and the ball gets pushed back up to the paddle surface. Now I'm checking the ball's fall: if it drops past the bottom during the clear phase it just resets to the paddle without costing a life, and otherwise it loses one. Still writing the game-over logic: when lives run out the phase switches to over, the ball is hidden, and the score gets saved for the user's run before the card refreshes. Still writing the game's over-state handling: after the game-over card, the demo restarts after a short wait, and the wait is longer when the player was in a real game. Now I'm wrapping up the level-clear handler: it sets the phase to clear, starts a short timer, and fires off a burst of hearts from the bottom of the field. Now I'm checking the level-clear path: once the last brick is gone, levelClear() runs, and the "cleared" popup fades out before the next level loads, so the two messages won't overlap. I'll also be firing a burst of hearts from the top of the field when that happens. Next I'm adding the heart rain: about 120 hearts start near the top of the field and fall under gravity. I'm also firing a fountain from the paddle area so the celebration covers both ends of the screen. Still writing the collision code: I'm computing the normal from the ball's offset to the closest point on the brick, with a fallback that pushes the ball out through the nearest side when its centre is inside. Still writing the collision code: if the ball's centre ends up inside a brick, I'm pushing it out through the nearest edge and fixing its position to match. Still writing the collision code: when the ball's centre is inside a brick I push it out through the nearest edge and flip the matching velocity component, and otherwise I place the ball at the contact point and reflect it if it's moving into the brick. Still writing the collision code: when the ball's centre is inside a brick, I'm pushing it out through the nearest edge, and otherwise placing it at the contact point and reflecting it. Now I'm starting the brick-hit handler, which drops the brick's hit points and flashes it. Still writing the brick-hit handler: a surviving brick loses a hit point, flashes, and gives a small puff with a quick tone, while a destroyed brick is removed and triggers a larger burst, rings, a glow, and a score popup. Still writing the brick-hit handler: a brick that survives takes a hit and flashes with a small puff, while a destroyed one bursts into hearts, rings, a glow, and a score popup, and the last brick triggers the level clear. Still writing the burst helper: each particle gets a random direction and a speed scaled by the power, with some larger heart-shaped pieces mixed in. Still writing the burst helper: each particle gets a random direction and a speed scaled by the power, with a lift on top and some larger heart pieces mixed in. Still working out the burst size: I'm weighing whether about 44 hearts per brick is enough or whether it should go to 50-60 to feel like a lot more. Still writing the hit visuals: the ring grows outward and fades, and I'm working on the glow's radial gradient. Still writing the glow and popup drawing: the glow fades from pink, the popups drift upward and fade out, and the rings and flashes get their timers updated. Still writing the frame loop: each frame measures elapsed time, clamps it so a stall can't jump the physics, advances the timers, then updates and renders the game. Still writing the update loop: the paddle moves first, then the serve timer counts down in attract mode before launching, and the level-clear and game-over timers advance the phase until the next level or a fresh game starts. Still writing the update loop: the ball gets pinned to the paddle while stuck, and the trail, particles, popups, and brick fade-in timers all advance each frame. Still wiring up the update loop: I'm checking the phase-specific timers and making sure a lost ball during the clear phase resets without costing a life. Still writing the updatePaddle function: in attract mode the paddle eases toward the AI target, and otherwise it follows the keys and the pointer before being clamped to the field. Still writing the AI target: when the ball is stuck or hidden the paddle sways, and otherwise it tracks the ball as it comes down. Still writing the AI target: when the ball is moving down, I'm predicting where it will cross the paddle line and adding a small error, and otherwise I'm drifting toward a point between the centre and the ball's x position. Now I'm working through the timing on the demo's first serve: the ball sits on the paddle, which starts at the centre, for about 0.7 seconds before launching at a slightly random angle. I'm also checking that a paddle still moving at launch is fine, and that the stuck ball's position is handled in the update step rather than inside updateBall. Still writing the render pass: the background is drawn first, then the bricks, glows, rings, ball, paddle, hearts, and popups, with each brick easing in with an overshoot as it appears. Still writing the brick draw routine: the brick scales up with the easing, then gets its base fill, a white top highlight, and a darker bottom shade. Still writing the brick draw: I'm finishing the flash overlay, which fills the brick with a fading white tint while its timer runs down in the update step. Still writing the flash overlay and the rounded-rectangle helper: the rectangle path is built from four arcs so the brick corners stay smooth. Still writing the brick draw: the tough bricks get three small cream-coloured seeds, and I'm starting a crack line from the top edge of the brick. Still writing the brick draw: I'm adding the crack line and the seed marks, and I'm skipping the seeds while a brick is still scaling in. Still writing the ball drawing: I'm adding the trail and the soft radial glow, then setting up the transform so the ball's seed shape lines up with its heading. Still writing the ball drawing: the seed shape is rotated to match the ball's heading, with a stuck ball pointing straight up, and I'm adding a small white highlight on top. Still writing the ball drawing: the seed's long axis lines up with the direction of travel, and a stuck ball lies flat on the paddle, so its angle is set to zero. Still writing the burger drawing: I'm setting up a scale around the bottom edge so the paddle squishes on impact, then drawing the individual layers of the stack. Still writing the burger drawing: the bottom bun gets a warm orange gradient, and I'm starting its outline from the left edge along the top of the bun. Still writing the burger patty: it's a dark brown rounded bar sitting just above the bottom bun, and I'm about to add its top highlight. Still writing the patty's grill marks and the cheese layer, which will have drips along its wavy bottom edge. Still writing the cheese layer: I'm building its wavy bottom edge with drips, using a helper that walks across the brick width. Still writing the cheese layer's wavy bottom: a helper will trace the drips as a band across the width of the patty. Still writing the lettuce, with a wavy top and bottom edge built from a helper that walks across the patty width. Still writing the wave helper for the lettuce: it walks from one x to another, with a sine offset for the bumps and a bulge mode for the cheese drips. Still writing the lettuce's wavy edges: I'm starting the path at the top-left point, and the wave helper will draw each edge point by point so the bumps follow the patty's width. Still writing the cheese layer's wavy bottom: the bumps will hang down from the base line, so the drips read as dripping cheese. Still writing the burger's stacking order, with the top bun drawn last so the lettuce and tomato sit beneath it. Still writing the burger layers: I'm laying out the top bun, lettuce, tomato, cheese, patty, and bottom bun at fixed offsets, so the stack overlaps in the right order. Still writing the layer heights: the dome, lettuce, tomato, cheese, patty, and bottom bun each get a set y-range, with the lettuce and cheese edges wavy. Still writing the top bun: I'm defining its dome as a bezier curve so it peaks above the bun's base, with the seeds sitting on top. Still working on the top bun's dome: I'm checking the peak height at the midpoint and estimating how far the seed positions sit below it across the bun's width. Still writing the burger's shadow and bottom bun: the shadow sits under the stack, then I'm starting the drawBurger function with its x and y origin. Still writing the burger's bottom bun: the shadow goes under the stack, and I'm starting the bun's outline along its top edge with a warm gradient. Still writing the patty: I'm adding its grill marks as a thin, light stroke across the top of the patty. Still writing the cheese layer: I'm tracing its top edge across the patty and starting the drippy bottom. Still writing the burger's lettuce: I'm adding its wavy top edge across the patty width. Still writing the top bun: I'm starting its dome path at the left edge, with the gradient running from light gold at the top to amber at the base. Still writing the top bun's dome: it's a bezier curve that peaks above the base, and I'm about to close the path and fill it. Still writing the wave helper: it steps across the width in fixed increments, with a sine bump for the lettuce and an absolute-value bulge for the cheese drips. Still writing the cheese drips: the bumps hang below the cheese base, and the dome seeds come next, spaced along the top bun. Still writing the top bun's seeds: I'm spacing seven of them across the dome, each one lifted a little from the curve and tilted to follow its slope. Still working out the paddle's top edge: it lines up with the top of the bun's dome, and the stuck ball sits just above it. I'm also adding a short "Tap or press Space to launch" hint above the ball while it waits. Still writing the hearts: I'm setting up the per-particle draw loop, with each heart growing in briefly, fading out near the end, and wobbling slightly as it moves. Still writing the heart draw loop: I'm scaling each sprite by its growth and fade, applying a small wobble to its position, and setting the transform per heart before restoring the base transform at the end. Still writing the heart draw loop: I'm checking the sprite scale math so each heart's on-screen width matches its size, then moving on to the popups. Still writing the popup draw loop: I'm setting each popup's alpha from its age, with the fade-in and fade-out clamped, and the big ones use a larger font and stay in place while the small ones drift upward. Still writing the popup text: I'm setting the font and alignment, then stroking an outline in dark plum before filling the label in its color. Still writing the glow and ring effects: I'm setting up a radial gradient for each glow that grows and fades as its timer runs out. Still writing the glow and ring effects: each glow is a radial gradient that grows and fades over its lifetime, and each ring is a stroke that expands and thins out. Still writing the update loop for the particles: I'm advancing each one's timer, applying gravity and drag, and dropping the ones that have expired. Still writing the update step: I'm advancing each particle's timer, applying gravity and drag, and dropping any that go off screen or expire. Still writing the heart rain: I'm spawning a batch of hearts above the top edge at random x positions, each with a small sideways and downward velocity. Still writing the particle spawn helper, which takes position, velocity, size, color, and lifetime, and builds each heart with random rotation and spin. Still writing the audio setup: I'm wrapping the AudioContext lookup in a try block so it falls back cleanly if the browser doesn't support it. Still writing the audio tone helper: it builds an oscillator with a gain envelope, optionally sliding the pitch, and plays it after a short delay. Still writing the audio helpers: I'm defining the click sound for wall bounces, which plays a short tone at a given frequency and volume. Still writing the audio helpers: I'm settling on the break sound, a short pop arpeggio with a slight pitch slide, and a quieter tinkle layered just after it. I'm leaving out the wall ticks to keep the sound from getting noisy. Still writing the audio helpers: I'm adding the level-clear arpeggio, a life-lost tone, and a game-over tone, all with the sound helper. Still writing the lives display: I'm building a row of three heart icons, with the ones past the current lives count drawn in the dimmed style. Still writing the refresh card: I'm setting up its visibility, kicker, and message defaults, then branching on the attract mode first. Now I'm writing the refresh card's text: it's hidden by default, and the attract mode sets its kicker and message, showing the final score after a user game and "Demo running" otherwise, with the phase-over case handled after that. I'm settling on caching the refresh card's text and calling it every frame, comparing against the last values so the DOM only updates when something changes. Still writing the input handler: it calls ensureAudio first, then starts a user game if we're in attract mode or the game is over. Still writing the input handler: the canvas pointer listeners set the paddle position from the pointer and call the press handler, with pointer moves only tracking while the game is in user mode. Still writing the keyboard handler: I'm mapping the arrow keys and A/D to the left and right flags, and blocking the default scroll for Space and the arrows. Still writing the keyboard handler: the keyup listener clears the left and right flags for the arrow keys and A/D, and I'm about to add the window blur handler to reset them as well. Still wiring up the blur handler, which clears the left and right flags so the paddle stops if the window loses focus. Next I'm working on the stage pointer handling, which attaches only to the canvas, and checking that the card's pointer-events setting lets clicks reach the canvas beneath it. Still writing the resize step: I'm sizing the canvas to fit the stage while keeping the 1280x800 ratio, then setting its CSS width and height and matching the field to it. Still writing the resize step: I'm setting the canvas and field to the scaled size, keeping the background canvas in sync, and redrawing the background. Still writing the resize step: I'm checking that the background heart pattern is drawn correctly under the base scale. Still wiring up the init order: I'm calling resize first so the base scale and background are ready, then starting the game state and HUD and kicking off the frame loop. Still writing the init sequence: I'm checking that nothing touches the ball before it exists, and that the browser APIs I'm relying on are available. Now I'm checking how the demo plays out level by level. Clearing all 60 bricks on level 1 should take the AI around a minute or so, which is fine. The AI aims at the predicted ball position with a bit of error, and the paddle is wide enough that most hits land, with edge hits sending the ball at sharper angles. I'm checking the ball-loss path next: when the AI misses, the ball gets reset to stuck, and in the clear phase it stays in that state until the level loads again. Now I'm working out the ball-loss path: losing a ball costs a life, and once the lives run out it ends the game, otherwise the ball resets to the serve state with a short "-1 life" popup above the paddle. The HUD hearts update to match. Next I'm thinking about how bricks pop in at level start with an eased scale. Now I'm checking the layout math for the 1280x800 view: the three columns, the gaps, and the padding leave about 698px for the stage. Now I'm checking the layout at 1280x800: the field scales to about 573 by 764 pixels and sits centered in its column. The left intro and right stats columns each look like they'll fit their content comfortably. Next I'm working out the mobile layout at 375x667, where the intro and stats rows take up the top and the stage fills whatever height is left. Still working through the mobile stats row: I'm checking whether the score values fit in the narrow boxes at 375px, and I'm considering a smaller font size so a longer number like "10,000" doesn't overflow. Now I'm settling the mobile score area: the sound button will show "Sound" with a small On/Off state under it so it stays narrow, and I'm checking that a score like "10,000" still fits in the stat boxes. Checking the mobile stat boxes now: at 375px the lives hearts would overflow with 15px icons and 8px padding, so I'm dropping the hearts to 13px, tightening the padding to 6px, and keeping the layout otherwise as is. I'm also glancing at the intro heading width at desktop, where "Heartburger" should still fit within its column. Now I'm checking the field's styling: rounded corners and a drop shadow, with no extra floor or decoration. I also want an aria-label on the canvas, and I'm looking at whether drawing the full-size background each frame will cost much on a high-DPI screen. I'm checking the opening sequence: bricks start appearing with a short stagger, the "Level 1" popup shows in the centre, and the start card sits over the field. The first brick should break around 1.2 seconds in, once the ball launches at 0.7 seconds. The centre popup would be hidden behind the overlay card, so I need to fix that overlap. I'm moving the big "Level" popup down to about y=410, below the start card's area and above the paddle, so it doesn't sit on top of the card. The ball will cross that spot now and then, but that's fine for a transient popup. I'm checking whether the card overlay blocks the ball path in the middle of the field, which is acceptable since it's just the attract screen. I'm also thinking about the pulsing "Click or press a key to start" prompt, and whether the card's backdrop blur will be too heavy, though it should be fine. Finally I'm estimating the hearts' burst size: a 48x26 CSS-pixel brick with particles at 40–330 px/s and a drag of 1.3 should travel roughly 250 px at most before fading. I'm estimating how far the hearts travel: with drag, each one covers roughly 0.77 of its launch speed, so I'm scaling the speeds down to keep the burst from spilling too far across the field. Gravity should pull them down quickly, so most will be gone within about a second and a half. I'm also varying their sizes, with most small and a few larger. I'm settling the hearts' look now: a mix of brick-coloured and pink or white tints, with no glow, so they read well against the dark field. I'm also picturing the overall palette, dark plum with pastel bricks, a golden burger paddle, and a cream ball, and adding a little "+10" pop with white text and a dark outline. Now I'm writing out the final HTML for the breakout game, with a few small fixes: the HUD's best score should track the running maximum, and the hearts' burst speeds should be moderated so the explosion doesn't spill too far across the field. Still writing the stylesheet... Still writing the stylesheet, now on the logo's heading, with a gradient text fill for the title. Still writing the stylesheet... Still writing the stylesheet... Still writing the stylesheet, now on the card, stats and stat boxes. Still writing the game's constants: a logical 480×640 playfield, ten brick columns, a 96px burger paddle, and a gravity value for the hearts. Still writing the game's constants: a 480×640 playfield, a 96px burger paddle, and the hearts' colour palette and sprite shape. Still writing the game's JavaScript: I'm setting up the DOM references for the canvas, the HUD, the card and the sound toggle. Still writing the game's JavaScript: I'm building the helper functions for clamping, random values, number formatting and the easing curve. Still writing the game's JavaScript: I'm laying out the brick rows with a helper that fills each row column by column, and sketching a pyramid pattern that narrows toward the top. Still writing the game's JavaScript: I'm laying out the pattern layouts for the bricks, including a diagonal rainbow, a checker of buns and fillings, a heart shape, a burger stack, and a pyramid that narrows toward the top. Still writing the game's JavaScript: I'm laying out the pattern layouts for the bricks, with a diagonal rainbow, a bun checker, a heart shape, a burger stack, and a pyramid. Still writing the game's JavaScript: I'm defining the random layout generator, which picks a row count that grows with the level and rolls each brick as empty, tough, or a random colour. Still writing the game's JavaScript: I'm building the brick factory, which turns each layout row into brick objects with positions, colours and hit points, with the tough bun bricks taking two hits. Still writing the game's JavaScript: I'm defining the brick layouts and the factory that turns them into brick objects with positions and hit points. Still writing the game's JavaScript: I'm setting up the base multiplier and the empty arrays for bricks, particles, popups, rings and glows. Still writing the game's JavaScript: I'm declaring the state variables for the ball, paddle, bricks, score, lives and modes, and the key-state object. Still writing the game's JavaScript: I'm adding the functions for ball speed, resetting the ball onto the paddle, and launching it at a random angle. Still writing the ball launch: it picks a small random angle and sets the velocity from the current speed, then switches the phase to play. Still writing the ball's speed normalisation: it rescales the velocity to the current speed and makes sure the vertical component never drops below a minimum, so the ball can't get stuck flying almost flat. Still writing the AI paddle logic: it predicts where the ball will cross the paddle line by bouncing it off the side walls. Still writing the ball's update step: it works out how many sub-steps to take based on the current speed, so the ball can't tunnel through bricks. Still writing the ball's update loop: it steps the ball in small sub-steps, bounces it off the side walls and the top, and checks whether it has hit the paddle. Still writing the ball's collision loop: it checks each brick and stops once one is hit, and if the ball drops past the bottom it gets lost. Still writing the ball's paddle bounce: it sets the angle from where the ball hits the paddle, then resets the velocity and squish. Still writing the collision check: it clamps the ball's centre to the brick's edges to find the closest point, then measures the distance from there. Still writing the collision code: it measures how far the ball centre sits from the closest brick edge, and when the centre is already inside a brick it picks the nearest side to push it out through. Still writing the collision code: it finishes the reflection for the ball's centre hitting a brick's side, then calls the brick-hit handler. Still writing the collision code: the inside-brick branch flips the velocity away from the chosen side, and the normal reflection covers corner hits. Still writing the brick-hit handler: it takes one hit off the brick, and if it's destroyed, awards points and bursts out the hearts. Still writing the brick-hit handler: it's finishing the score, popups and sound for a destroyed brick, and checking whether the level is cleared. Still writing the burst helper: it spawns heart particles with random angles and speeds, scaled by power. Still writing the ball's lost-ball handler: it checks whether the level is cleared, then takes a life and resets the ball. I'm writing the ball-lost handler: it deducts a life, shows an "Oops" popup, hides the ball, and either ends the game or resets the ball into the serve phase. Still writing the game's JavaScript: I'm finishing the game-over handler, which sets the phase to over, picks a longer delay in user mode, hides the ball, and records the score for user games. Still writing the game's JavaScript: I'm finishing the level-clear handler and starting the burst of heart particles that fans upward from the paddle. Still writing the level-clear burst: it's fanning out the pink, pale-pink and yellow hearts upward from the paddle, then scattering a second wave of falling hearts across the screen. Still writing the level-clear burst: I'm setting the hearts to fall as a rain from above the top of the field, and noting that the cull only removes them once they drop past the bottom. Still writing the loadLevel function: it sets the level, builds the bricks, resets the ball and switches to the serve phase. Still writing the game's JavaScript: I'm setting up the level-one popup at the centre of the screen, then starting newGame, which resets the score, lives and paddle position. Still writing the game's JavaScript: I'm setting up the newGame reset, then starting the user game with audio enabled and a fresh score. Still writing the HUD refresh: it updates the score, best, level and lives displays only when their values change, and rebuilds the hearts for remaining lives. Checking the Material favorite path against the standard icon, and it matches, so the heart icon is set. Next I'm turning to the refreshCard function, which starts by picking a state for the card. Now I'm writing the refreshCard function, which decides whether the card shows and what its kicker and message say. It shows the card in attract mode, with different text after a finished user game, and in the over phase it shows the final score. It builds a key from those values and skips the update if nothing has changed. Still writing the update function, which runs each frame and handles the card and effects. Still writing the update loop: it advances the timers and runs the serve, clear and over phases, then moves the ball or pins it to the paddle, and finally updates the effects. Still writing the update loop: it advances the timers, and when the ball is pinned to the paddle it follows the paddle, otherwise it steps the ball and records a short trail. Still checking how the update loop handles the paddle and ball during the over phase, and whether the ball gets pinned or stepped there. Still writing the render function: it resets the transform, draws the cached background, then the bricks, glows and rings, the ball, the burger paddle, hearts, and popups, with a hint shown during user serve. Still writing the draw helper: it sets the hint's font and alignment, then strokes and fills a pulsing "Tap or press Space to launch" line above the paddle. Still writing the brick draw routine: it scales the brick in from nothing for its first moments, then fills it and adds a highlight band across the top. Still writing the brick draw routine: it's adding the small dark dots on tough bricks, drawing four light specks across the face. Still drawing the brick's flash overlay, a white highlight that fades out over its short timer. Still writing the brick draw: I'm finishing the flash overlay, a white highlight whose alpha scales down with its remaining timer. Still checking the brick draw's corner rounding: the radius is capped at half the height, so it should stay valid even when the brick is scaled down to almost nothing. Still writing the draw helpers: I'm checking the heart particles are drawn after the burger so they sit above it, and confirming the transform is reset to the base scale at the end of the frame. Still writing the background: I'm building the vertical gradient for the backdrop, running from a plum at the top through a deep purple in the middle to a near-black at the bottom. Still writing the background: I'm adding a soft pink radial glow at the top of the gradient, then setting up a faint field of heart sprites in a grid across the backdrop. Still writing the background: I'm placing a faint grid of heart sprites across the backdrop, then laying a dark vignette over the edges. Still writing the background: I'm finishing the vignette and confirming the backdrop is sized from the resize, then moving on to the input handling and setup. Still working on the input handling: I'm wiring the pointer events so a click starts the game or launches the ball, and moving the paddle as the pointer moves. Still writing the input handling: if the pointer press starts a new game, I'm re-aiming the paddle to the pointer right after the reset, though I'm unsure whether newGame already launches the ball before that aim is applied. Still writing the sound toggle: it flips the sound flag, makes sure audio is ready, updates the On/Off label and the pressed state, then drops focus from the button. Still writing the frame loop: it measures the time since the last frame, caps the step so it never exceeds about 33 ms, then updates and renders before requesting the next frame. Still checking that refreshHUD is safe to call before its use, since the variables it touches are declared with let and need to be initialized first.