Client-Side Runtime CompositionBuilding a virtual execution environment in the browser using service workers, encryption, and in-memory loading
1. The Question
Mental model: this system turns encrypted data into a temporary file store held in the browser’s memory, then uses a background worker to serve those files as though they came from a real web server.
I gave a simple brief to an AI agent, which returned a detailed architectural description: a layered system where files are encrypted at build time, decrypted inside the browser, served from memory by a service worker, and rendered in an isolated frame. The brief had been to build an educational site that could hide a few secret easter-egg games that ordinary visitors would never know existed, but that could be unlocked with a secret code. The architecture was wildly disproportionate to the request.
That disproportion was the interesting part. The system the AI described was built entirely from standard browser features, combined in a way that made them behave like something more. The ideas were worth testing. So I built it. The original brief fell away, and what remained was a set of questions I wanted to work through properly: how do browsers actually work under the surface? Where do security boundaries sit? What remains visible when the work happens inside the browser rather than on a server? The study that followed taught me things about browser security, what stays visible to monitoring, and how systems can be built in layers, that the original brief would never have surfaced.
When something unexpected comes back from a brief, the instinct is to ask what it is actually telling you. The request was for hidden games. What came back was a system design built from browser features I had never combined that way before, and understanding how those pieces fit together felt more valuable than the games ever would have been.
When you open a web page, your browser fetches files from a server: HTML, stylesheets, scripts, images. Those files arrive over the network, get rendered on screen, and live only as long as the tab stays open. Close the tab and everything is gone. The browser has no permanent storage that works like a hard drive, no way to run code independently of the page, and every file it loads is visible to anyone watching the network.
That model works well, and most web development stays comfortably within it. This project explores what happens when those built-in capabilities are combined and pushed beyond that default model.
Modern browsers include features that go well beyond rendering pages. Service workers can sit between the browser and the network, intercepting requests and deciding what to return. The Web Crypto API can encrypt and decrypt data locally without involving a server. Data held in the browser’s memory can act as a temporary file store that lasts for as long as the worker is alive. Iframes can load and render content in an isolated context, separated from the page around them.
Each of these is an ordinary, well-documented feature. The question is what happens when they are wired together with deliberate intent: a service worker that serves files from memory rather than from the network, encrypted files that are decrypted locally and loaded into that memory, and an iframe that renders the result as though it were a separate hosted application.
That is what this project builds. A self-contained space where code can load, run, and render, built entirely from standard browser features, running inside a normal web page.
This project is presented as a proof-of-concept architecture study for education, documentation, and defensive awareness. It pairs every architectural explanation with a corresponding defence analysis: what remains observable, what defenders can monitor, and where the limits of concealment sit when everything runs inside the browser. The sample payloads are harmless mini-games. Because of the dual-use nature of this work, the source code is kept private and is available on request for legitimate educational and defensive research purposes via the contact form.
2. A System in Four Parts
The system is built from four separate pieces, each responsible for one job. One prepares the content ahead of time. One decides when that content is allowed to appear. One serves it from memory when the browser asks for it. And one provides the visible application that a user sees before anything else happens.
Each piece can be developed, tested, and understood on its own. The host application is the assembly layer that wires them into one working product. In the sample implementation, the visible host is a technical archive interface. The hidden payload is a launcher menu that opens small browser games.
Systems thinking: This is the same discipline of keeping each part focused on one job that runs through my other work: analytics as a classification layer, CRM as a decision framework, organisational design as an incentive system. The difference is that here the layers are browser features rather than business concepts.
3. Design Decisions
The four components described above were not chosen for novelty. Each one exists because of a specific constraint or design goal. The technical reference covers how they work in detail. This section explains why they are shaped the way they are.
This page explains the product thinking and system design behind the project. The deeper technical documentation lives in the separate technical reference, including the full execution timeline, component contracts, cryptographic design, lifecycle states, failure modes, observable signals, and defensive controls.
Why encrypt per namespace, and decrypt on demand?
The compiler produces one encrypted bundle per folder rather than one large blob. In the sample setup, that means separate bundles for the launcher menu, a memory game, a reaction game, and a pixel art game. The runtime can decrypt only the launcher first and leave the rest encrypted until the user actually asks for something.
This matters because decrypted content in memory is the most exposed the system gets. Keeping that exposure proportional to what the user has actually opened, rather than decrypting everything up front, reduces the window during which content could be found by someone inspecting the browser’s memory.
Product thinking: Encrypt per namespace, decrypt on demand. The launcher acts as a gatekeeper for the sub-packages behind it, and each additional unlock is a deliberate step rather than an automatic one.
Why hash the trigger instead of storing it?
The trigger phrase is stored in the source code as a hash: a one-way fingerprint. You can produce the fingerprint from the phrase, but the fingerprint alone reveals nothing about the original. Someone inspecting the application’s code would find only the fingerprint, and working out what produced it requires already knowing the answer.
This is a deliberate trade: the system can verify the phrase without ever containing it. The same phrase also serves as the input for generating the decryption key, so one piece of knowledge unlocks both the gate (trigger match) and the content (decryption). That keeps the system simple without weakening it.
Why three visibility states instead of one toggle?
The controller manages conceal, reveal, and purge as separate states rather than a single show/hide toggle:
- Conceal (blur or tab switch) hides the overlay without destroying the runtime. The decrypted content stays loaded in the background.
- Reveal (trigger re-entered while concealed) shows the overlay again without repeating decryption.
- Purge (Escape key) destroys the overlay, clears the controller, and empties the worker’s memory.
A single toggle would mean that hiding the runtime either destroys it (expensive to rebuild) or leaves it always recoverable without authentication (too permissive). The three-state model gives fast concealment when the user switches away, deliberate re-entry of the trigger to reveal, and a clean emergency exit on purge.
Why serve from memory instead of from the network?
The service worker holds decrypted files in RAM and never writes them to persistent storage. When the worker is terminated or purged, the data is gone. The alternative would be to fetch payload files from the network at unlock time, or to save them in the browser’s built-in storage (IndexedDB, Cache Storage) for reuse.
Fetching from the network would create an obvious second-stage download: a clear signal to anyone monitoring traffic. Saving to the browser’s storage would leave traces that survive the session. Memory-only serving avoids both. The cost is that the runtime must be rebuilt from scratch if the worker is terminated, but that is the right trade for a system designed to leave nothing behind.
Why does the host application matter?
The host is the visible product. If the hidden runtime never unlocks, the user should still be looking at a complete and coherent application. In the sample implementation, the host is a technical archive interface: a data-heavy utility that justifies the application’s size, memory footprint, and service worker registration.
That last point matters. A service worker sitting idle on a simple static page would look unusual under inspection. A service worker that actively caches and serves a rich web application is expected behaviour. The host provides the credible surface that makes the rest of the system plausible.
Product thinking: The host application must stand on its own. That is the difference between a system that works at two layers and a trick that looks suspicious at one.
4. Observability and Defence
This architecture can be subtle. Visibility shifts rather than disappears. Every capability it relies on is a standard browser feature, and standard browser features are inspectable. Part of this project’s value as a study comes from taking the defender’s perspective seriously.
- Network shape: the initial page load carries the encrypted payload alongside the visible application’s assets. A large download followed by quiet browsing is a recognisable pattern.
- Encryption activity: generating the decryption key and decrypting the payload produce measurable CPU work. Monitoring tools that watch for encryption usage can spot it.
- Memory usage: decoding the payload, building usable objects, and loading them into the worker all leave temporary traces visible in memory snapshots.
- Service worker behaviour: worker registration, fetch interception patterns, and responses for virtual file paths are all inspectable through standard browser tooling.
- User interface behaviour: iframe overlays, reveal and conceal cycles, and interaction patterns inconsistent with the visible shell all remain observable.
Organisations retain practical leverage: restricting service worker origins, clearing worker state on exit, limiting iframe capabilities, and watching for encryption activity that correlates with unusual session behaviour.
Systems thinking: Across my other work I often deal with the gap between what is visible and what is actually happening: reported metrics versus real behaviour in analytics, stated goals versus actual incentives in organisations, sent campaigns versus real outcomes in CRM. This project explores the same theme in a technical context: what the system does versus what can be seen from outside. Understanding where that gap opens, and where it closes, is what makes the study useful for both builders and defenders.
5. What It Demonstrates
Read as a systems study, this project produces five transferable lessons.
This project applies the same instinct that runs through my other work, but to the browser itself. The new layer is a self-contained execution space built from service workers, encryption, and in-memory file serving. The underlying platform stays the same. The system built on top of it behaves differently. In the same way that an operating system provides useful abstractions over hardware (a filesystem, a process manager, a display), this project combines browser features into something the browser was designed to support individually but that takes on a different character when the pieces are assembled together.