From Header Bars to Full-Screen Magic: Redesigning Kids Games
Our kids puzzle app had a traditional mobile layout — a header with a hamburger menu, navigation links, and a login button eating up precious screen real estate. For an app where the visuals are the experience, every pixel matters.
We decided to rethink the entire layout from scratch.
The Goal
Make the app feel like opening a storybook — full-screen, immersive, with beautiful theme artwork filling every corner. No chrome, no distractions. Just the content.
Full-Screen Immersive Layout
We removed the header bar entirely on all device sizes. The theme carousel now fills the entire viewport edge to edge. On notched devices (iPhone, iPad), the background extends behind the notch and home indicator for a truly seamless feel.
The key CSS changes were surprisingly simple:
- Removed
bg-gray-50from the layout container so the page content’s own background bleeds through - Set
html, body { background: black }so the safe area behind the notch blends with the dark game backgrounds - Applied
env(safe-area-inset-bottom)to floating elements so they sit above the home indicator
The Floating Action Button
Navigation moved to a glassmorphic floating button in the bottom-right corner. It uses backdrop-blur-xl with a semi-transparent white background, so it blends with any background.
bg-white/20 backdrop-blur-xl border border-white/30
Tap it and menu items fan out upward with a staggered animation. The FAB is context-aware — it shows different items based on where you are:
- Home screen: Just the Profile button
- Inside a game: Adds a Home button
- Dev mode: Adds a Status page (hidden in production via
import.meta.env.DEV)
The avatar shows a generic user icon when logged out, or the user’s initial on a colored circle when logged in. Both navigate to a profile page that handles all auth concerns.
Responsive Card Sizing
Getting the carousel cards right across phone, tablet, and desktop took several iterations. Percentage-based sizing breaks down on wide screens — 28% of a 1400px viewport is still a massive card.
We landed on a hybrid approach:
if (w <= 600) {
// Phone — one prominent card
setCardW(68);
} else if (w <= 1024) {
// Tablet — active card with neighbor peeking
setCardW(55);
} else {
// Desktop — pixel-capped sizing
setCardW(Math.max(20, Math.min(35, (350 / w) * 100)));
}
The desktop breakpoint uses a pixel target (350px) converted to a percentage, which means cards stay a reasonable size regardless of how wide the screen gets.
On-Demand AI Puzzle Generation
The biggest UX simplification: tapping a theme card now generates a fresh AI puzzle image on the spot. No more intermediate screens, no puzzle selection menus. Each tap gives the kid a unique puzzle.
The flow: Tap theme → random prompt selected → server calls Hugging Face Stable Diffusion → puzzle board loads with generated image.
Each theme has 4-5 pre-written prompts (e.g., for Frozen: “a majestic ice castle with glowing blue towers and snowflakes”). The client picks one at random and sends it to our /api/image/generate endpoint, which has in-memory caching to avoid redundant API calls.
This replaced an entire StationView component that showed a grid of puzzle thumbnails. The new approach is simpler for kids (one tap = play) and more engaging (something new every time).
”Coming Soon” Cards
We added a comingSoon flag to the station data model. Coming soon cards show a frosted overlay badge and don’t respond to taps. This lets us tease upcoming features (like the Photo Puzzle — turn your own photos into puzzles) without breaking the carousel.
The cover and background images for the Photo Puzzle card were generated using our existing generate-theme-images.ts script, which calls the same Hugging Face API.
Unified CI/CD Pipeline
We also fixed a CI annoyance: every push to main was triggering two separate GitHub Actions workflows — “CI” and “Build & Deploy”. We merged them into a single pipeline:
test → build-and-push (client + server in parallel) → update-infra
PR checks only run the test job. Deploy jobs use if: github.event_name == 'push' to skip on pull requests. Tests now gate deployment — if they fail, nothing ships.
The Cleanup
This session was as much about removing code as adding it:
- Pool Game — 7 files deleted (feature was unused)
- StationView — intermediate puzzle selection screen, removed
- Hub/menu screen — the carousel is the home now
- MobileNav, Home.tsx, Items.tsx — all deleted
Net result: ~1,000 lines deleted. Bundle size dropped from 374KB to 354KB.
Stack
- React 19 + React Router v7 + Tailwind CSS v4
- Bun for builds and testing
- Hugging Face Inference API for image generation
- GitHub Actions → ECR → ArgoCD for deployment
- EKS on AWS for hosting
What’s Next
- Build out the Profile page
- Implement the Photo Puzzle feature (camera → puzzle)
- Add CloudFront CDN for static assets
- Refine progress tracking across sessions
Ship fast, delete more than you write.