The NYT Mini popularized a specific shape of puzzle: small grid, single shared puzzle per day, streak tracking that compounds across weeks. Mini Cross takes that shape and renders it in a cyber-terminal aesthetic — phosphor green on near-black, monospace clue panel, scanline overlay. The game shipped at 59 out of 60 on our QA rubric across four iterations, and it's the first game in the catalog that was built across multiple cron fires of our remote build pipeline.
This post is the story of how it came together: the daily-only constraint that locked in before scaffold, the iterations that tuned feel before content, the streak ladder that emerged in iter-4, and the moment the pipeline crossed its own boundary mid-build.
Want to play first, then read the build story? ▶ Play Mini Cross Now
The Constraint That Locked Before Code
The first design call for Mini Cross was made before any scaffolding: every player gets the same puzzle on the same day, chosen deterministically from a date-seeded rotation. The spec described a 60-puzzle pack with the rotation indexed by daysSinceEpoch % 60.
This sounds incidental. It's the entire game. Free-play multi-puzzle mode was the alternative — let players solve as many as they want, in any order, save progress per puzzle. We rejected it before scaffold. The streak meaning collapses if you can solve five puzzles on Sunday to "save up" for the weekday. The shared social anchor (everyone got the same puzzle today) goes away. The return-visit mechanic that defines the genre stops working.
Why daily-only matters: A streak is a constraint that produces meaning, not a feature you bolt on top. If you let players bank progress, you've made a different game — one where the streak is a number that doesn't say much. Locking the daily constraint at the spec layer made every later decision (rotation depth, leaderboard key, milestone thresholds) flow downstream from the constraint instead of needing to defend it.
DOM Grid, Not Canvas
The grid is a 5×5 CSS grid of div cells. No canvas. The choice came up at iter-1 and stuck.
Canvas would have given us pixel-perfect control over animations and the scanline overlay. It would also have forced us to reimplement focus management, cursor blink, screen-reader flow, and keyboard navigation — all of which the DOM gives us for free. The visual effects we actually needed (active-cell glow, correct/incorrect cell flashes, completed-word highlight) were all reachable in CSS.
The choice paid off again in iter-4 when we added the streak milestone overlay. Adding role="status" and aria-live="polite" to a DOM banner is one attribute pair. Doing the equivalent for a canvas-rendered banner would have required rebuilding the announcement layer separately.
The Mobile Keyboard Problem
iOS Safari's native keyboard breaks 5×5 grids. When the keyboard appears, the page re-layouts, the grid loses focus, and the cell the player tapped scrolls offscreen. There's no clean way around this with the native keyboard — the layout reflow is the platform's behavior, not ours to override.
The fix is a custom virtual keyboard overlay. A row of A-Z + Backspace buttons slides up from the bottom of the screen on mobile, each button is 44 pixels tall (the iOS minimum tap target), and every button uses touchstart with preventDefault to suppress the native keyboard from ever appearing. The grid stays focused. The page doesn't reflow. The cursor advances cleanly.
Path Runner solved its swipe-input problem the same way (minimum velocity threshold to disambiguate intent from drag). The pattern reuses across genres.
Score Feel Before Content Depth
iter-1 shipped at 47 out of 60. The game was playable. The QA flag was a content-quality issue: some Down entries weren't real English words. They were placeholder fill that structurally validated as crossword data — the integration lint passed, the puzzle was solvable, but actually solving it surfaced "is this even a word?"
iter-2 fixed the fill, added Web Audio SFX, and locked in the 44-pixel virtual keyboard. Score: 54 out of 60.
iter-3 was where the game started to feel like it was worth coming back to: score persistence (your all-time best + yesterday's score live in the HUD), Hard Mode (a +50 bonus, with Check/Reveal hidden so you can't safety-net), and a canvas particle burst on win — 80 green and teal squares emit from the grid center over 60 frames and clean themselves up. The puzzle pack expanded from 10 to 13. Score: 57 out of 60.
The order matters here. Score-and-feel work landed first. Content depth (more puzzles) second. We could have inverted that — ship 60 puzzles first, polish the win moment second — but the inverse wouldn't have rewarded the daily return-visit player. Score persistence is what makes you remember whether yesterday's puzzle was hard. Without it, every solve is a one-shot.
The Streak Ladder
iter-4 added the celebration that wasn't in the spec. Six tiers — 3, 7, 14, 30, 60, and 100 days — each one fires a triumphant chord stab plus an ascending arpeggio and a full-screen banner with a CSS keyframe scale-and-fade animation.
The choice of tiers matters. Linear every-N-days banner fatigues fast. Logarithmic tiers (1, 2, 4, 8, ...) over-reward the early game and under-reward sustained engagement. The ladder we landed on maps to natural commitment plateaus: three days is the "I might do this again tomorrow" moment, seven is a week, fourteen is two weeks, thirty is a month, sixty is two months, a hundred is a hundred. The 3-day pop is critical — it fires early enough that low-engagement players see one before they'd otherwise drift away.
Why the streak banner shipped: The streak count was already in the HUD from iter-1. Players could see their streak. What they couldn't see was the moment of becoming a 7-day, 30-day, 100-day streaker. Without that moment, the number is just a counter. With the moment, the number becomes a goal.
Final score: 59 out of 60. Iter-5 was skipped per our 58-point ship rule.
The Pipeline Crossed Its Own Boundary
Mini Cross is the first game in the catalog that was built across multiple cron fires of our remote build pipeline. Most prior games had been built in a single session. Mini Cross was different — the spec, scaffold, and first three iterations ran on the remote state-machine across roughly five distinct trigger fires. One of those fires self-resolved a mid-flight git merge conflict.
iter-4, the iter-4 QA pass, and the wrapup all ran locally on the orchestrator instead of on the remote pipeline. The reason was practical: the next remote fire stalled briefly, the polish round was small enough to finish inline faster than re-waiting for the next cron, and the integration commit needed tighter human review than a remote run gives.
That hybrid local+remote pattern — remote for heavy iterative phases where context-state matters, local for final polish where the developer wants tighter control — is now the canonical mode for the pipeline. Mini Cross was the first game to discover it. It wasn't planned; it just turned out to be the right shape.
What Mini Cross Is Worth Coming Back To
Mini Cross is short. Most solves run under five minutes. The point isn't depth-of-session — it's depth-of-streak. The same puzzle every day, the same global leaderboard, the same six-tier celebration ladder waiting on the other side of three, seven, fourteen, thirty, sixty, and a hundred consecutive days.
The puzzle pack will grow incrementally — content additions ship via D1 migrations rather than game-code changes, separating the content layer from the logic layer. New puzzles get added without re-shipping the game.
If you've been bouncing off the NYT Mini paywall or just want a different aesthetic for your morning crossword, give it a run. The 3-day pop is closer than you think.
Originally published at vibearcade.com/blog/how-we-built-mini-cross. Vibe Arcade is a one-person experiment to understand what current AI models can do autonomously, where the rough edges are, and where humans need to stay in the loop.
Top comments (0)