Full Stack Developer
Full Stack Developer
All ProjectsDrop-in JavaScript library that replaces loading spinners with playable mini-games
8
Playable games at launch
<8 kB
Core bundle gzipped
4
Frameworks supported
HTML, React, Vue, Svelte
0
Runtime dependencies
loading-games is a lightweight, framework-agnostic npm library that replaces loading spinners with fully playable mini-games. When an AI generation, file export, or heavy computation takes longer than expected, users get Snake, Flappy Bird, 2048, or five other games — then seamlessly return to the app the moment loading completes. The core bundle is under 8 kB. Each game is lazy-loaded only when needed.
Web apps increasingly have long loading states — AI responses, file processing, video rendering — but the industry answer is still a spinner. Spinners communicate nothing and actively encourage abandonment. The concept of playable loading screens is decades old (Namco patented it for PlayStation in 1995), but no polished, developer-ergonomic open-source library existed for the web. Every existing attempt was either a jQuery toy, framework-specific, or long abandoned.
A monorepo-structured npm library with a Web Component core (<loading-game>), native wrappers for React, Vue, and Svelte, and eight hand-crafted canvas games — each under 10 kB. An intelligent delay system ensures the game only appears if loading actually takes long enough to warrant it. A three-tier theming system auto-matches the host app's color scheme via CSS variables. Personal best scores persist across sessions.
Architecture
Designed the monorepo structure and locked the public API surface before writing any game code. The GamePlugin interface — init, start, pause, resume, destroy — became the contract every game implements. Getting this right first meant all eight games could be built in parallel without stepping on each other.
Core Engine
Built the Web Component shell, intelligent delay system, three-tier theme resolution, and lazy-load infrastructure. Each game is a separate tsup entry point and dynamic import — the core registers <loading-game> in under 8 kB; game code only downloads when first rendered.
Game Development
Implemented all eight games against the GamePlugin interface using the Canvas 2D API — no game engine, no dependencies. Snake served as the reference implementation. Games were built easiest-first: Memory Cards → Whack-a-Mole → Snake → 2048 → Flappy Bird → Brick Breaker → Asteroids → Wordle-lite.
Framework Wrappers & Ship
Wrapped the Web Component in thin React, Vue, and Svelte adapters — each a single file that maps framework idioms to the core JS API. Changesets handled versioning across all four packages. size-limit CI enforcement ensured no accidental bundle bloat before publish.
The hardest part wasn't the games — it was the delay system. The first version showed the game immediately on any load, which caused a jarring flash for fast operations. The second version introduced a fixed 800 ms delay, which felt arbitrary. The final design — configurable delay plus a minDisplay prop that prevents a half-second game flash — required thinking about the problem from the user's perspective rather than the developer's API perspective. Good library DX means the right thing is also the easy thing.
~ John Johnson