---
title: orbital drift
canonical: "https://presque.cool/projects/orbital-drift/"
description: "Des paysages sci-fi, un cockpit spatial et de la radio ambient. Une fenêtre contemplative sur des mondes qui n'existent pas."
---

<div data-lang="fr">

## Le pitch

Orbital Drift est un générateur procédural de paysages sci-fi. Des soleils binaires, des planètes aux textures variées, des champs d'étoiles — le tout généré algorithmiquement avec des palettes de couleurs personnalisables. Chaque scène est unique et peut être sauvegardée ou partagée via URL.

**Essayer** : [presque.cool/orbital-drift/](https://presque.cool/orbital-drift/)

<div class="quick-overview">
  <div class="overview-item">
    <span class="overview-label">Durée</span>
    <span class="overview-value">~3 semaines</span>
  </div>
  <div class="overview-item">
    <span class="overview-label">Période</span>
    <span class="overview-value">Fév 2018 → Déc 2025</span>
  </div>
  <div class="overview-item">
    <span class="overview-label">Stack</span>
    <div class="tech-tags">
      <span class="tech-tag">React</span>
      <span class="tech-tag">TypeScript</span>
      <span class="tech-tag">Canvas API</span>
      <span class="tech-tag">PWA</span>
    </div>
  </div>
  <div class="overview-item">
    <span class="overview-label">Statut</span>
    <span class="overview-value accent">✓ En production</span>
  </div>
</div>

---

## Pourquoi ce projet

Un jour, en naviguant sur internet, je suis tombé sur un [tutoriel de Geometrieva](https://geometrieva.medium.com/tutorial-for-that-space-illustration-you-keep-seeing-around-9c97214b4d92) pour créer des paysages spatiaux minimalistes. L'esthétique m'a immédiatement parlé — elle ressemblait à celle des vidéos de [Kurzgesagt](https://www.youtube.com/@kurzgesagt), une chaîne que je suis depuis longtemps.

Je me suis dit : et si je générais ce type de paysage de manière procédurale ?

L'image m'avait donné envie d'en faire une version procédurale — des centaines de scènes différentes à partir du même code, chacune unique et partageable.

Je voulais aussi quelque chose de **contemplatif**. Pas un jeu, pas un outil utilitaire — juste une fenêtre sur un univers généré, qu'on peut regarder défiler.

---

## Deux versions, deux époques

**Prototype Vanilla JS (2018)** :
Première expérimentation avec la génération procédurale et le Canvas API. L'essentiel était là : soleils, planètes, étoiles, palettes de couleurs. Puis le prototype est resté en l'état pendant 7 ans.

**Version finalisée React (décembre 2025)** :
Réécriture complète — pas une migration. L'esthétique générale (Kurzgesagt, Geometrieva) est restée, mais le code a été entièrement repensé. J'en ai profité pour ajouter ce qui manquait à l'expérience contemplative :

- **Ambiance "cockpit spatial"** — Un HUD discret, un effet CRT optionnel, une impression d'être aux commandes d'un vaisseau
- **Radio streaming** — Les stations proviennent de [BoxRadio.net](https://boxradio.net/), un agrégateur de radios en streaming. Inspiré par Lofi Girl, elles accompagnent la contemplation avec de la musique d'ambiance.
- **Mode fullscreen avec Wake Lock** — L'écran ne se met pas en veille, parfait pour laisser tourner en fond

Ces éléments se sont ajoutés en cours de route. Le projet a grandi au-delà de l'idée initiale — 7 ans de maturation entre un prototype brut et une expérience complète.

---

## Le cœur technique : génération procédurale déterministe

Chaque scène est générée à partir d'un **seed**. Le même seed produit toujours la même scène — c'est ce qui permet de sauvegarder et partager des paysages via URL.

**PRNG Mulberry32** :
Un générateur de nombres pseudo-aléatoires déterministe. À partir du seed, il produit une séquence de nombres qui semble aléatoire mais qui est parfaitement reproductible.

**Placement des planètes** :
Les planètes sont placées avec un algorithme anti-chevauchement ("breathing room"). Chaque nouvelle planète doit respecter une distance minimale avec les autres pour éviter les collisions visuelles.

**Textures procédurales** :
Les planètes ont des patterns variés (lignes horizontales "hotdog", bandes "stripe"), des gradients multi-couches, des glows et des anneaux optionnels — tout généré algorithmiquement.

---

## Performance Canvas 2D

Le rendu doit rester fluide, même avec beaucoup d'éléments et un effet de parallaxe.

- **SSAA (Super-Sampling Anti-Aliasing)** — Le canvas est rendu à 2x la résolution, puis redimensionné. Cela donne un anti-aliasing propre sans passer par WebGL.
- **Cache de textures** — Les planètes sont pré-rendues dans des canvas offscreen et réutilisées. Cela évite de recalculer les textures à chaque frame.
- **Séparation en couches** — Les planètes arrière et avant sont séparées pour le parallaxe et le painter's algorithm (ce qui est derrière est dessiné en premier).
- **Overscan buffer** — Le canvas est légèrement plus grand que l'écran pour éviter les bords noirs pendant le parallaxe.

---

## L'expérience : au-delà du générateur

Ce qui fait tenir Orbital Drift, ce n'est pas la génération de paysages — c'est l'ambiance autour.

- **Radio intégrée** — Plusieurs stations de streaming audio, inspirées par l'ambiance Lofi Girl. La musique s'intègre naturellement à la contemplation spatiale.
- **Visualiseur audio** — Un visualiseur réactif qui pulse avec la musique — discret mais présent.
- **Wake Lock API** — En mode fullscreen, l'écran ne se met pas en veille. On peut laisser Orbital Drift tourner comme un fond animé.
- **Effet CRT optionnel** — Pour ceux qui aiment l'esthétique rétro-futuriste.

---

## Stack technique

<ul class="tech-stack">
<li><strong>React</strong> + <strong>TypeScript</strong></li>
<li><strong>Vite</strong> comme bundler (avec SWC)</li>
<li><strong>Tailwind CSS</strong> en mode CSS-first (couleurs OKLCH)</li>
<li><strong>Canvas API</strong> pour le rendu procédural</li>
<li><strong>Web Audio API</strong> pour le streaming et le visualiseur</li>
<li><strong>PWA</strong> — installable, offline</li>
<li><strong>i18n</strong> maison (français/anglais)</li>
<li><strong>Persistance localStorage</strong> pour les scènes sauvegardées</li>
<li><strong>Compression</strong> — Brotli + Gzip sur les assets</li>
<li><strong>CSP</strong> — Content-Security-Policy avec hashes auto-générés</li>
</ul>

---

## Évolutions

| Date     | Version | Description                                                                            |
| -------- | ------- | -------------------------------------------------------------------------------------- |
| Fév 2018 | 0.1.0   | Prototype initial — Génération procédurale de base avec soleils et planètes            |
| Déc 2025 | 1.0.0   | Réécriture React — Stack moderne, radio streaming, HUD, Wake Lock, sauvegarde, partage |

---

## Bilan

**Durée** : environ 3 semaines (décembre 2025).

**Ce que j'ai appris** :

- Ma première vraie expérience en génération procédurale — comprendre comment un seed et un PRNG peuvent créer des mondes cohérents
- Le Canvas API en profondeur : layering, caching, anti-aliasing sans WebGL
- L'importance de l'ambiance dans un projet contemplatif — les features "non-essentielles" (radio, CRT, Wake Lock) font toute la différence

**Ce que je referais pareil** :

- Commencer simple (juste la génération) et ajouter l'ambiance après — cela permet de valider le cœur technique avant d'investir dans le polish
- Rendre chaque scène partageable via URL dès le départ

**Ce que je changerais** :

- J'améliorerais la version mobile, pour l'instant elle n'est pas très satisfaisante.

</div>

<div data-lang="en">

## The pitch

Orbital Drift is a procedural sci-fi landscape generator. Binary suns, planets with varied textures, star fields — all generated algorithmically with customizable color palettes. Each scene is unique and can be saved or shared via URL.

**Try it**: [presque.cool/orbital-drift/](https://presque.cool/orbital-drift/)

<div class="quick-overview">
  <div class="overview-item">
    <span class="overview-label">Duration</span>
    <span class="overview-value">~3 weeks</span>
  </div>
  <div class="overview-item">
    <span class="overview-label">Period</span>
    <span class="overview-value">Feb 2018 → Dec 2025</span>
  </div>
  <div class="overview-item">
    <span class="overview-label">Stack</span>
    <div class="tech-tags">
      <span class="tech-tag">React</span>
      <span class="tech-tag">TypeScript</span>
      <span class="tech-tag">Canvas API</span>
      <span class="tech-tag">PWA</span>
    </div>
  </div>
  <div class="overview-item">
    <span class="overview-label">Status</span>
    <span class="overview-value accent">✓ In production</span>
  </div>
</div>

---

## Why this project

One day, browsing the internet, I came across a [tutorial by Geometrieva](https://geometrieva.medium.com/tutorial-for-that-space-illustration-you-keep-seeing-around-9c97214b4d92) for creating minimalist space landscapes. The aesthetic immediately spoke to me — it reminded me of [Kurzgesagt](https://www.youtube.com/@kurzgesagt) videos, a channel I've followed for a long time.

I thought: what if I generated this type of landscape procedurally?

The image made me want a procedural version — hundreds of different scenes from the same code, each one unique and shareable.

I also wanted something **contemplative**. Not a game, not a utility tool — just a window into a generated universe that you can watch unfold.

---

## Two versions, two eras

**Vanilla JS prototype (2018)**:
First experimentation with procedural generation and the Canvas API. The essentials were there: suns, planets, stars, color palettes. Then the prototype sat untouched for 7 years.

**Finalized React version (December 2025)**:
Complete rewrite — not a migration. The general aesthetic (Kurzgesagt, Geometrieva) remained, but the code was entirely rethought. I took the opportunity to add what was missing from the contemplative experience:

- **"Space cockpit" ambiance** — A subtle HUD, an optional CRT effect, a feeling of being at the controls of a spacecraft
- **Radio streaming** — Stations are sourced from [BoxRadio.net](https://boxradio.net/), a streaming radio aggregator. Inspired by Lofi Girl, they accompany contemplation with ambient music.
- **Fullscreen mode with Wake Lock** — The screen doesn't go to sleep, perfect for leaving it running in the background

These elements were added along the way. The project grew beyond the initial idea — 7 years of maturation between a raw prototype and a complete experience.

---

## The technical core: deterministic procedural generation

Each scene is generated from a **seed**. The same seed always produces the same scene — this is what allows saving and sharing landscapes via URL.

**Mulberry32 PRNG**:
A deterministic pseudo-random number generator. From the seed, it produces a sequence of numbers that seems random but is perfectly reproducible.

**Planet placement**:
Planets are placed with an anti-overlap algorithm ("breathing room"). Each new planet must respect a minimum distance from others to avoid visual collisions.

**Procedural textures**:
Planets have varied patterns (horizontal "hotdog" lines, "stripe" bands), multi-layer gradients, glows and optional rings — all generated algorithmically.

---

## Canvas 2D performance

Rendering must stay smooth, even with many elements and a parallax effect.

- **SSAA (Super-Sampling Anti-Aliasing)** — The canvas is rendered at 2x resolution, then resized. This provides clean anti-aliasing without WebGL.
- **Texture caching** — Planets are pre-rendered in offscreen canvases and reused. This avoids recalculating textures every frame.
- **Layer separation** — Back and front planets are separated for parallax and the painter's algorithm (what's behind is drawn first).
- **Overscan buffer** — The canvas is slightly larger than the screen to avoid black edges during parallax.

---

## The experience: beyond the generator

What makes Orbital Drift hold together isn't the landscape generation — it's the ambiance around it.

- **Integrated radio** — Several audio streaming stations, inspired by the Lofi Girl ambiance. Music integrates naturally with space contemplation.
- **Audio visualizer** — A reactive visualizer that pulses with the music — subtle but present.
- **Wake Lock API** — In fullscreen mode, the screen doesn't go to sleep. You can leave Orbital Drift running as an animated background.
- **Optional CRT effect** — For those who like the retro-futuristic aesthetic.

---

## Tech stack

<ul class="tech-stack">
<li><strong>React</strong> + <strong>TypeScript</strong></li>
<li><strong>Vite</strong> as bundler (with SWC)</li>
<li><strong>Tailwind CSS</strong> in CSS-first mode (OKLCH colors)</li>
<li><strong>Canvas API</strong> for procedural rendering</li>
<li><strong>Web Audio API</strong> for streaming and visualizer</li>
<li><strong>PWA</strong> — installable, offline</li>
<li><strong>i18n</strong> custom (French/English)</li>
<li><strong>localStorage persistence</strong> for saved scenes</li>
<li><strong>Compression</strong> — Brotli + Gzip on assets</li>
<li><strong>CSP</strong> — Content-Security-Policy with auto-generated hashes</li>
</ul>

---

## Timeline

| Date     | Version | Description                                                                          |
| -------- | ------- | ------------------------------------------------------------------------------------ |
| Feb 2018 | 0.1.0   | Initial prototype — Basic procedural generation with suns and planets                |
| Dec 2025 | 1.0.0   | React rewrite — Modern stack, radio streaming, HUD, Wake Lock, save & share features |

---

## Takeaways

**Duration**: about 3 weeks (December 2025).

**What I learned**:

- My first real experience with procedural generation — understanding how a seed and a PRNG can create coherent worlds
- The Canvas API in depth: layering, caching, anti-aliasing without WebGL
- The importance of ambiance in a contemplative project — the "non-essential" features (radio, CRT, Wake Lock) make all the difference

**What I'd do the same**:

- Start simple (just the generation) and add ambiance later — this validates the technical core before investing in polish
- Make each scene shareable via URL from the start

**What I'd change**:

- I'd improve the mobile version — right now it's not very satisfying.

</div>
