# The Long Silence renders a seeded universe around a 0.1 unit ship

> A browser-based space exploration game in WebGL2 where stars, worlds, nebulae and derelicts are generated from a seed and shaded by hand-written shaders, with one deliberate exception: the ground under your feet is authored through image generation and headless Blender. The technical write-up is unusually specific about why each rendering decision was made.

**achimala/TheLongSilence** — A space exploration game built by Claude Opus 5

- Repository: https://github.com/achimala/TheLongSilence
- Stars: 518 · Forks: 80
- Language: JavaScript
- License: MIT
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/achimala-thelongsilence

## Everything is a seed except the ground beneath your boots

The premise is that almost nothing ships as an asset. Every star, world, ring system, nebula and derelict is generated from a seed and shaded by shaders written by hand. No photographs, no third-party files, nothing downloaded from an asset store.

There is one exception, and the project is upfront about it. The ground under your feet, the surface you land on and walk across, is authored by an image generation model and by Blender, driven through Python scripts in the tools directory, then shipped as images and one small GLB. So the dividing line is deliberate: everything you see from orbit is maths, and everything you stand on is art-directed.

That split has a practical consequence. The space scenes can be made arbitrarily large because their detail comes from a seed rather than from memory, while the landed scene has a bounded budget of authored material sets, which is why the later sections talk about picking four out of thirteen rather than generating new ones per planet.

Running it needs a build step and a dev server:

```bash
npm install
npm run dev        # http://localhost:5173
npm run build      # static bundle in dist/
```

The production output is a static bundle, and the runtime dependency list is a single 3D library, with the bundler, the browser automation used for smoke tests and the deployment tool all kept as development dependencies.

## A floating origin exists because the ship is 0.1 units long

One world unit is one kilometre. A single system spans millions of units while the ship is 0.1 units long. That ratio is the whole reason the renderer is built the way it is.

A floating origin solves the precision half. The ship is pinned at the origin and everything else in the system is positioned relative to it every frame, so the coordinates that matter stay small no matter how far out you have travelled. Without that, double precision starts losing the fractional detail that a hull 100 metres long needs when it sits four million kilometres from anything.

The depth half needs a logarithmic depth buffer, and this is where the project documents a sharp edge. Custom shader materials have to opt into log depth by hand, through specific shader chunks in the noise shader file. Miss that opt-in and two concentric spheres z-fight, which the author describes as the result looking like triangular confetti. It is a failure mode that would be hard to diagnose without knowing it was possible.

So there are two cooperating mechanisms here: one to keep coordinates small, one to keep depth usable across six orders of magnitude, and each has to be respected explicitly by anything that draws.

## Planets are baked into cubemaps once instead of evaluated per pixel

The terrain function is expensive. Roughly twenty octaves of simplex noise per pixel, per frame, is not something a phone survives, so the project does not evaluate it at runtime at all.

Instead each solid world is rendered exactly once into a cubemap. Linear albedo goes into the red, green and blue channels and terrain height goes into the alpha channel. The runtime shader then reads that back with three texture taps for normals, plus lighting. The expensive work happens once per world rather than once per pixel per frame.

The choice of cubemap over an equirectangular map is not incidental. A cube projection has no pole pinch and no seam, and both of those are the standard artefacts you would otherwise spend time fixing on an object as visible as a planet.

Resolution is spent selectively. The nearest world is re-baked at 1024 pixels per face, and everything else sits at 256. Since you are looking at one planet up close and several as distant points at any moment, that is the allocation that matches what the camera is actually doing.

Atmospheres use a different technique again: a single-scattering raymarch through a spherical shell, worked in an object space scaled to the planet's own radius, with Rayleigh coefficients taken from real optical depths and a soft penumbra on the light ray so that twilight fades instead of stopping at a hard line.

## Auto exposure uses a square-root mean because the sky is black

Exposure adaptation runs entirely on the GPU rather than reading pixels back to the CPU. A luminance reduction steps from 64 pixels down to 8 and then to 1, and the result feeds a ping-pong adaptation target.

The interesting decision is the statistic used to average those samples. The textbook choice for this is a logarithmic mean, and the project rejects it with a specific reason: a space frame is about 90 percent black sky, and taking the logarithm of values near zero drags the average down to almost nothing, which then blows out every shot.

The substitute is a square-root mean, which compresses the same range without collapsing toward zero the way the logarithm does. Same inputs, same hardware, same reduction cascade, but the averaging function is chosen for the actual content rather than for the general case.

The post-processing chain is equally hand-rolled rather than assembled from a library: a bright pass prefilter, six levels of dual-filter bloom with attenuated wide mips, an anamorphic streak, god rays and lens ghosts, then a composite doing radial blur, chromatic aberration inside the sampler, an AgX tonemap, grain and dither, finished with antialiasing.

Performance is held at 60 frames per second by trading resolution rather than features, with the engine watching frame time and moving the render scale between 0.62 and 2 times. Nothing in the feature set turns off; the image just gets softer.

## Traffic runs on a schedule rather than a simulation

Space traffic in a game like this is usually the obvious place to spend effort: simulate ships, steer them, let them react. This project does the opposite and schedules them.

Craft follow analytic paths keyed to the clock. The consequence is that they are exactly where they belong after a fold jump or after you have paused for two minutes, which matters more than it sounds in a game built around teleporting between star systems and closing the tab.

Each craft carries a beacon, and the beacon is a quad sized from view depth so that it holds a constant few pixels on screen regardless of distance. The reasoning is geometric: sixty metres of hull four million kilometres away is far below a single pixel, so at true scale a freighter would simply not be there.

