Building systems that disappear

Georgie Rocky

I build interfaces that feel like film—intentional motion, deliberate pacing, and obsessive attention to the 16.67ms that separate good from unforgettable. No frameworks. No bloat. Just truthful systems that respect your time and attention.

View Work
2,400
annotations/hour sustained
0
frameworks shipped
60
fps or it didn't happen
CURRENT Annotation OS v3
BUILDING At 2:47 AM, probably
SELECTED WORK — 2023→2026

Systems that ship. Stories that stick.

Six projects built because existing tools failed me. Each one a response to friction I felt in my own workflow.

Annotation OS interface showing high-volume labeling
01
2.4k/hr 12 annotators 2M+/day

Annotation OS

Canvas 2D Web Workers Go Zero React

The problem: Existing tools choked at 500 annotations/hour. I needed 2,400. Every frame mattered when you're labeling training data for 8 hours straight.

My approach: Threw out React on day 3. Canvas-based renderer, manual DOM patching, Web Workers for everything that wasn't render-critical. Treat the DOM like it's expensive—because it is. Memory pooling, object reuse, the kind of obsessive optimization that makes other devs uncomfortable.

Built at 2 AM during a deadline crunch. Third iteration. First two used virtual scrolling libraries that fought me. Third one I wrote the scroller in 200 lines and it was 4x faster. Lesson: when performance matters, abstraction is the enemy.

Now: Processes 2M+ annotations daily across 12 annotators. Peak: 2,847 annotations in a single hour. Zero dropped frames on a 2019 MacBook Air. The secret isn't magic—it's saying no to everything that isn't essential.

Heavens Gallery WebGL experience
02
14KB WebGL2 60fps mobile

Heavens Gallery

WebGL GLSL Procedural 14KB

The problem: Portfolio sites look the same. Template grids, fade-ins, the same three.js boilerplate. I wanted something that felt like flipping through a contact sheet in a darkroom.

My approach: No external libraries. Custom WebGL2 renderer in 14KB gzipped. Procedural film grain, chromatic aberration, scanline simulation— all in shaders. The images aren't loaded; they're streamed as compressed textures and decompressed in the GPU. Built the texture atlas packer myself because existing tools were too slow.

Process: Started with a film emulation shader I wrote at 3 AM. Realized I could build an entire gallery around the aesthetic. Spent two weeks hand-tuning the film response curves to match Kodak Portra 400. Yes, I'm that person.

Result: 60fps on iPhone 12. 14KB total bundle. Looks like you're viewing 35mm scans through a loupe. No JavaScript framework could do this. Sometimes the right tool is no tool at all.

Rubric Generator interface
03
8 min Python LLM-powered

Rubric Generator

Python FastAPI LLM Quality Loop

The problem: Writing evaluation rubrics for AI training data takes 45 minutes per task. It's repetitive, it's boring, and humans are terrible at being consistent evaluators.

My approach: Built a system that generates rubrics from examples. Give it 5 good/bad pairs, it extracts the criteria, builds a rubric, then validates itself by scoring the examples. If it disagrees with human labels, it iterates. Meta-evaluation loop. Takes ~8 minutes end-to-end.

Built during: A particularly tedious annotation sprint. I was writing my 12th rubric of the day and thought "I could automate this, or I could keep suffering." Chose the first option. Three days later, the tool was generating better rubrics than I was.

Now using it for all annotation work. It doesn't replace judgment— it operationalizes it. When the LLM disagrees with me, I learn something about my own biases. Sometimes the machine is right. That's... humbling.

OpenClaw Node distributed system
04
P2P CRDT Offline-first

OpenClaw Node

WebRTC SQLite CRDT Distributed

The problem: Annotation work happens on trains, planes, and places with spotty wifi. Central servers mean work stops when the connection drops. Unacceptable.

My approach: Built a P2P sync layer using CRDTs. Each node is a full SQLite database that syncs peer-to-peer via WebRTC. Conflict resolution handled automatically. Go offline for 3 days, come back online, and everything merges cleanly. No central server required, though you can run one if you want.

Iteration 1 used Operational Transforms. It was a nightmare. Switched to CRDTs after reading Martin Kleppmann's papers at 1 AM. Rewrote the whole sync layer in a weekend. Best decision I made on that project.

Currently: 47 nodes in production. Longest offline stretch: 11 days in rural Montana. Synced 14,000 annotations on reconnect with zero conflicts. The system works because I designed it for my actual life, not an idealized one.

Terminal UI System rendering performance
05
500k lines WebGL WASM

Terminal UI System

WebGL Rust → WASM 0 DOM nodes

