Sixteen pages, one design system.
This site has no framework or build step. It’s hand-written HTML, CSS and JavaScript on free hosting, plus one small Cloudflare Worker that protects the assistant’s optional AI phrasing. If you’re a filmmaker who also tinkers, this is the part you might find useful.
- Pages
- 16
- Stylesheets
- 02
- Themes
- 05
- Cloud Worker
- 01
- Site Cookies
- 00
One shared system, room to specialize
lab.css carries the colour, type, spacing, navigation and footer shared by every
page. sun.css contains only the Golden Hour planner and scene rules that do not
belong anywhere else. The result is consistency without forcing a distinctive tool into the
main stylesheet.
Seventy-one design tokens cover colour, type, spacing and motion. Five themes : dark, light,
sepia, timber and forest : are per-theme overrides of the same tokens, applied by an inline script in the
<head> before first paint so there's no flash of the wrong colours.
What needs JavaScript, and what doesn't
The Reel and SkyBound are plain HTML. Production notes, timelines and all 81 portfolio behind-the-scenes photographs remain readable with JavaScript switched off.
The notebook pages, gear list, Story Generator and LaB Assistant are built from shared data
files. JavaScript handles rendering, search, saved kits and live counts; each page includes a
plain <noscript> explanation instead of leaving an empty shell.
That trade keeps 127 resources, 66 gear items and 1,334 prompts in one source of truth.
Details worth stealing
These are the small decisions that separate a site that works from one that only looks like it does, and most are simple enough to borrow.
A scope frame that stays put
The reel is a 2.39:1 film exported inside a 16:9 YouTube frame, so the black bars
are baked into the video. The poster hides them with object-fit:cover, and the
trap is the player: open it out to 16:9 and the frame jumps taller as the bars
reappear. This one does not move at all: the iframe is sized to 16:9 by
width: 134.44% of the container’s height: and centred, so what
overflows top and bottom is exactly 7.205% of the width each side. The true letterbox on a
2.39 film is 7.204%. It crops to the pixel.
The catch is that YouTube draws its own furniture in those bars: the title overlay, the “Watch on YouTube” strip and the control bar: so cropping them means replacing them. There’s a small bar of our own instead: pause, close, and a fullscreen button that hands over to the native player, where the full 16:9 frame and the real scrubber are waiting. Close destroys the iframe rather than hiding it, so playback genuinely stops. Worth knowing if you ever embed scope footage: the letterbox is in the file, not in the page.
Nothing contacts YouTube until you press play
Every video is a poster image and a button. The youtube-nocookie.com iframe
is injected on click and not before, so simply reading a page sets no cookies and loads no
tracking script. It is also dramatically faster, because a page with six films embeds zero
players until you want one.
The catch, which took an outside pair of eyes to spot: the facade only works if the
poster is yours. Pull it from i.ytimg.com and Google is contacted on page load
anyway: the player is deferred, the surveillance isn’t. Host the frames
locally, and drop any preconnect to the same host, or the whole exercise is
decoration.
A finger cannot hover
Across the site, 106 hover-treated photographs begin in grayscale. On a touchscreen that
reveal can never fire. Under
@media (hover:none) the photographs simply arrive in colour instead.
Worth checking on anything where hover carries meaning rather than decoration. Touchscreen devices receive full colour automatically so nothing is hidden behind an impossible gesture.
Colour solved numerically, and per theme
Core text tokens are checked against each theme surface for WCAG AA contrast. Colours that cannot safely share one value receive a theme-specific override instead of relying on one compromise everywhere.
The five themes still feel related, but legibility takes priority over forcing every accent and quiet grey to remain identical.
Native elements before libraries
Every expandable section: the production timelines, the gear categories, the
resource groups: is a plain <details> and <summary>.
No accordion library, no JavaScript, and keyboard support, screen-reader semantics and
find-in-page all work for free.
Browsers will even open a collapsed <details> to show a search match inside it, which no hand-rolled accordion does.
Share links keyed by content, not position
A brief you send someone is encoded as a short hash of its own text, never its position in the list. So the prompt library can grow or be reordered entirely, and a link already out in the world still opens the same brief. Saved kits on the gear page work the same way.
Index-based links would rot as soon as the data moved. Content keys let shared links survive reordering and additions.
A chatbot with search in charge
The assistant searches the site’s film notes, 127 resources, 66 gear entries, dated events and authored field notes before it answers. Every factual response keeps a source, while exact field-note answers bypass model rewriting so filenames and paths remain intact. Follow an internal citation and an orange guide moves to the cited film, resource, event or item of kit.
On the public site, a protected Cloudflare Worker can hand the retrieved answer to a fixed model for a natural voice. The raw visitor question is omitted from that cloud request; only the already-sourced public answer is sent for phrasing. A grounding check rejects any rewrite that drops or changes a date or claim. The model can change the phrasing; it cannot change the facts.
One solar clock, shared by two scenes
The Golden Hour Helper (sun.html) calculates sunrise, sunset, civil twilight,
golden windows, solar noon, azimuth, elevation and a practical colour-temperature estimate
for any date and location. The same engine holds the field in SkyBound : Weather on Detroit
local time, with a separately moving moon carrying the date’s phase.
Both tools lay the current Open-Meteo cloud percentage over that maths. Clear sky keeps the calculated warmth, broken cloud filters it, overcast turns it grey-blue and changes Golden Hour’s advice. Cloud alters the picture, not the flight-safety verdict, because a percentage is not a ceiling.
Golden Hour keeps the sun as the subject: low pine tips, drifting birds and wind streaks, with the treetops answering the current wind and gust reading.
Dragging the slider recalculates the solar position in local memory. Coordinates leave the page only to fetch that optional weather snapshot.
The solar maths stays local and instant; cloud is labelled as weather laid over the calculated window, not as part of the astronomy.
A weather scene that actually reads the weather
SkyBound Weather (droneweather.html) pulls current wind, gusts, temperature,
precipitation and model visibility for Shelby Township (42.67°N) from Open-Meteo. Its
conservative guide flags active compensation at 12 mph steady wind or 14 mph gusts, and
grounds at 18 mph for either.
The animation reads the same numbers. Wind is horizontal streaks whose count, length and speed scale off the figure, so 3 mph and 22 mph cannot look alike, and gusts arrive in bursts with real lulls, because a metronome does not read as weather.
The scene is not in a box: its horizon is the page’s own dividing rule, tinted with the safety state.
Drizzle is drawn apart from rain, and the light and the animals answer the same state. Deer, foxes, squirrels and rabbits wander through when it is calm enough, with the drone breaking station to film whatever turns up. After dark the cast changes over: bats on two sine waves fighting each other, one slow owl mostly gliding, a raccoon read by its mask and ringed tail, and an opossum with a bare one-pixel tail.
The night animals were drawn pale so they would read against a dark sky, and only rendering the thing showed that to be wrong: at full cloud the night sky lifts to grey and pale wings vanish into it. Their tone now cross-fades on live cloud cover, pale enough to catch moonlight on a clear night and back to silhouette under a deck.
No API key, no tracking. Everything renders into one low-resolution buffer upscaled with nearest-neighbour, and the picture and the advisory read the same numbers through the same thresholds, so they cannot disagree.
An interactive crop previewer that previews local media
The Aspect Ratio Previewer (aspect.html) overlays 2.39:1 Scope, 1.85:1 Flat, 16:9 HD, 4:3 Academy and 9:16 Vertical mattes live over sample stills, or over your own photos and video clips. It computes exact active pixel resolutions rather than leaving you to guess letterbox boundaries in an NLE timeline.
3840×1607 is the real canvas for 4K at 2.39, so you know your working area before rendering rather than after.
Zero upload, 100% private. Photos and clips are parsed locally in browser memory via URL.createObjectURL() without sending a byte across the network.
A checklist that can leave its page
The 18-point pre-flight list stays absent until requested beside live conditions, then becomes a higher-contrast non-modal field note shared by every public page: softly rounded, movable and resizable on a desktop, minimizable, dismissible and printable through the browser’s native PDF flow.
The checks, window state, position and dimensions persist in localStorage. Each completed six-item section gets a small spark-and-glow acknowledgement before the final 18/18 message. There is no account, no server sync and no PDF library.
A modal would trap you inside the checklist at the exact moment you want to read the weather behind it. A fixed region stays within reach without taking over the page, and a first visit carries no floating UI until you ask for it.
The useful tool is the one that remains available without demanding attention.
The one page nobody plans to visit
The zero on the missing page is an eye: drawn, not typeset,
because a font’s counter isn’t knowable from CSS and Space Mono’s zero has
a mark inside it that read as a second pupil. One path with fill-rule: evenodd
makes the counter a real hole, so the page shows through in any theme and the pupil stays
clipped inside the letter.
The eye follows your cursor, wanders when you sit still, and gives up on you entirely if you poke at it five times. The message rerolls from two pools: one is funny about the page being gone, the other is filmmaking encouragement.
What it doesn't do
- No advertisements, banners, or sponsored content anywhere.
- No first-party cookies. YouTube is contacted only after Play.
- No accounts, no sign-up, no email capture anywhere.
- No affiliate links. Nothing on the gear page was sent free.
- Saved kits, prompts and checklist progress live in your own browser and are never sent anywhere.
- Motion-heavy interactions respect
prefers-reduced-motion, removing continuous or decorative animation.
There is one quiet counter worth stating plainly: a lightweight visitor counter, GoatCounter. It is open source, sets no cookies and is used only for aggregate page counts. The numbers are at labmedia.goatcounter.com if you want to look.
If you want to build one
The honest version: it is plain HTML, CSS and JavaScript, and the hard parts were deciding what to cut, then checking the result instead of assuming it worked. That does not mean the code is nothing; it means the decisions outlast it.
The site runs on free static hosting; the domain is its recurring cost. The free tools on the resources list are where I’d start. Have a go first, then if you get stuck on something specific, ask me. That offer is real, it is just worth a great deal more once you have hit the wall yourself.