Lewati ke konten
insomnius.

Games by Insomnius

authorMuhammad Arief Rahman

19 Oktober 2026

Bacaan 11 menit

react

typescript

bun

games

algorithms

puzzle-generation

indexeddb

pwa

frontend-security

Tulisan ini tersedia dalam bahasa Inggris. Navigasi situs tetap menggunakan bahasa yang Anda pilih.


Overview

Games by Insomnius began as a small question: could I make a collection of games that felt like a good programming problem—clear rules, visible state, and the satisfaction of one considered move?

The result is eight browser games: Sudoku, a technical Crossword, 2048, Sokoban, Nonograms, Mastermind, Tower of Hanoi, and Instruction Lab. But the interesting work was not just building their boards. It was deciding what should happen when a puzzle takes time to generate, a browser refuses storage, an update arrives mid-game, Safari behaves differently, or a player refreshes an install offer.

This is the story of those decisions, the reusable tooling that came out of them, and how I made the videos and presentation around the project. There is no account or backend requirement, and personal progress stays in the player's browser.

A short tour

Games by Insomnius — considered play, deliberately built · 24 detik · Suara aktif saat diputar, tanpa pemutaran otomatis.
Unduh film
Baca transkrip (Inggris)

Choose one of eight thinking games. Make a move, use a hint, or follow the consequences of a 2048 slide. The engineering follows the same principle: commit saves before reloading, make updates explicit, and keep the games useful offline. The project also produced a reusable deterministic frontend-security checker. Games by Insomnius: game.insomnius.dev.

Start with the board, not the chrome

I kept the Insomnius visual language: green light/dark roles, IBM Plex Sans headings, system body text, and Source Code Pro for numbers and code. Each play screen gives its board or program the primary space. Help, sharing and the game switcher stay discoverable without turning eight games into a crowded row of tabs.

Keyboard and touch paths had to work together. Crossword uses actual letter inputs and the phone keyboard; narrow grids pan instead of shrinking into unreadable squares. Mastermind reserves room for all four active positions. The 2048 animation carries real tiles to their destinations instead of simply flashing a replacement grid. Reduced motion removes unnecessary travel while preserving feedback.

Desktop collection, captured from the running application. The browser outline is presentation, not a physical-device test.
The actual phone layout, not a desktop screenshot squeezed into a phone. Select the image to inspect it.

Make the puzzles defensible

A random-looking board is not evidence of a good puzzle. I gave each generator an explicit property to check:

  • Sudoku: unique solutions, with notes, hints and checks.
  • Crossword: connected layouts, matching intersections, valid numbered entries and exactly 2,000 distinct normalized technical answers.
  • Sokoban: replayable solutions, reverse-pull reasoning and bounded planning filters that test more than delivery distance.
  • Nonograms: uniqueness and complete deductions, not merely an attractive bitmap.
  • Hanoi: mixed legal starting arrangements with an exact starting minimum.
  • Instruction Lab: generated contracts checked against independent mathematical outputs across twelve cases.

Generation runs in browser workers. When creating a replacement, the current puzzle remains available until its successor passes validation. Seeded simulations exercise legal moves, solved states, variation and save recovery. These are specific guarantees, not a claim that a timeout proves correctness or that an algorithm can predict every person's experience of difficulty.

The other two games have their own state logic: 2048 merges each tile once per move, and Mastermind counts exact/elsewhere feedback without double-counting repeated symbols.

A technical crossword, with attribution

I wanted the crossword to be useful to programmers rather than a collection of generic trivia. Its 2,000-answer bank covers distributed systems, architecture, AI/ML, databases, security and software delivery. Original clues sit alongside definitions adapted from pinned Wikipedia and MDN revisions.

Sources, changes and CC BY-SA licensing remain available with the downloadable bank. The glossary license applies to those definitions, not unrelated application assets. Easy, Medium and Hard change grid budgets and clue counts; freeform layouts do not promise that every letter is crossed.

Treat progress as the player's property

I moved persistence to a shared IndexedDB-backed store with a working in-memory view, coalesced writes and a committed-write boundary. The application can respond immediately without pretending that an unfinished write is durable.

Migration is deliberately conservative: read an owned legacy key, commit its IndexedDB copy, and only then remove the old value. There is no localStorage mirror or fallback. If storage fails, the current page remains playable in memory and says that persistence is unavailable; it does not silently promise that progress will survive closing the browser.

Personal records use the measure that fits the game. Sudoku prefers fewer hints; Crossword prefers fewer reveals, then checks, then time; 2048 retains its existing best points. Sokoban rooms and Instruction Lab contracts keep separate scopes. Legacy untimed games do not receive invented zero-second records. These are local records—not synchronized accounts, a tamper-proof competition or a global leaderboard.

Design the update notice before the reload

An update arriving halfway through a puzzle should be a decision, not a surprise. I added public release metadata, content-fingerprinted assets and an explicit Reload / Later notice.

The important sequence is save, then update. Reload flushes pending IndexedDB writes, activates a waiting worker when needed, waits for controller change and preserves the current route, query and fragment. The page does not refresh itself, steal focus, or tell the user to clear website data. Previous immutable assets are retained with checksum checks so an already-open tab can still load its preceding release's code.

The same boundary applies to the PWA. A newly installed worker waits; installation is not permission to interrupt another tab. Version checks and API/private paths are never cached as offline app data.

Add offline play without an install trap

I built a release-specific offline shell covering all eight games, their generation workers, fonts and the complete crossword corpus. Navigation tries the network first and falls back to a known cached route. Runtime navigation HTML is not written into the cache; install-time HTML is fetched anonymously and checked against the worker's release.