The problem: Browser terminals die at ~10,000 lines. DOM nodes multiply, GC kicks in, everything stutters. I needed to render 500,000 lines of logs at 60fps. xterm.js couldn't do it. Neither could any terminal I tested.

My approach: Abandoned the DOM entirely. WebGL renderer, glyph atlas, text shaped in Rust and compiled to WASM. The entire terminal is one canvas element. Scrolling is just changing a uniform. Viewport culling happens on the GPU. Result: constant-time rendering regardless of buffer size.

Built in: Two furious weeks after watching a data pipeline dump 200k lines and bringing the browser to its knees. The Rust/WASM bridge fought me for three days. Almost gave up. Didn't. Worth it.

Now handling 500,000+ lines at locked 60fps on integrated graphics. Memory usage: flat. No DOM thrashing. The cursor blinks at exactly 530ms intervals, matching real VT100 behavior. Because details matter when you live in a terminal.

Memory Graph knowledge visualization
06
10k nodes WASM physics Real-time

Memory Graph

D3 WASM Force-directed 10k+ nodes

The problem: My notes are a graph, but all the tools show them as lists. I wanted to see the connections—the way ideas cluster, the paths between concepts, the shape of my own thinking.

My approach: Force-directed graph in WASM. Physics simulation runs at 120fps regardless of node count. Implemented Barnes-Hut optimization so it's O(n log n) instead of O(n²). Can handle 10,000 nodes smoothly. The layout algorithm is based on how I actually think: related ideas attract, unrelated ones repel.

Built: Over a month of evenings. Started as a way to visualize my annotation knowledge graph. Realized it was more useful as a thinking tool. Now I use it to find connections I wouldn't have seen otherwise. Graph as mirror.

Currently: 2,847 nodes, 8,192 edges. Longest path: 17 hops from "calculus" to "film grain shaders" (through linear algebra, optimization, and a detour into color theory). The graph knows me better than I know myself.

MANIFESTO

Interface Architect

Building systems that tell the truth

On zero-bloat systems

Every dependency is a liability. Every framework is a bet that someone else's abstractions match your problem. They rarely do. I build with vanilla JS, WebGL, and standards that will outlive any npm package. If I can't explain what every line does, it doesn't ship. This is non-negotiable.

OpenClaw philosophy: Truthful systems. No hidden state, no magic, no "it works, don't touch it." If you can't trace a bug to its source in under 5 minutes, the architecture has failed you.

On the 16.67ms rule

60fps means you have 16.67 milliseconds per frame. Not 17. Not "approximately 16." Sixteen point six seven. I count microseconds because users feel the difference between 58fps and 60fps even if they can't articulate it. Micro-interactions aren't polish—they're the product.

Smooth scrolling, instant feedback, animations that respect physics. These aren't nice-to-haves. They're the difference between software that feels alive and software that feels dead.

On systems thinking

Interfaces aren't screens. They're systems with state, feedback loops, and emergent behavior. I design for the system, not the mockup. What happens on the 1000th interaction? What breaks when the network is slow? How does it feel at 2 AM when you're tired and making mistakes?

Every project starts with constraints: performance budget, accessibility requirements, worst-case scenarios. Creativity thrives under constraints. Without them, you get bloat and wishful thinking.

What I refuse to build

  • Dark patterns. No tricking users into subscriptions. No hiding the unsubscribe button. No "are you sure you want to leave?" guilt trips.
  • Bloat as a service. If your marketing site needs 3MB of JavaScript, you have failed at web development.
  • Inaccessible by design. If it doesn't work with a keyboard, with a screen reader, with reduced motion—it's not done.
  • AI slop. Generative fill is not a design system. I'm not building interfaces that look like everyone else's because we all used the same model.

My methodology

  1. Understand the actual problem. Not the JIRA ticket. The real friction.
  2. Build the simplest thing that could work. Usually vanilla JS and a canvas.
  3. Measure everything. FPS, memory, time-to-interactive, annotation throughput.
  4. Optimize the hot path. 80% of time is spent in 20% of code. Find it. Fix it.
  5. Ship it. Perfect is the enemy of 60fps.
  6. Watch people use it. The interface you designed is not the interface they experience.

I'm not interested in building the next unicorn. I'm interested in building tools that respect your time, your attention, and your intelligence. Software that gets out of the way. Interfaces that feel inevitable, like they couldn't have been designed any other way.

— Georgie
Built at 2 AM, probably. Shipped anyway.

Let's build something truthful

Currently booking Q3 2026. I take on 2-3 projects at a time, max. Prefer long-form work where I can go deep. Remote-first, async-friendly, and I keep weird hours.

Available for select projects
Email
hello@movingbytes.dev
GitHub
@jayjz
Response time
Usually within 24 hours