01 / 06Create React App · canvas grid
Tomi AI Cube
A companion that lived in a terminal.
The first attempt was a command line that could draw. Create React App, plain JavaScript, one fullscreen canvas where every letter and every animation was assembled out of little cubes. Commands were plugins — /galaxy, /ring, /countdown, /time — and a small backend on port 3580 held what it knew about you: your name, your preferences, the thread of the session.
Why it did not stayIt could talk and it could remember, but it had no presence — a prompt with a memory is still a prompt. The memory idea stayed in the plan; the interface did not survive the week.
02 / 06Vanilla JS · Grunt · particles
Tomi AI Ball · Shape Shifter
No framework, no interface — just an object made of dots.
React went out entirely: vanilla JavaScript, a Grunt build, and a sphere of particles that scattered and reassembled into words, icons and shapes. Commands started with # and chained through |; a ?say= link handed the same state to somebody else. Font Awesome lived in the repository instead of on a CDN, on purpose.
Why it did not stayGorgeous for ten seconds and empty on the eleventh. It settled two things for good: the companion is an object, not a form field, and owning the render loop is worth losing the framework.
03 / 06Vite · React · TypeScript
Pixi · OLED Companion
It turns out the companion is a device.
A 32×34 pixel matrix on OLED black, seventeen emotions each in its own module, and forty-six tiny apps living on that screen: clock, snake, tetris, pong, breakout, flappy, invaders, tic-tac-toe, battleship, matrix rain, starfield, plasma, radar, an oscilloscope, Conway's life, a maze. Voice input, and a double tap for immersive mode.
Why it did not stayThe richest of the six and the hardest to aim: forty-six screens make a handheld console, not a companion. The device metaphor was kept. The buffet was not.
04 / 06Vite · React · anime.js
RoboCompanion
Everything bet on the face.
One component of sixty-four kilobytes drew a big robot face: seventeen emotions with real transitions between them, not swapped pictures. Post-processing hung off it as plugins — CRT, dithering, glitch, LED, matrix rain. Left alone it kept behaving on its own, and it spoke two languages.
Why it did not stayThe hypothesis held — character beats features — and the bill arrived with it: a single file that large is where every next idea goes to stall.
05 / 06Vite · React · MediaPipe
AIC v2
Giving it eyes.
The camera watches your face and your hands, and the companion answers with an expression. The model and the key moved into a settings panel inside the app, a light theme joined the dark one, and the interface learned to translate itself.
Why it did not stayThe most ambitious and the least finished — a fair number of animations never got past placeholders. The camera went back on the shelf, and the settings panel quietly proved the opposite of its own point: picking the model is not the client's job.
06 / 06Vite + TypeScript · Node + Express + Postgres
Tomi
The one that shipped.
Three applications: a client on Vite and TypeScript with no framework on purpose — eighty-five per cent of the screen is canvas, and a framework only gets in the way of a sixty-frame loop — a Node, Express and Postgres backend, and a separate admin app. The server decides the model and the prompt, not the client. Memory is typed facts with validity windows: nothing is deleted, a newer fact displaces an older one. Money is counted in whole micro-dollars, because floating point and billing do not mix.
What it does differentlyThe circle closes. Terminal, then object, then device, then face, then eyes — and finally a companion that lives on a phone, runs its own interface and keeps its own accounts. Everything the first five proved is in here, and everything they cost is why it looks the way it does.