The installation offer taught me a small but important distinction: seeing is not dismissing. Refreshing or navigating should not make it disappear forever. Only explicit close/install actions or installed-mode detection suppress it. The banner starts in flow, stays pinned while scrolling, defers to open help and never invokes a native installation sheet without a click. iPhone/iPad users get Safari instructions and an honest warning that installed-app saves may be separate from Safari.

Offline scope is explicit. Game code is essential; large tutorial videos are not precached, and sound remains optional. Browser storage eviction and quota restrictions still exist. “Works offline” is not a promise that an operating system can never remove its files.

The live checks found a problem staging could not: the public worker response allowed four hours of caching despite the origin's revalidation policy. I strengthened the worker's browser/CDN headers to no-store and verified the result through the public edge before calling the release complete.

Turn a security task into reusable tooling

Frontend environment variables deserve a hard boundary: if a value reaches client JavaScript, it is public. I disabled automatic Vite environment exposure, made allowed configuration explicit, excluded private files from Docker contexts, disabled production source maps and added nginx denials for private/config/source paths.

I also made the checks reusable. The implementation lives in Harness's frontend-security tool, not as a game-specific prompt that claims to know whether a build is safe.

The optional AI skill is a thin workflow wrapper: help prepare a versioned configuration, invoke the checker and explain its redacted report. Scripts decide pass/fail; the model does not override a finding. The deterministic checks cover private artifacts, credential patterns, known comparison values, unsafe public injection and source maps, with bounded reads and live probes. Separate configuration checks reject an unsafe Vite environment prefix before dotenv loading can expose values through debug output.

That distinction matters. AI helped me shape the workflow and interpret results, but repeatable policy belongs in executable code. Logs and reports avoid raw secret values. Passing these checks is evidence about the configured checks and scanned artifacts—not a claim to detect every possible secret or a substitute for rotating a leaked credential.

Use feedback to find the small failures

Several refinements came from observing the application rather than adding another feature:

  • Safari did not reliably emit the newer dialog event, so tutorial mounting follows the actual open attribute.
  • Save-status text changed width and moved the sound control. I reserved its layout slot and memoized the preference component so unrelated moves/saves do not rerender it.
  • The initial SEO document flashed without styles on refresh. Critical styles and a bounded startup state fixed that without serving special content to crawlers. If JavaScript fails or is disabled, the same readable rules/navigation remain available.
  • Theme switching now follows the parent's control-origin circular reveal and sun/moon motion, with an immediate reduced-motion path and safe unsupported/interrupted fallbacks.

Each game's help includes written rules, a native 36-second tutorial, captions and a transcript. Video playback never autoplays. Optional game effects start Off, and tutorial volume is independent.

Where AI helped—and where it did not

For sound, I used one isolated Codex task to design oscillator parameters. A deterministic Bun renderer turns that specification into five short, quiet WAV effects and verifies their bytes. They are Codex-designed, locally synthesized sounds, not recordings returned by an audio-generation model, and no generation API runs in the player's browser.

For the installed-app identity, Codex designed an original geometric G around an inward turn. I retained the brief, SVG and rationale, rendered PNGs locally, checked small-size legibility and maskable safe bounds, and used opaque backgrounds. The manifest identity stays stable; replacing an icon is not a reason to replace the player's storage. Existing installed icons refresh according to each browser's policy.

The application still uses the actual Insomnius owner logo for its link back to the parent site. The new Games mark identifies the game application rather than pretending to replace Kanji or the whole portfolio's branding.

How I made the showcase film

I treated the film as another interface: choose a story, show real state and make every transition explain something. I used the video-making skill's planning rubric to settle a short, polished sequence before writing the animation: choose a game, make a considered move, keep progress safe, then connect the product to the tooling built around it.

I captured the running applications with Bun and Playwright in fresh browser profiles. Desktop and phone captures use their actual viewport sizes. The generic browser/phone outlines are presentation, not evidence of physical-device testing. Sudoku before/after states come from the real Hint action, and 2048 states come from actual moves. Edited states are not presented as an uninterrupted screen recording.

The motion is authored in fframes: Rust describes the SVG scene for each frame, Skia/Vulkan renders the surfaces, and FFmpeg encodes the output. Device reframing, a save/commit/reload diagram and restrained state edits provide different kinds of motion instead of repeating a slide template. The scene source, storyboard and asset provenance are kept with the project.

I composed a quiet deterministic instrumental score in code and used sparse CC0 interface accents, without narration. That avoids relying on unclear stock-music redistribution terms for the new film. Review includes rendered contact sheets, sharp frames, decoded output checks, captions and numerical analysis of the decoded AAC—not just the pre-encode mix. The product-bearing opening is already present in frame zero; I extract the poster from that first encoded frame so the player and bare MP4 share a useful opening composition. The portfolio player is self-hosted, has native controls, never autoplays and uses preload="none" to request deferred loading. That is a browser hint, not an absolute guarantee against a metadata request.

The longer 36-second in-game tutorials have a separate Hyperframes-based source pipeline, with checked worked examples, enlarged teaching diagrams and direct native playback. Documenting those inputs, licenses and rebuild steps is part of making the video—not a footnote after exporting an MP4.

What I own end to end

My work covers the interface, engines, puzzle generators, persistence and records, update/install/offline behavior, accessibility paths, security boundaries and reusable checks, AI-assisted sound/logo specifications, tutorial/showcase production, browser verification and scoped deployment.

The stack is React, TypeScript, Vite and Bun, served as static artifacts through Docker/nginx. Verification includes deterministic checks and Chromium/WebKit automation, with independent game-specific oracles where applicable. Browser emulation and numerical audio analysis are not physical iPhone, OS-install or speaker-listening certification. Those limits are documented alongside the evidence.

Play Games by Insomnius · Source