Tap anywhere to begin. Skip intro at the bottom ends this opening and opens the site.
Skip to content
ElevateEmpowerEngageAbout me

How this site actually works

A plain look at the technology, artwork, privacy choices, and decisions behind Entertrainer. No mystery tour; just the working parts.

The technology, in plain terms

Framework
Nuxt 3, client-rendered

FrameworkOne Vue app; four routes are full applications rather than pages. The content remains available as soon as each route mounts, without depending on animation or interaction. That distinction matters here.

Design system
One CSS file, no framework

Design systemColour, type, surface and motion are defined once in assets/css/main.css and read by everything downstream. No Tailwind, no component library, about six hundred lines including the comments. One file doing the job is easier to inspect than a small forest of abstractions.

Type
Four faces, four jobs

TypeFraunces for display, Archivo for interface, Source Serif 4 for reading, IBM Plex Mono for metadata. All SIL Open Font License, all self-hosted, three of the four variable — so the whole range is eight files. Chosen as the closest open equivalents to a commercial stack I could not license.

Colour
White, near-black, six accents

ColourA neutral ramp from 50 to 1000 and six saturated accents, one per section. Every accent is paired with the one text colour that clears 4.5:1 on it, measured rather than assumed. That is why the green and cyan carry black text and the blue carries white.

Surfaces
One hairline, 3-6px radii, no shadows

SurfacesAn earlier version put a 2px outline, a 20px radius and a hard offset shadow on everything, three treatments doing the job type and space are supposed to do. There are now two shadows in the whole stylesheet, both for things that genuinely float. The rule and the space around it handle separation.

Motion
Four durations, five curves

MotionEvery transition picks from the same short list, and things leave faster than they arrive. Scroll reveals are CSS scroll-driven animations, so the failure mode is "no animation" rather than "no content". If motion fails, the content is still there.

Images
WebP and PNG, drawn or generated, then composited

ImagesCard artwork was generated and the titles set on top afterwards, because type rendered by an image model is type nobody proofread. Images can improvise; headlines need proofreading.

Hosting
Vercel, static output

HostingThis site has no database or analytics. A tool sends only the AI request you make, and nothing is kept.

Opening sound
Pixabay ident by Diamond_Tunes

Opening soundOne short welcome tone on tap-to-enter: “Digital Vibe (Podcast Intro Ident)” by Diamond_Tunes on Pixabay (Content License). Trimmed to the preloader window. Attribution is appreciated; the license does not require it. Device silent mode is respected — playback uses ordinary HTML audio inside the tap gesture and fails quietly if muted or blocked.

The decisions that matter

It works without a pointer

Every filter is a real radio group with arrow-key movement, every control has a visible focus ring, and the first thing in the tab order is a skip link to the content. Keyboard access is therefore a requirement, not a finishing touch, for a learning designer’s portfolio.

It works without motion

Turn on reduced motion and the card lifts, the staggers and the page transitions all collapse to state changes. Nothing on this site is legible only while it is moving. Motion is optional; meaning is not.

It works without images

Every card puts its artwork in a band above the type instead of behind it, so a slow, dark or missing image costs you a picture and never a headline. The front page is fully readable with images disabled. The picture may wait. The headline does not.

Your StoryGen projects stay in your browser

StoryGen keeps your storyboards in your browser’s own storage, so they survive a refresh and never reach me. The others hold nothing at all. Where a tool calls a model it sends only the text you gave it for that one request, and nothing is kept on the way through. Your storyboard stays in the browser; only the text you submit is sent for that request.