Notes & Studies
Journal
Notes on works and technical writing.
Notes from behind the work: production thinking and technical writing held under one craft bar across code, motion, film, and photography.
Motion Studies
Ring of light
Turning the bright side of the ring of light once around
The bright side of a ring of light drawn with gold dots travels along the rim of the dark circle. The dots never move; when the direction changes, only the brightness shifts. The speed rises a little partway through, then settles. At the loop's seam the speed before and after lines up, so the motion connects smoothly. The only thing that moves is the direction of the bright side, nothing else.
Loop · Corona · Eclipse · Canvas2D→3D
How to build 2D→3D
A flat donut tumbles as if solid — swelling once on the same wave — then lies flat again. When you want that solid-looking move while keeping a flat, graphic look — the kind that composites as 2D art — this is the motion-graphics way to get it: tilt the rim's shape, drop it onto the screen, and take the convex hull of the points as the outline, and a flat ring reads as solid. We follow the build with code.
2D→3D · Projection · Convex Hull · SVGAuto-orient
How to build auto-orient
Flat circles travel around a tilted ring — the near ones swell and slow, the far ones shrink and speed up. Scale one perspective factor into both position and size, and the pacing and the depth both fall out of that single projection, kept in step by the geometry. When you want depth while keeping a flat, graphic look, this is how to build it — with code.
Auto-orient · 3D · Perspective · SVGDifference
How to build difference
Overlapping circles open and close, and where they overlap drops out so it looks subtracted. That drop-out is really an even-odd fill rule — paint the regions covered an odd number of times — plus one clock that folds back at the mirror. Skeleton code included — the article builds up from the assembly idea.
Difference · Even-Odd · Easing · SVGInterference
How to build interference
An inner dot orbits, and a ring dot dodges each time it passes nearby. It looks like the ring dots react to what comes close, but their motion is really one pulse repeated on a clock that keeps ticking. What looks like dodging is a distance force layered on top. Skeleton code included — the article builds up from the assembly idea.
Interference · Proximity · Easing · SVGOffset
How to build offset
Five circles slide left, and a wave of sizes seems to travel right to left. That wave is one move, layered with each copy delayed by a little. That stagger is what 'offset' is. Skeleton code included — the article builds up from the assembly idea.
Offset · Stagger · Easing · SVGTime delay
How to build time delay
Five capsules bounce in turn and look like a wave. That wave is one jump-and-landing profile, replayed by each capsule at its own time offset. That offset is what the time-delay drawer is. Skeleton code included — the article builds up from the assembly idea.
Stagger · Time Delay · Easing · SVGArrangement
How to build arrangement
Nine dots gather at the centre, open into a ring, then swirl back to new places — it looks finely choreographed. You hand-author two layouts — a square grid and a ring — and the swirl and the seat-swap both fall out of those two layouts and how the dots are matched between them. Skeleton code included; we build it from scratch.
Arrangement · Turntable · Easing · SVGParallax
How to build parallax
Seven circles bob up and down and look like they sit at different depths. That depth read comes from one thing: every circle shares the same waveform, and the travel amount changes from circle to circle. The wider a circle bobs, the nearer it reads; the smaller, the farther. Skeleton code included — the article builds up from the assembly idea.
Parallax · Amplitude · Easing · SVGFollow-through
How to build follow-through
The follow-through of an i swinging right to left. The lag and the bounce are really two things: one one-way swing, and a wobble whose size is set by how fast the move leaves its last key. The faster it whips off the key, the bigger the wobble — and the lag and overshoot fall out of that. Skeleton code included — the article builds up from the assembly idea.
Follow-through · Overshoot · Easing · SVGMerge & split
How to build merge & split
Eight circles on a slowly turning ring dive into the center one after another, get swallowed into one growing disc, then peel off and return to the ring. Both the merge and the split are one thing: a single gather-wait-return clip replayed by every circle with a small delay, over a ring that keeps turning at a steady pace. The melt is same-color circles overlapping, and the middle disc swells with the square root of the swallow count, so its area keeps the count honest. Skeleton code included — the article builds up from the assembly idea.
Stagger · Overshoot · Easing · SVGSplit
How to build split
A disc cracks down the middle, the halves slide past each other while the whole pair turns, and it all seals back into one circle. It reads as two choreographies — rotation and slide — but a single progress number drives them both. The perfect landing is geometry's job, and this article walks through the assembly that makes it so.
Shear · Rotation · Easing · SVGCycle
How to build cycle
On an ∞ track, a thick stroke's head and its dot sprint through most of a lap in one burst, then crawl the rest. In this two-gear-looking move, you set 2 speed keys — one whip's worth — and the crawl's speed follows from the promise that one loop closes exactly 1 lap. The stroke itself is a fixed-length window: as it slides along the track, the head and tail appear to move.
Path · Dash · Easing · SVGSymmetry
How to build symmetry
4 bars stretch open to the left and right, the center square swells, all of them freeze together at full stretch for a beat, then walk the same road home. This perfectly rehearsed-looking move is driven by a single number that climbs from 0 to 1, pauses, and returns to 0. Every shape reads that number times its own motion amount, and the mirror is the sign of that amount flipping between left and right. The center square even makes a half turn on the same number. One number and the per-shape motion amounts, written out as short functions and unpacked.
Pulse · Hold · Easing · SVGAfterimage
How to build afterimage
While 2 dots make one lap around a circle, the tail splits into flip-book frames in the fast stretch, melts into one band in the slow stretch, and vanishes the moment they stop. Each layer of the tail is the dot's own past — the same rotation replayed a fixed beat later per copy. One rotation drives it all, and whether the tail splits or melts follows the rotation's speed — fast and the echoes pull apart, slow and they fuse. One rotation and 9 copies, written out as short functions and unpacked.
Echo · Time Shift · Easing · SVGInverse proportion
How to build inverse proportion
Two kissing circles keep trading size — one inflates exactly as the other deflates. The drawer is named 'inverse proportion', yet throughout the loop what stays constant is the sum of the radii. Keyframes sit on the top-left circle's radius — 3 of them; the other radius is that sum minus the first, and both centres are computed to recede from a fixed kiss point by their own radius, so the contact stays put. The whole build — including why the kiss point holds fixed — is written out as short functions and unpacked.
Conservation · Complement · Easing · SVGLinkage
How to build linkage
While the center square makes a quarter turn, the side squares slide as if bolted to it, and near the diamond everything seems to pause. Each side's position is solved every frame as the spot that just grazes the spinning square — one rotation drives the motion, and the sides follow it by geometry. Even the pause is the contact point's progress stalling there for a moment. One rotation and a one-line contact law, written out as short functions and unpacked.
Tangency · Geometry · Easing · SVGRandom
How to build random
Nine dots pop in an order you can't predict. That random-looking order is really one fixed table that writes a place-in-line into each of the nine cells. The motion itself is one keyframed clip, replayed by all nine at a steady staggered beat. The whole build — down to the spring-like undershoot that turns out to be an authored key — is written out as short functions and unpacked.
Scramble · Determinism · Easing · SVGCount growth
How to build count growth
The dots seem to grow from 6 to 19 and fall back to 6. That count change is really one thing: group-staggered entrances layered onto the whole lattice opening and closing together. Offset when each group appears, and the swell in the count emerges on its own. The whole trick is written out as short functions and unpacked.
Lattice · Emergence · Easing · SVG
Renewal Case Study
Engineering Notes
Filmtone / Code Generation
Generating Swift from TypeScript math — Filmtone's cross-platform color parity pipeline
Color transforms, motion blur, and exposure math live in TypeScript inside `packages/film-lab-renderer/src/`. `bun run generate:filmtone-ios-swift` mechanically produces `FilmtonePhase0Generated.swift`; hand-editing the generated module is prohibited. The Phase 0 contract test (`verify:swift-contract`) confirms the generated math matches the TypeScript output. WebGL fragment shaders read the math as GLSL constants, WebGPU compute shaders as WGSL, and the iOS Swift export session as the generated module. Color parity is held by structure, not discipline.
Filmtone · WebGL · WebGPU · Swift · Cross-platformFilmtone / iOS Bridge
Reaching iOS PhotoLibrary, Core Image, and ActivityKit through a Capacitor native plugin — implementing FilmtoneMediaPlugin's nine methods
Filmtone iOS is a Capacitor 7.4 hybrid app, but `FilmtoneMediaPlugin` exposes nine native methods to the TypeScript side: `pickSource` (PhotoLibrary), `pickLutFile` (DocumentPicker), `probeSource` (AVAsset metadata), `renderPreviewFrame` (Core Image), `runExport` (Core Video write), `saveToPhotos` (PHPhotoLibrary), `shareOutput` (UIActivityViewController), `cancelExport`, `handleMemoryWarning`. Each is published via Swift `@objc`, with a TypeScript proxy in `src/native/filmtoneMedia.ts`. Bridge changes ship in dual-side PRs (single-side updates are the most common runtime breakage).
Filmtone · Capacitor · iOS · Native Plugin