← All work

web · July 2026

Aso

An interactive essay that makes you feel 1,600 years of Georgian writing. A single letter dissolves into ~3,000 canvas particles and reassembles across three historical scripts — Asomtavruli (5th-century stone), Nuskhuri (9th-century quill), Mkhedruli (11th-century living hand) — as you scroll. Zero runtime dependencies, 100/100/100/100 Lighthouse.

Tornike Kalandadze — software engineer & technical lead, client delivery since 2019 · Tbilisi (GMT+4)

Problem

How do you make 1,600 years of script evolution felt, not just described — on the open web, instantly, and accessibly — without an animation library flattening the intent into a canned tween?

Approach

Model the transition as a particle system solved with cheap math instead of a heavy assignment solver. Glyphs sample to point clouds, match by Hilbert-curve rank (O(n log n), spatial locality keeps trajectories from crossing), and animate along quadratic Bezier arcs with rational-sigmoid easing staggered by rank so the morph reads as a wave. Historical accuracy is enforced at build time — fontkit verifies all 33 letters exist as genuine outlines across three Unicode blocks before a build can pass — and the runtime carries zero dependencies, with reduced-motion and a phone-first layout designed in from the start rather than bolted on.

Impact

3,000 particles at ~7.4ms/frame (about 55% frame-time headroom), 5.1KB of gzipped JavaScript, and a 100/100/100/100 Lighthouse. Reduced-motion users get crossfades instead of particle travel; it renders from 360px with no horizontal scroll; and every letter on screen is a real historical outline, not a fabricated shape — a design decision the build refuses to compromise.

Through every lens

01 · Full-stack

A build-time font pipeline is part of the product, not a side script: fontkit verifies all 33 Georgian letters exist as real outlines across three Unicode blocks before a build can pass, and subset-font emits 87KB of optimized woff2 — historical accuracy enforced, not trusted.

02 · Mobile

Responsive from 360px with no horizontal scroll, and prefers-reduced-motion swaps particle travel for crossfading glyphs site-wide — the essay works in the hand and respects the setting.

03 · Frontend

The signature: a letter dissolves into ~3,000 canvas particles and reassembles as the next script, matched by Hilbert rank and eased along Bezier arcs so the change flows as a wave. No animation library — the scroll mapping is ~40 lines — and it holds ~55% frame-time headroom while doing it. The proof is the page you're scrolling.

Built with

Vite · TypeScript · Canvas 2D · fontkit · subset-font · GitHub Pages

Notes

A frontend piece where the engineering is the point. Each of the 33 Georgian letters is a real outline — a build-time pipeline (fontkit) verifies coverage across three Unicode blocks so no glyph is ever faked, and subset-font ships them as 87KB of optimized woff2. At runtime, glyphs render to a 512x512 offscreen canvas, compress to ~3,000 particle targets, and morph: point clouds are sorted by Hilbert-curve index and paired by rank (O(n log n), keeping spatial locality so trajectories barely cross), then each particle rides a quadratic Bezier curve with perpendicular bow and custom rational-sigmoid easing, staggered by Hilbert rank so the change flows through the letterform as a wave. Canvas 2D holds 3,000 particles at ~7.4ms per frame — roughly 55% headroom — with WebGL deliberately left on the table. The whole thing is Vite + TypeScript with no animation library; the scroll mapping is ~40 lines. prefers-reduced-motion swaps particle travel for crossfading glyphs site-wide, the canvas carries role=img with live labels, Georgian text is tagged lang=ka, and it's responsive from 360px with no horizontal scroll.

Contact sheet