Matter.js Ball Pit Hero Section — Free Interactive Physics Hero

Matter.js Ball Pit Hero Section · Animations · Plain HTML, CSS & JS · Live preview

CategoryAnimations

What's included

Features

Cursor collider
Static body with synced velocity.
Tap to pop
Query.point plus ring animation.
Area-based fill
Right ball count for any size.
Responsive rebuild
ResizeObserver, no squashed circles.
Readable overlay
pointer-events and text backdrops.
Pauses off-screen
IntersectionObserver toggles the runner.
Reduced motion
Starts settled, no rain-in.
Shake and gravity flip
Fun CTA-driven interactions.

About this UI Snippet

An Interactive Physics Hero with Matter.js — Cursor Pushing, Popping, Resizing and Performance

Screenshot of the Matter.js Ball Pit Hero Section snippet rendered live

Physics ball-pit heroes are a popular way to make a landing page feel playful. The hard parts aren't the physics — they're making it responsive, readable and cheap to run. This snippet handles all three.

Pushing balls with the cursor

The pointer is represented by an invisible static circle. Each frame it's moved to the pointer with Body.setPosition(cursor, pointer, true) — the third argument, updateVelocity, gives it a velocity equal to how far it moved. Without it balls are just shoved out of the way; with it, a fast flick sends them flying while a slow drift nudges them gently. Big jumps (the pointer entering or leaving) skip the velocity so balls aren't blasted.

Tap to pop

Query.point(balls, point) finds the ball under the tap. It's removed, a fading ring is drawn where it was, and a new ball drops back in a moment later from whichever edge gravity pulls from.

Filling any size

The number of balls is computed from the hero's area (about 45% coverage), with smaller balls on narrow screens, so it looks full on a phone and a wide monitor alike.

Resizing without squashing

Scaling a canvas with CSS stretches circles into ovals. Instead, a ResizeObserver (debounced) recreates the renderer at the new size, rebuilds the four walls and nudges any ball that ended up outside back in. Walls are extra-thick so fast balls can't tunnel through them.

Readable content on top

The headline and copy sit above the canvas with pointer-events: none so the cursor reaches the balls, while the CTA buttons re-enable pointer events. Text gets a strong shadow and a translucent backdrop so it stays legible over any colour.

Performance and accessibility

An IntersectionObserver sets runner.enabled = false when the hero leaves the viewport, so it costs nothing while you read the rest of the page. With prefers-reduced-motion, balls start settled at the bottom instead of raining in.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet into an AI assistant like Claude and ask it to explain the cursor collider and the resize strategy. Ask it to use your logo or emoji as ball sprites, tilt gravity with the phone's accelerometer, spell a word with letter-shaped bodies, or add sounds on collisions. It can also help port it into a React component with proper cleanup.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a landing page hero filled with Matter.js 0.20 (from a CDN) physics balls in plain HTML, CSS and JavaScript.

Requirements:
- A full-bleed dark hero with a kicker badge, big gradient headline, short copy and two CTA buttons layered above the canvas; the content uses pointer-events: none except the buttons, and has text shadows and translucent backdrops for readability.
- Colourful balls with a white highlight fill about 45% of the hero area (smaller balls on narrow screens) and rain in from above.
- An invisible static cursor circle that follows the pointer, with velocity set to its movement so it pushes balls realistically.
- Tapping a ball pops it with a fading ring (Query.point) and a new ball drops in shortly after.
- "Shake it up" launches all balls; "Flip gravity" inverts gravity.
- On resize (debounced ResizeObserver) recreate the renderer at the new size and rebuild thick walls, keeping balls inside; pause the runner with IntersectionObserver when off-screen; with prefers-reduced-motion start the balls settled.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

Requires
<section class="bp" id="bpHero">
  <div class="bp-copy">
    <span class="bp-kicker">New · v3.0 is here</span>
    <h1>Design tools that<br><em>bounce back</em></h1>
    <p>Move your cursor through the pit. Tap a ball to pop it, and it'll drop right back in.</p>
    <div class="bp-cta">
      <a href="#" class="bp-btn" id="bpShake">Shake it up</a>
      <a href="#" class="bp-btn ghost" id="bpGravity">Flip gravity</a>
    </div>
  </div>
</section>

Step by step

How to Use

  1. 1
    Move through the pitYour cursor pushes the balls around.
  2. 2
    Pop a ballTap or click one; a new one drops in.
  3. 3
    Shake it upLaunch every ball into the air.
  4. 4
    Flip gravitySend the pile to the ceiling and back.
  5. 5
    Resize the windowThe pit rebuilds at the new size.

Real-world uses

Common Use Cases

SaaS landing pages
A memorable, playful first impression.
Product launches
Celebrate a release with motion.
Portfolio intros
Show personality on the first screen.
Event pages
Balls in brand or event colours.
404 pages
Something fun to play with while lost.
Related: Matter.js Physics Playground
Spawn and drag shapes: Matter.js Physics Playground.
Related: Matter.js Soft-Body Jelly
Squishy instead of bouncy: Matter.js Soft-Body Jelly Blobs.

Got questions?

Frequently Asked Questions

Add an invisible static circle, and every frame move it with Body.setPosition(body, pointer, true); the updateVelocity flag sets its velocity to how far it moved, which makes collisions transfer the right amount of energy.

Don't stretch it with CSS. On resize (debounced with ResizeObserver), create a renderer at the new size, rebuild the walls, and move any bodies left outside back into bounds.

Yes. Position the content above the canvas with pointer-events: none so the cursor reaches the canvas, then set pointer-events: auto on buttons and links.

Use an IntersectionObserver on the hero and set runner.enabled to false when it leaves the viewport and true when it returns.

Matter.Query.point(bodies, {x, y}) returns the bodies containing that point.