🌌 How I Built a GROK-Inspired Starfield & Shooting Stars Using HTML Canvas ✨
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.
🌌 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 viarequestAnimationFrame.
📁 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: hiddenprevents scrollbars.position: fixedkeeps the canvas locked to the screen.pointer-events: nonelets 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 positionradius→ 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:
- The canvas dimensions are updated.
- 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:
- Clear the canvas.
- Update star positions.
- Draw stars.
- Possibly spawn a shooting star.
- 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.