The whole thing, as ground you can fly.
I build the model side and the product side of the same thing, and I ship it under my own domains.
11domains live
6projects built end to end alone
17summits on this map
The range has a shape and the shape is the argument. The capital in the middle is me: ayoubalkak.com, the tallest mountain on the map. Lumevel stands on its shoulder, one step down. From there the ground falls away into three ranges, rendering, models and infrastructure, and under those sit the grounds the projects stand on. A solid path means one thing is built on the other and I can point at the line in the code. A faint dotted path means one domain lives under another. Nothing is connected because it looked better connected.
Nothing here is a picture of the work either. Fly into a summit and you land in a small place built from what that project actually does: Aurora keeps its own lights in the sky, Drift is a field of particles that will not sit still, Conveyor is a line of jobs where some of them fail, Creeper Glory is a town assembling out of cubes. Each place runs live, on your GPU, while you read.
I run Lumevel, a web design company. On the map it stands on the capital's shoulder, one step below me and apart from the lab work. The rest is mine: rendering work on the GPU, models running where the request is instead of at somebody else's endpoint, and the plumbing that keeps a job alive after it fails.
Reach me
Moving around
Drag to orbit, wheel or pinch to zoom, Shift drag to pan. Arrow keys or WASD move you over the ground, O pulls back to the whole range, Escape steps out of wherever you are. Click a summit or a region name to fly there. The address bar keeps up, so any place can be linked.
This page normally opens as a mountain range you fly through: a capital in the middle, ranges falling away from it, seventeen summits on real terrain. With JavaScript off you are reading the same words as a plain document, all of them, in order. Nothing was held back for the map.
Eleven domains, all live.
Every one of these resolves right now, and every one is mine.
Every place on the map
Reach me
▲ Rendering
The Rendering range
Rendering
Pixels on the GPU. Three projects and the ground under them.
Aurora writes GLSL by hand. Drift reaches the same instruction stream from much higher up, through Three.js and react-three-fiber. Creeper Glory never leaves the DOM and holds its frame rate anyway. React and Vite are the shell all three share.
Six of the seventeen summits stand in this range, close together, so it reads as the broadest ground on the map.
Summits here
Rendering · a summit with its own sky
Aurora
Generative skies, written as a real WebGL shader.
The lights standing over this summit are the project's own kind: curtains drawn by a shader, moving because time is one of their inputs. Not a video, not a texture.
The sky is one fragment shader. There are no textures, no sprites and no image of a cloud anywhere in it. Every pixel is a function of position and time, evaluated on the GPU: value noise stacked into fractal Brownian motion, warped by a second noise field so the bands curl instead of sliding, then lit by a sun that is two numbers.
React, Zustand and Vite hold the dials and nothing else. Anything that has to be right sixty times a second lives in GLSL, because that is the only place it can be.
Stack
Links
Rendering · a summit that will not sit still
Drift
A dreamscape you move through. Instanced spring physics, bloom, depth of field.
The swarm breathing around this peak is the project at small scale: hundreds of points, each pulled home by a spring, none of them ever quite arriving.
Points on springs. Each one has a rest position and a velocity, the pointer pushes on the field, and the springs pull it back with damping so it settles instead of ringing. Depth does the rest of the work: size, brightness and softness all fall off with distance, so the field reads as a volume rather than a wall of dots.
The real one runs on react-three-fiber with instanced meshes, so all of it is one draw call, and the bloom and depth of field are post passes.
Stack
- react-three-fiber
- Three.js
- drei
Links
Rendering · a town built out of cubes
Creeper Glory
A maximalist Minecraft showcase. Motion design held to production grade from the first frame to the last.
The blocks assembling beside this summit do it the way the real site does: staggered off the diagonal, so the build reads as a wave instead of a pop.
A showcase built at the motion quality I would hand to a client, not the quality that survives one demo. Every transition is choreographed rather than defaulted, and the ones that could not be faked had to hold their frame rate on a laptop.
It is the loudest thing I have built and it is deliberate. Restraint is easy to claim when you have never tried the other end.
Stack
Links
Rendering · standing ground
GLSL
The language the GPU actually runs.
Aurora writes GLSL by hand. Three.js writes it for you, from materials you configure. That is the whole reason those two stand next to each other here: the same instruction stream at the bottom, reached from two very different heights.
Knowing what the generated shader looks like is what makes the generated one debuggable.
Feeds
Rendering · standing ground
Three.js
A scene graph over WebGL.
Drift talks to it through react-three-fiber, so the scene is described in React and rendered outside of it. React decides what exists. The render loop, which runs every frame, never goes through React at all.
drei supplies the parts nobody should write twice: controls, loaders, the post processing chain. This page is built on it too, which felt like the only honest choice.
Feeds
Rendering · standing ground
React and Vite
The shell three of these projects share.
Aurora, Drift and Creeper Glory all start from the same shell. It holds state, routing and the dev server, and it stays out of the frame loop. The rule is the same in all three: React owns what exists, the animation owns what it looks like this millisecond.
Feeds
▲ Models
The Models range
Models
Inference where the request is.
Lens and Resonance, and the one decision they share. The weights ship with the project, so neither of them calls a vision API or a sentiment API. transformers.js against ONNX weights is that decision, and it is the only path that runs between these two.
Resonance also reaches into Infrastructure, because a model has to load into something.
Summits here
Models · a summit that reads images
Lens
Classification, OCR and a palette, every model self hosted. No Vision API.
The prism turning over this summit throws off five shards of color. That is the palette step: Lens ends every run by clustering an image down to the few colors that carry it.
Three things happen to an image and none of them leave the machine. A classifier labels it, Tesseract reads whatever text is in it, and a clustering pass pulls out the palette. sharp does the decoding and resizing before any of that.
Stack
- transformers.js
- Tesseract.js
- sharp
Links
Models · a summit that listens
Resonance
Text goes in, an emotion spectrum comes out, from a transformer running on the server rather than somebody else's endpoint.
The rings widening from this peak are its output made visible: a sentence lands, and a spectrum spreads out from it.
The model is ONNX weights, loaded and run by transformers.js in the serverless function itself. The sentence you type does not become an API call to a third party, which was the entire reason to build it rather than wire up a sentiment endpoint in an afternoon.
The interesting part is not the model, it is the cold start: getting weights into a function that only exists while the request does, without making the first visitor wait for it.
Stack
- transformers.js
- ONNX
- Vercel
Links
Models · standing ground
transformers.js and ONNX
Transformer models running in JavaScript, against ONNX weights.
Lens and Resonance both stand on this, which is why neither of them needs a vision API or a sentiment API. The weights ship with the project and the inference happens where the request already is.
It is the single decision that connects those two summits, and it is the reason the words self hosted are on this page twice.
Feeds
▲ Infrastructure
The Infrastructure range
Infrastructure
Queues, state, deploys.
Conveyor and the two things it stands on. QStash moves the jobs, Redis remembers what happened to each one, and without that second half a retry is indistinguishable from a duplicate.
Vercel is the summit two ranges touch. Conveyor and Resonance both need a server that exists only while the request does, and that constraint shaped both of them.
Summits here
Infrastructure · a summit with a working line
Conveyor
A job pipeline you can watch. Serverless queue, retries, and a dead letter sink for the ones that never make it.
The line circling this summit is doing the real thing: jobs moving, one of them failing, waiting out its backoff, and the unlucky ones dropping into the pit that glows red. That pit is the dead letter sink.
A queue is easy to describe and hard to watch. This one publishes jobs to QStash, keeps every job's state in Redis, and gives each one a bounded number of attempts with a growing delay between them.
What the interface shows is the part that normally only exists in logs: the attempt that failed, the wait before the next one, and the job that runs out of attempts and lands in the dead letter sink instead of disappearing. A pipeline you cannot see is a pipeline you cannot fix.
Stack
- Upstash QStash
- Redis
- Vercel
Links
Infrastructure · standing ground
QStash and Redis
The queue and the memory behind Conveyor.
QStash delivers the jobs. Redis remembers what happened to each one, which is the half people skip. Without it a retry is indistinguishable from a duplicate, and a dead letter is just a job that stopped.
Feeds
Infrastructure · standing ground
Vercel
Where the serverless parts run.
Conveyor and Resonance both need a server that exists only while a request does. That constraint shapes both of them: Conveyor cannot hold a worker open, so state has to live somewhere else, and Resonance has to get a model into a process that will be thrown away.
It is the one summit on this map that two different ranges touch.
Feeds
▲ Shipped
The Shipped range
Shipped
Domains with people on them.
Five summits. ayoubalkak.com is the capital of the map and the parent of eight subdomains, and the faint dotted paths running out of it are that and only that. DNS, not architecture.
Lumevel and Traduction Office are their own apex domains and carry no paths at all, because there is no path to draw.
Summits here
Shipped · the capital
ayoubalkak.com
You are here.
The center of the map is me, on purpose. Ayoub Alkak, AI engineer and full stack developer in Limoges, France. This mountain is the tallest here because everything else runs out and down from it: Lumevel on the shoulder, the three ranges below, the grounds under those.
The citadel on this summit has a curtain wall, a keep and a lighthouse whose beam sweeps the range. The eight obelisks standing outside its wall are the subdomains, and the faint paths running out to them are the DNS records made visible.
The apex domain, and the parent of eight of the subdomains on this map: aurora, drift, lens, conveyor, resonance, creeper, code-de-la-route and decode. The faint paths running out of this summit are that, and only that. DNS, not architecture.
Two of the eleven domains are not under it. Lumevel and Traduction Office are their own apex domains, because they are their own things.
Links
Shipped · the studio
Lumevel
The web design company I run.
The hall on this summit is a drawing office. The frames circling its roof are pages of light, each one sketching a layout that never quite finishes, and the windows stay lit.
Its own domain, its own brand, its own clients. It stands on the capital's shoulder, one step down: close because I run it, separate because it is a company and not a lab project.
No path runs from Lumevel to the projects, because there is not one. Client work and lab work are separate, and pretending otherwise would be the first lie on this page.
Links
Shipped · three languages
Traduction Office
Clients and translators, in French, English and Arabic, with RTL.
Two sides of a marketplace in one product, in three languages, one of which runs right to left. RTL is not a stylesheet flag. It changes what leading means, which side a chevron points, how a mixed number reads inside an Arabic sentence, and where a form error should sit.
Its own apex domain, not a subdomain of mine.
Links
Shipped · on the road
Code de la Route
The French driving code, with the English alongside it.
Live, on a subdomain of ayoubalkak.com. Both languages, side by side.
Links
Shipped · version one
Decode
Live, v1.
On its own subdomain, shipped and running. There is a v2 in my head and nothing about it belongs on this page yet.
Links