← Back to the site

Guide · How this was built

The box that lets the light out.

This page documents the concept, the techniques, and the iteration passes behind the Bright Box Solutions site — so anyone can study or reproduce the approach. The whole site is a single hand-written HTML file: no framework, no build step, one external library (Three.js) loaded from a CDN.

1 · Concept

Everything derives from the company's own mark: a black field, a wireframe box, light escaping from its corner. Bright Box audits businesses — it shines light into operational black boxes. So the site is built on one metaphor, executed literally: darkness is the canvas; light is information. Every interactive technique on the page is a variation of illumination — a glowing box, a cursor that works as a torch, a methodology that ignites step by step as a beam descends.

The Bright Box Solutions logo: a white wireframe box with light rays escaping its top-left corner, on black.

2 · Design tokens

A chiaroscuro palette: two near-blacks, two greys, one warm white, and a single gold reserved for light itself. Gold is never decoration — it only appears where something is being illuminated or asked for.

VOID 060707
CARBON 0D0F0E
SEAM 1E2321
ASH 8D948F
BONE EDEAE2
LUMEN E8C87A

Type plays three roles. Cinzel — a Trajan-descended inscriptional serif that matches the carved capitals of the wordmark — for display. Albert Sans, light weight, for body. JetBrains Mono for the instrument voice: labels, prices, dates, the regulatory line. The mono everywhere signals "measurement", which is the product.

3 · The five techniques

The stage (WebGL, Three.js r128)

The hero is a live 3D restaging of the logo: two nested wireframe cubes joined by corner struts, a layered additive-blend glow at the core, ~340 gold particles that spawn inside the box and drift up and out (light escaping), and a faint background dust field for depth. The camera eases toward the pointer for parallax. Guards: device-pixel-ratio capped at 2, the render loop pauses when the tab is hidden, prefers-reduced-motion renders a single still frame, and if WebGL is unavailable the canvas hides and the CSS gradient stands in.

The torch room

A statement typeset twice, layered: a barely-visible layer beneath, a fully-lit layer above wearing a CSS mask-image: radial-gradient(...) whose centre follows the cursor via two custom properties. The visitor literally sweeps a light across the dark to read what AI is already doing in their business. On touch devices — where there's no cursor — a JavaScript Lissajous path sweeps the light automatically (CSS keyframes can't interpolate custom properties, so this is done in JS), gated by an IntersectionObserver so it only animates on screen. Reduced-motion removes the mask entirely and shows the lit text.

The methodology beam

The 5-Step Methodology sits on a vertical rail. A gold beam fills the rail as a function of scroll position, and each step ignites — dot, heading, and body brightening — the moment the beam passes it. A scroll-linked progress metaphor: the audit illuminating the process, top to bottom.

The chambers and the counting figure

Service cards carry an interior radial glow that tracks the cursor position (two custom properties again) plus a subtle 3D tilt toward the pointer — the card leans into your attention. The £200,000 case figure counts up from zero with a quartic ease-out when it enters the viewport. All of it degrades to static under reduced-motion.

The instrument rack (tool embedding)

Live diagnostic tools embed directly in the page. The entire system is one config array — adding a tool is one object, no markup:

const TOOLS = [
  {
    id: 'iso-scan',
    title: 'ISO 42001 Gap Analysis',
    sub: 'One line of description.',
    tag: 'Free',
    url: 'https://your-tool.vercel.app/path',
  },
  // add the next tool here
];

Each entry renders as an expandable row; the iframe lazy-loads on first open (so the page never pays for tools nobody opens), only one instrument runs at a time, and every row carries an "open full screen" escape hatch. allow="microphone" is set for voice-driven tools.

4 · The finish layer

5 · The three iteration passes

Per the brief, the site wasn't accepted until it survived three fine-toothed-comb passes. What each one actually changed:

Pass 1 · Structure

Automated checks over the finished baseline: balanced markup, JS syntax verification via node --check, and presence of every required system (tool config, reduced-motion handling, WebGL fallback, the five methodology steps). An earlier concept draft ("Light for the Machine Age") was archived and rebuilt — it lacked the config-driven tool system.

Pass 2 · Design critique

The mark was redrawn to match the real logo (rays from the top-left corner, the three dashes, the underlined wordmark). An editorial numbering system (01–05) was added to section labels. The chambers gained their 3D tilt; the case figure gained its count-up; favicon, Open Graph image, and a keyboard skip-link were added.

Pass 3 · Accessibility & devices

Every text colour was audited programmatically against WCAG: four greys failed (the worst at 2.29:1) and were raised to ≥4.5:1 without losing the dim-versus-lit hierarchy. The touch-device torch sweep was moved from CSS keyframes to JavaScript because custom properties don't interpolate in keyframes. Tool rows now wrap on narrow screens, and decorative numerals were hidden from screen readers.

6 · Deploying this on Vercel

The project is static — three files and an asset folder. From the project directory:

# one-time
npm i -g vercel

# deploy
vercel --prod

Or push the folder to a GitHub repository and import it at vercel.com — no framework preset needed. /guide works because this page lives at guide/index.html, which Vercel serves as a clean URL automatically. Before going live, edit two things in index.html: the gapsight deployment URL in the TOOLS array, and the booking link in the contact section.


Designed and built by Claude (Fable 5) for Bright Box Solutions — hand-written HTML, CSS, and JavaScript; Three.js r128 for the WebGL stage; Cinzel, Albert Sans, and JetBrains Mono via Google Fonts.