A static site that keeps accumulating prototypes eventually runs into a maintenance question: can the structure from the first version keep absorbing new demos, or does every new project require another page setup and another deployment decision?
I ran into this while building a site for 3D product prototypes. The first version contained one larger prototype that tested whether browser-based 3D spatial measurement was viable at all. Later, the design questions became more specific: camera compensation after model scaling, touch interaction for a Gizmo, movement behavior after duplicating a measurement, and so on.
Those questions were better explored as separate demos rather than continuously added to one product prototype. But deploying every demo independently would make links, entry points, and maintenance increasingly fragmented.
So the architectural problem became: how can the site keep accepting new demos while preserving one entry point, one set of conventions, and a low deployment overhead?
I worked through the structure with Claude Code. I defined the practical constraints — easy to extend, easy to share individually, and simple to deploy — while Claude Code helped surface implementation options and their trade-offs.
The final structure keeps the main site fully static and uses a simple manifest file to drive the homepage.
Scanat-Demo/
├── index.html
├── demos.js
└── demos/
├── scale-transition/
│ └── index.html
├── gizmo-touch/
│ └── index.html
└── ...index.html reads demos.js and renders the demo cards. Each demo lives in its own self-contained demos/<slug>/ directory.
The manifest is just a JavaScript array:
window.DEMOS = [
{
slug: 'scale-transition',
title: 'Model Scale Transition',
description: 'Smooth camera compensation after changing model scale',
tag: 'Interaction Motion',
accent: '#2f81f7',
date: '2026-06',
},
];Adding a normal demo only requires two changes:
demos/<slug>/index.html;demos.js.The homepage logic stays untouched, and the entire collection remains inside one static deployment and one domain.
I also considered converting the whole site to React or another frontend framework.
The decision not to do that was based on the actual content. Most demos were self-contained HTML files using Three.js from a CDN. They did not need a build step. Introducing a framework at the site level would have added installation, build, and deployment configuration to every simple prototype without solving an existing problem.
The same reasoning applied to content storage. With a relatively small number of demos and infrequent updates, a JavaScript manifest was enough. Adding a card became a data change rather than a change to rendering logic, without introducing a backend or database.
The principle was simple: design for the complexity that already exists, rather than buying infrastructure for complexity that may appear later.
An exception eventually appeared.
The fifth demo was built with React Three Fiber and TypeScript and required a Vite build. At that point, the assumption that every demo could be stored directly as source HTML was no longer true.
Instead of restructuring the entire site, only that demo received an additional source/build layer:
Scanat-Demo/
├── demos/<slug>/ ← built static output
└── sources/<slug>/ ← React / TypeScript sourceDevelopment happens inside sources/<slug>/. After building, the generated static files are placed in the matching demos/<slug>/ directory.
From the main site's perspective, nothing changes. The demo is still registered through demos.js and still behaves like any other static entry.
This keeps the added complexity inside the one project that actually needs it instead of spreading it across the site.
Embedding a framework build inside a subdirectory introduced one practical issue.
A default Vite build may reference assets from the site root:
/assets/index-xxx.jsBut the demo is actually hosted under:
/demos/<slug>/If the build output is copied there unchanged, the browser still looks for /assets/ at the root and the deployed demo returns 404s for its resources.
The fix is to build with a relative base, for example:
base: './'The broader point is that a build output embedded in a static subdirectory must not assume that it owns the site root.
For plain demos, place the self-contained files directly under demos/<slug>/.
For Vite-based demos, keep source under sources/<slug>/, build with a relative base, and copy the generated output into the matching demos/<slug>/ directory.
The main site remains a static deployment and does not need different Vercel configuration when a framework-based demo is added.
Another option was to make every framework-based demo its own Vercel project, or manage them as separate applications in a monorepo.
That would work technically, but it would recreate the fragmentation the site was meant to avoid. Every new exception would add another deployment object and another place to manage.
The final approach therefore allows demos to use different internal technologies while preserving the same publishing interface: each one ultimately becomes a self-contained static directory inside demos/.
The technologies can differ. The way the site consumes and publishes them stays stable.
The engineering details of this structure came largely from discussions with Claude Code. My role was defining the constraints and making the trade-offs: which complexity was worth introducing, which should stay isolated inside an individual demo, and whether an exception justified changing the overall site architecture.
The useful part of the structure is not simply that the first version was static. It is that later exceptions can be absorbed without changing the publishing model. Simple demos can remain build-free. Complex demos can use their own framework and build process. Both still enter the same site in the same way.
For this kind of personal prototype collection, the principle I would keep is: allow implementations to differ without letting every technical difference become a new management model.