Skip to content
Back to work

Personal project · 2023 — Present

Portfolio experiments lab

Where interaction ideas get tested before they reach client work, and shared once they earn it

  • Next.js
  • React Three Fiber
  • three.js
  • Motion
  • Canvas 2D
  • TypeScript
  • Tailwind

The problem

Interaction ideas are cheap to describe and expensive to discover halfway through a client build. I needed somewhere to find out what a technique actually costs — in frame budget, in bundle size, in accessibility debt — before proposing it to anyone paying for it.

The approach

This site is the lab. A React Three Fiber scene with GLTF models, a full-viewport Canvas 2D glitch effect, pointer-tracked glow surfaces and scroll-linked timelines all exist here first, which is how I learned which of them survive contact with a mid-range phone and which do not. The effects that earn their place graduate to the showcase, rebuilt as self-contained components with a live preview, a props panel, the source and a prompt an AI agent can rebuild them from.

The outcome

A working set of judgements rather than opinions: which effects are worth their cost, which need capability gating, and which need to be switched off entirely when someone has asked for reduced motion. The refresh documented in docs/portfolio-refresh-audit.md is the result of turning that lens on my own code. Those judgements are now public: anyone can open an effect in the showcase, tune it, and take it away as code or as a prompt.

Architecture moves

  • React Three Fiber scenes loaded as lazy client islands via next/dynamic, kept out of the initial bundle.
  • Motion tokens centralised in lib/motion so durations, easings and springs are shared values rather than magic numbers.
  • Capability and reduced-motion gating handled at the provider level, so individual components do not each reimplement the check.
  • Canvas effects driven by a single requestAnimationFrame loop rather than per-component intervals.
  • Showcase components are single files with no imports from the rest of the site. Each page reads its component's source at build time, so the Code tab is always the file that renders the preview, and a test fails if a file reaches into the app or lists the wrong dependencies.

Performance levers

  • Heavy 3D and canvas work is dynamically imported, so the first paint does not wait for it.
  • Animation restricted to transform and opacity wherever the effect allows.
  • Scroll and pointer listeners throttled and passive, and the number of simultaneously animating elements capped on small screens.
  • Effects disabled outright on touch and low-power devices instead of merely slowed down.

Engineering impact

  • Turned a portfolio into a test bed, which makes the technique choices in client work evidence-based.
  • Produced the reusable motion and gating primitives this site now runs on.
  • Gave me a documented audit of my own animation defects — including the ones I had shipped.
  • Made the lab shareable: a growing library of original effects that visitors can preview, tune and copy as code or as an AI prompt, several of which now run on this site.

Challenges conquered

  • Wanting a cinematic feel while keeping first paint fast, which is mostly a fight about what is allowed to block rendering.
  • Making reduced motion a genuine alternative rather than the same animation played slowly.
  • Accepting that some effects I liked were not worth their cost on a mid-range Android.

From lab to showcase

For a long time the experiments lived inside this site's own components, wired into its providers, motion tokens and helpers. That made them easy to run here and impossible to hand to anyone else. Sharing one meant explaining it.

The showcase changes that. Every effect that survives the lab is rebuilt as a single file using React and Tailwind, with Motion only where a spring genuinely helps. It imports nothing from the rest of the site, so copying it gives you something that runs.

Each item comes with:

  • A live preview and a props panel, so you can tune it before you take it, with the matching JSX written out as you go.
  • The source, read at build time from the same file that renders the preview, so the code on the page can never drift from the demo.
  • A prompt, written by hand rather than generated, that an AI coding agent can rebuild it from in your own stack, React or not.

Built to the same rules

The showcase is held to the standards the lab exists to test. Every effect honours reduced motion with a finished, static state rather than a slower animation. Canvas work pauses when it scrolls out of view. Nothing animates layout properties, and the card, the button and the glyph field track the pointer through CSS variables, motion values and refs, so moving the cursor never re-renders them.

Running here too

Some of the pieces are back in use on this site. The principle cards under "How I work" are Spotlight Cards with Ink Text numerals you can paint, and the Showcase button in the header is the Magnetic Button. A good place to start is Glyph Field, which hides this site's logo in a field of flickering glyphs.