← ALL NOTES
METHOD·2026.09·6 MIN READ
A Scalable Content Structure for a Static Demo Site
dev-toolsprocess-design
The Problem

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.

Base Structure

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:

JAVASCRIPT
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:

  1. create demos/<slug>/index.html;
  2. add one entry to demos.js.

The homepage logic stays untouched, and the entire collection remains inside one static deployment and one domain.

Why the Main Site Does Not Use a Framework

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.

Integrating a More Complex Demo

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 source

Development 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.

A Build-Path Issue

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.js

But 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:

JAVASCRIPT
base: './'

The broader point is that a build output embedded in a static subdirectory must not assume that it owns the site root.

Engineering Notes

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.

Why I Did Not Split Deployments

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.

Takeaways
  1. Stabilize the content entry point before standardizing the technology stack. For a growing demo site, consistent access and directory conventions matter more than making every project use the same framework.
  2. Use simple data-driven content when the scale is small. A manifest file can separate content updates from page logic without requiring a backend.
  3. Keep complexity local. One demo needing a framework does not mean the entire site should become a framework application.
  4. Give different implementations the same publishing interface. If every demo ultimately becomes a self-contained static directory, the main site does not need to know how it was built.
  5. Check asset paths when publishing into subdirectories. A build that works locally may fail once embedded below the site root.
About the Architecture Decision

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.

CONTINUE READING
Translating Figma Component Properties into Code Props2026.09Engineering a Figma Design System into Production Assets2026.09