How we built the sky behind Surf
The live sky behind every chat follows the real sun, moon and, if you allow it, your weather. Here is how we approached it, what went well, and what to watch for if you build your own.
The first thing people notice in Surf is the sky. It is not a photo or a looping video. It is drawn live in your browser, it follows the time of day where you are, and it quietly changes when Surf is busy. This post covers how we approached it, without the exact recipe, so you can borrow the ideas for your own product.
What we wanted
- A background that feels alive but calm, never competing with the conversation in front of it.
- A sky that is true to the moment: morning looks like morning, the moon is where it should be.
- A small sign of activity, so you can feel Surf working without another spinner.
- Something cheap enough to run all day on an ordinary laptop or phone.
How it works, in broad strokes
A palette first, a renderer second
We started with design, not graphics. Each part of the day (morning, afternoon, evening, night) has a hand-picked set of colors in our design system. The live sky blends between them based on how high the sun actually is, so the colors stay on brand while the timing follows nature. The same palette doubles as a plain CSS gradient that shows instantly while the live sky loads, or permanently on devices that cannot draw it.
Real sun and moon
Sun and moon positions come from well-known published astronomy approximations, the same kind used by sunrise calculators. They are accurate enough to put the sunset glow and the moon in believable places, including the moon’s phase, with very little math per frame.
Clouds from noise
The clouds, haze and light rays are generated on the GPU from layered noise, a classic technique for natural-looking texture. A handful of dials (cover, softness, drift, glow) shape the look, and a small amount of variation is seeded by the date and place, so each day’s sky is a little different but stays the same if you reload.
Optional weather
If you turn on the weather card, the sky can reflect it: overcast, fog, rain or snow. We only use a rough area, rounded to roughly ten kilometres, read the forecast from a public source, and refresh it every half hour only while you are looking at the page. With the card off, the sky simply follows the clock.
A hint of activity
When Surf is working on a task, the clouds drift a little faster. The speed eases in and out over a couple of seconds, so it reads as a mood change rather than a glitch.
Seasons on top
Seasonal scenes, like our Halloween evenings, are a lightweight layer of simple vector shapes and CSS animation over the normal sky, switched on with a feature flag. No extra artwork to download and no second renderer.
What we needed
- A WebGL canvas and one fragment shader. No 3D engine or graphics library.
- A design palette with clear stops for each part of the day.
- Sun and moon approximations and a reliable way to handle time zones.
- A performance budget: a capped resolution, a capped frame rate, and a full stop when the tab is hidden.
- A plan for failure: a CSS fallback, recovery when the browser drops the graphics context, and a still sky for people who prefer reduced motion.
What went well
- Starting from the palette. Because colors come from our design system, the sky never drifts off brand, and text can pick a readable color from the same data without reading pixels back from the GPU.
- Rendering smaller than the screen. Clouds are soft, so drawing at a reduced resolution and letting the browser scale it up costs almost nothing in quality and saves a lot of power.
- Dissolves instead of jumps. When the weather or place changes, the old sky fades into the new one, so updates never feel jarring.
- Layers, not rewrites. Weather, activity and seasons each sit on top of the same base, which kept every addition small.
What to watch out for
- Battery and heat. A full-screen shader running at 60 frames per second is expensive. Cap the frame rate, cap the pixels, and pause when nobody is looking.
- Lost graphics contexts. Browsers can take the GPU away at any time, especially on phones. Listen for it, show the fallback, and rebuild cleanly.
- Readability. A beautiful sky can wreck contrast. Decide text color from the sky, and keep the busiest detail away from where people read.
- Motion sensitivity. Respect the reduced-motion setting from day one, not as a patch later.
- Time is hard. Time zones, daylight saving and the hours around midnight hide bugs. Test sunrise and sunset in several places.
- Privacy. Anything location-based should be opt-in, coarse, and never stored longer than it needs to be.
- Testing. Animated backgrounds make screenshot tests flaky. Give your tests a way to freeze the scene.
Make it your own
You do not need our shader to get something similar. Start with a CSS gradient that changes with the hour. Add one layer of slow noise for clouds. Then tie one visual detail to something meaningful in your product, the way our clouds speed up while Surf works. Keep the palette yours, and the sky will feel like your product instead of a copy of ours.
The best background is one people feel before they notice it.
Questions or ideas? Write to help@lilac.codes. We read everything.
Give it a try
Meet your Bud and hand it a first task. It takes a few minutes to set up.
Open HeySurf