The beacon is what makes a system read as busy. It is an admission that the simulation was traded for legibility, done deliberately rather than by omission.

The rest of the world follows the same principle of visual honesty at impossible scales. Distant points keep their brightness instead of vanishing, because a system that looks empty at range does not read as populated once you arrive.

## The ground asks the height field once per instance, not once per vertex

Standing on a planet needs a completely different scene from orbit, and the project separates them explicitly. Orbiting needs an entire planet with no visible surface geometry; standing on one needs ten kilometres of terrain with no visible sphere at all. So the ground is its own radial grid whose rings grow exponentially, displaced by the same terrain function used for the orbital bake, bent down by the planet's real radius and hazed by the same scattering coefficients as the atmosphere shell above it.

The optimisation described here has a before and an after. A tuft, a tree and a stone each need to know where the surface is, which way it faces, whether the habitat rules permit it, and whether it sits in shadow. Previously every vertex of every instance asked those questions again. Now a placement pass answers them once per instance into three small float textures each frame, and the vertex shaders fetch their texel by instance id.

The measured effect is given: the worst landed frame went from 50 milliseconds to 13 at 5.7 megapixels. That is close to a fourfold improvement on the heaviest case, which is the frame where the ground is most of the screen.

The landed look comes from authored material sets. There are thirteen, each generated as a photographic albedo by an image model with height, normal, roughness and occlusion derived from it numerically, seam-fixed in the gradient domain. A world picks four by type, and the terrain shader blends them by height so sand pools in the hollows and rock crests break through, sampling the larger octaves stochastically so no tile repeats visibly, then retinting everything about that world's palette so one image serves both an oxide desert and a bone-coloured one.

## One construction kit surfaces the ship, freighters, stations and derelicts

The unifying idea in the rendering code is that everything man-made looks the same way because one module makes it so.

A single greeble module owns the plate-seam law, the weathering, the sun-bleaching, a grazing rim term and five base materials. The player's hull, every freighter, every station and every derelict are surfaced by that one kit rather than by separate asset pipelines, which is why a derelict abandoned in a distant system shares its construction grammar with the ship you flew there.

The detail that makes it hold up is welding. Parts bake their own transforms into their geometry and are then welded per material, so panel lines run continuously across the boundary between two parts instead of stopping at the seam where they were assembled. A hundred pieces cost six draw calls after that, which is what allows a hundred pieces to exist at all.

The player's hull is not modelled by hand either. A Python script lofts it in headless Blender, so the ship that appears in the title sequence and the ship you fly are the same object by construction rather than by manual matching.

Around all of this sits ordinary tooling: a smoke test driven by browser automation, an icon generator, a splash image generator that shells out to a platform image tool to produce the social preview, and a deploy script that builds and pushes through a command line tool for a worker runtime. The source is laid out so that the engine and input sit apart from graphics, world generation, ship, game logic and interface.

## Conclusion

The Long Silence is worth reading if you build graphics in a browser, because the write-up explains the failure mode behind almost every technique rather than asserting that it is fast, and the numbers given are specific enough to check your own assumptions against. It suits you less if you want to read about game design, since the story premise occupies a few paragraphs and the rest is rendering engineering. Before running it, expect a hard requirement for WebGL2 and a first frame that compiles shaders for a while, and note that the only runtime dependency is the 3D library itself, with the build tooling kept separate.

## FAQ

### What does The Long Silence run on, and what does it need?

It runs in a browser tab using WebGL2 with no downloaded assets. The production build is a static bundle, and the only runtime dependency is a 3D library, with the bundler, browser automation for smoke tests and the deployment tool all kept as development dependencies.

### Does The Long Silence ship with textures or models from elsewhere?

No. Stars, worlds, ring systems, nebulae and derelicts are generated from a seed and shaded by hand-written shaders, and nothing is a photograph or a third-party file. The one exception is the ground under your boots, whose materials, stones and leaves are authored by an image model and by Blender and shipped as images and one small model file.

### Why does the game use a floating origin?

One world unit is one kilometre and a system spans millions of units while the ship is 0.1 units long, so ordinary floating point loses the detail a small hull needs. The ship is pinned at the origin and everything else is positioned relative to it each frame.

### How are the planets drawn at runtime?

Each solid world is baked once into a cubemap holding linear albedo in colour channels and terrain height in alpha, then read back with three texture taps for normals plus lighting. The nearest world re-bakes at 1024 pixels per face and the rest sit at 256. Cubemaps are used rather than equirectangular maps to avoid pole pinch and a seam.

### Why does auto exposure use a square-root mean instead of a log mean?

A space frame is about 90 percent black sky, and logging values near zero drags the average toward nothing, which blows out every shot. A square-root mean compresses the range without collapsing to zero. The reduction runs on the GPU from 64 pixels down to 8 and then 1, feeding a ping-pong adaptation target.

### How does the game keep 60 frames per second?

By trading resolution rather than features. The engine watches frame time and moves the render scale between 0.62 and 2 times, so the frame rate is held by softening the image instead of removing anything from the scene.

## Sources

- [achimala/TheLongSilence on GitHub](https://github.com/achimala/TheLongSilence)
- [Issues](https://github.com/achimala/TheLongSilence/issues)
- [License: MIT](https://github.com/achimala/TheLongSilence/blob/main/LICENSE)
- [README](https://github.com/achimala/TheLongSilence/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/achimala-thelongsilence
