🌌 How I Built a GROK-Inspired Starfield & Shooting Stars Using HTML Canvas ✨

Published: (December 13, 2025 at 03:35 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Recreating the GROK Starfield & Shooting Star Effect with HTML Canvas

If you’ve seen the GROK‑style starfield animation, you know the vibe: slow, cinematic rotation, subtle flicker, and the occasional shooting star streaking across space. This post breaks down a pure HTML + CSS + JavaScript implementation that recreates that effect — no libraries, no frameworks, just the Canvas API.

GitHub ⭐Live Demo 🚀


🌌 What This Effect Includes

  • Full‑screen HTML5 <canvas>
  • Hundreds of rotating stars orbiting off‑screen
  • Natural flicker / glow simulation
  • Rare, elegant shooting stars
  • Responsive resize handling
    All running smoothly via requestAnimationFrame.

📁 Project Structure

index.html   → Canvas container
style.css    → Fullscreen black background
script.js    → Animation logic & customization

No build step required — just open index.html in a browser.

🧱 HTML: Minimal Canvas Setup

The canvas fills the entire viewport and acts as the rendering surface for everything we draw. The JavaScript file is loaded at the bottom to ensure the DOM is ready before accessing the canvas.

🎨 CSS: Fullscreen, No Distractions

html, body {
  margin: 0;
  padding: 0;
  background: black;
  overflow: hidden;
  width: 100%;
  height: 100%;
}

#starfield {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
  • overflow: hidden prevents scrollbars.
  • position: fixed keeps the canvas locked to the screen.
  • pointer-events: none lets UI elements sit above it.

🧠 JavaScript: Core Concepts

Canvas & Context

const canvas = document.getElementById("starfield");
const ctx = canvas.getContext("2d");

Everything is drawn manually using the 2D rendering context.

⭐ Star Data Model

Each star is stored as an object:

{
  angle: Number,
  radius: Number,
  speed: Number,
  size: Number
}

Stars are defined using polar coordinates:

  • angle → rotation position
  • radius → distance from the center

This makes circular motion trivial.

🌍 Canvas Resize Handling

function resizeCanvas() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  initStars();
}

Whenever the window resizes:

  1. The canvas dimensions are updated.
  2. Stars are regenerated to fit the new size, keeping everything sharp and responsive.

✨ Initializing the Starfield

const numStars = 360;

Stars are created like this:

stars = Array.from({ length: numStars }, () => ({
  angle: Math.random() * Math.PI * 2,
  radius: Math.random() * Math.sqrt(canvas.width ** 2 + canvas.height ** 2),
  speed: Math.random() * 0.0003 + 0.00015,
  size: Math.random() * 1.2 + 0.5,
}));
  • Random angles distribute stars evenly.
  • Large radii let stars orbit beyond the viewport.
  • Tiny angular speeds create slow, cinematic motion.

🔄 The Animation Loop

function animate() {
  requestAnimationFrame(animate);
  // clear, update, draw, spawn shooting stars, etc.
}
requestAnimationFrame(animate);

Each frame:

  1. Clear the canvas.
  2. Update star positions.
  3. Draw stars.
  4. Possibly spawn a shooting star.
  5. Update shooting stars.

🌟 Drawing Rotating Stars

star.angle += star.speed;

const x = centerX + star.radius * Math.cos(star.angle);
const y = centerY + star.radius * Math.sin(star.angle);

Classic circular‑motion math.

Flicker / Glow Effect

const flicker = 0.4 + Math.abs(Math.sin(Date.now() * 0.0015 + i)) * 0.5;

Brightness is faked by:

  • Oscillating opacity.
  • Slight per‑star phase offset.

Simple, fast, and effective.

☄️ Shooting Stars

Shooting stars are rare by design:

if (shootingStars.length === 0 && Math.random() < 0.01) {
  // create a new shooting star
}

Only one can exist at a time, keeping the moment special. Each shooting star has position, velocity, and lifespan.

🎯 Shooting Star Trail

The trail uses a linear gradient:

const grad = ctx.createLinearGradient(
  s.x,
  s.y,
  s.x - s.vx * 35,
  s.y - s.vy * 35
);

Opacity fades toward the tail, creating a natural streak effect without particles.

⚙️ Easy Customization

All tuning lives in script.js.

Density

const numStars = 360;

Flicker Strength

// base brightness
0.4
// flicker amplitude
0.5

Shooting Star Frequency

Math.random() < 0.01

Speed (shooting star)

vx: 3 + Math.random() * 2,
vy: 1 + Math.random() * 1.5

💡 Ideas for Extensions

  • Mouse‑based parallax.
  • Color‑shifted stars.
  • Depth layers with different speeds.
  • Gradient space backgrounds.
  • Nebula noise overlays.

🧪 Why This Approach Works

  • Zero dependencies – pure JavaScript and Canvas.
  • Extremely fast – simple math + canvas rendering.
  • Easy to embed anywhere (landing pages, backgrounds, demos).
  • Great for ambient UI backgrounds – demonstrates how far plain JS + Canvas can go when used thoughtfully.
Back to Blog

Related posts

Read more »