💡 Inspiration

Remember leaving a computer alone long enough for the screen saver to kick in? The flying toasters, the starfields, the pipes. They were the most fun thing on the machine, and you couldn't touch them without making them disappear.

I wanted to flip that. What if the screen saver wanted you to interact with it? What if moving your mouse didn't dismiss the stars but pulled them in? And since I was building it for an MLH hackathon, I wanted one moment where the whole sky came together to say hello.

⚙️ What it does

Trippy Screen Saver is a full-screen, cursor-reactive star field that runs entirely in the browser. There's no install, no login, and no backend. Open the link and you're in space.

You do The sky does
Nothing Nothing is still: the swarm drifts along a slowly shifting flow field and gently orbits the center of the screen while the stars twinkle.
Move the pointer Stars within about 220 px are pulled toward your cursor, and the pull gets stronger the closer they are. A soft glow follows the pointer.
Click anywhere Every particle flies into place to spell MLH, brightens and warms up as it arrives, holds the word for a moment, then scatters back into free drift.
Press Pause / Play The animation freezes or resumes, and a status line at the bottom tells you what the sky is doing.

It also fits the screen it's on: the number of stars scales with your viewport (roughly 900 to 2,200 swarm particles plus 280 to 900 background stars), it renders sharply on high-DPI displays, and it rebuilds itself when you resize the window.

🛠️ How we built it

The whole thing is a single TypeScript class drawing onto one <canvas> with the Canvas 2D API. There's no graphics library and no game engine. I built it in three layers.

Layer 1: The sky. Every frame starts with a deep vertical gradient, three soft radial "nebula" clouds in purple, blue, and magenta, and a faint galactic glow. On top of that sits a field of background stars, each with its own twinkle phase and a cool-blue or warm-white tint. The biggest ones get a small halo.

Layer 2: The swarm. The foreground particles are the interactive part. Each one is rendered like a real star: a radial-gradient halo, a bright white core, and cross-shaped diffraction spikes on the brightest ones. Their motion comes from a few forces added together:

  • Flow field: three layered sine/cosine waves over position and time give each point on screen a direction that shifts slowly. It's a cheap stand-in for noise that still looks organic.
  • Idle orbit: until you move the mouse, particles get a gentle tangential push around the center plus a per-particle wobble, so the page is never static.
  • Cursor attraction: within a 220 px radius, with linear falloff.
  • Damping, speed clamping, and edge wrap-around keep everything calm and on-screen.

Layer 3: The word. When you click, I render "MLH" in a heavy font onto a hidden offscreen canvas, read its pixels back with getImageData, and sample a grid of points wherever the text is opaque. Each particle gets one of those points as a target. A small state machine (free → forming (0.9 s) → holding (1.4 s) → releasing (1.1 s) → free) controls how strongly particles ease toward their targets, so the word assembles, holds, and dissolves instead of just popping in and out.

The shell. Vite handles the dev server and build, Tailwind CSS v4 (through @tailwindcss/vite) styles the overlay (title, hint text, and a frosted-glass Pause button), and the site is deployed on Vercel.

🧗 Challenges we ran into

  • Making a word out of particles look like a word. If the sample grid is too coarse, "MLH" turns into confetti. If it's too fine, there aren't enough particles to fill it. I scaled the font size and sampling step to the viewport and assigned particles to target points round-robin, so the letters stay filled on both small and large screens.
  • Forces fighting each other. Cursor attraction and word formation both want to control the same particles. Without a rule, moving the mouse while the word formed would tear the letters apart. I turn off cursor pull while the word is almost fully formed, and switch the particles from free physics to easing toward their targets during the word phases.
  • Letting go gracefully. Releasing particles from the word at full velocity looked like an explosion, and releasing them at zero looked frozen. The fix was to soften velocities when the hold ends, ease out over the release phase, and then give every particle a small random kick back into the drift.
  • Frame hitches. Switching tabs and coming back produces a huge time delta, which made stars teleport. Capping the per-frame time step keeps motion smooth and consistent across frame rates.
  • Sharp vs. fast. Rendering at full device pixel ratio makes Retina screens look crisp but multiplies the pixel count. I cap it at 2× and scale particle counts to the viewport area.

🏆 Accomplishments that we're proud of

  • Thousands of individually lit, twinkling stars with halos and diffraction spikes, drawn in plain Canvas 2D with zero runtime dependencies.
  • A click-to-spell effect that reads clearly and moves in a way that feels physical, not scripted.
  • The page is alive the moment it loads. Idle drift means there's always something to look at, even before you touch anything.
  • Small accessibility details: the Pause button uses aria-pressed and has a visible focus ring, the canvas has an ARIA label, and a live hint line explains what's happening.

📚 What we learned

  • A convincing "noise" field doesn't need a noise library. A few overlapping sine waves go a long way.
  • Offscreen canvases plus getImageData are a simple, powerful way to turn any text or shape into particle targets.
  • Most of what makes an animation feel good happens in the transitions: easing, damping, and deciding which force wins when.
  • Vite, TypeScript, and Tailwind v4 make a tiny, fast static site with almost no configuration.

🚀 What's next for Trippy Screen Saver

  • Custom words: let visitors type their own message (a name, a team, a hackathon) for the swarm to spell.
  • More shapes: logos and icons, using the same offscreen-sampling trick.
  • Touch-first polish: tuning the controls and particle counts for phones and tablets.
  • Real screen saver mode: a fullscreen toggle and an auto-cycle that spells a new word every so often, so it can run on a lobby display at an event.

Built With

Share this project:

Updates