Lúmina: a personal memory archive where your memories orbit as a galaxy (three.js + Angular)

Lúmina — memory as a place you navigate: orbits, a gravitational lens, and a space for what you want to remember.

Live: https://growingdesert.com

Everything drifts toward disorder. What we call a person is, mostly, what they managed to keep. I wanted an place where that was literal; where memories had positions, orbits and distances. So I built it using three.js.

The screens, in order: the entry; your own space, where each memory orbits a nucleus and a nucleus is a theme you gave it; a memory opened; the shared space before anyone has written to you; other people’s universes, linked by the memories actually exchanged; and the oblivion, where what you let go ends up.

How it’s built

Angular 22 + three.js, shipped as a PWA — no store, it runs in the browser including on phones.

The particle work splits in two. Dense clouds are THREE.Points driven by a custom ShaderMaterial, with per-particle attributes for colour, size, alpha, phase and a drift vector, so each particle moves and twinkles at its own rate and nothing is synchronised. Anything that has to be individually picked or animated is a Sprite instead, with materials pooled and cached
by key.

There are no image assets in the 3D at all. Soft glows are either computed per fragment from gl_PointCoord or generated at runtime as radial gradients on a 2D canvas, and some labels are text baked onto a canvas and uploaded as a CanvasTexture.

Positions come from real orbital parameters; radius, angular speed, phase, axis; rather than laid-out coordinates. Beyond that it’s THREE.Line for the filaments between things, Mesh for shells and for a subdividedPlaneGeometry displaced into terrain, OrbitControls for the camera and
a Raycaster for picking.

The heaviest piece is a full-screen post pass, and it’s an easter egg: click the logo enough times and the universe collapses. The scene renders into a WebGLRenderTarget and a single fullscreen triangle samples it through a lens shader, so whatever was moving keeps moving while it bends. It runs as an explicit state machine on a single clock, the overlay’s render loop, instead of chained timeouts, so a dropped frame delays every phase equally rather than letting the shader and the phase count different things. The target is half-float and stays in linear space on purpose: three only encodes to sRGB when drawing to the canvas, so at 8 bits the lower half of the linear range quantises away and a scene this dark posterises and lifts. With half-float the round trip is exact and there’s no visible jump when the effect is off.

If you open it

What I’d most value back is dull and specific: what device you were on and how it ran. I have no way to test across hardware, and mid-range Android is exactly the target I have to hit — a line like “Pixel 6a, smooth” or “old iPad, crawls once there are a few universes” is worth more
to me than any compliment.

And if you have a second one in you: did the space read as something you could navigate, or did you have to work out what to do?.

Happy to go into any part of the implementation in more detail.

You should profile based on GPU metrics, using tools like Spector.js , DevTools to monitor CPU usage. Relying solely on FPS won’t reveal exactly which components are consuming resources, and performance will plummet drastically on entry-level GPUs. Granular monitoring allows you to accurately estimate how your project will perform on lower-end devices without actually needing to own them. Additionally, it is best to avoid features that lack broad compatibility

I like the idea of ​​storing memories, but is there a way to experience it without having to log in?

2 Likes

Thanks, that’s genuinely useful. I’ve been leaning on FPS and you’re right
that it’s the metric that tells you least, it says something is wrong,
never what. I’ll capture a frame with Spector.js and profile it properly
instead of guessing, and I’ll keep the compatibility point in mind.

On logging in: fair, and you’re not the first to ask. I’m going to put
together a demo that shows the main parts of the space without an account,
so you can move through it before deciding whether you want one. I’ll post
back here when it’s ready.

1 Like