"elastic"
ELASTICA
Physics engine for elastic collisions
A JavaScript library providing a physics engine for simulating elastic collision using Aligned Axis Bounding Boxes (AABBs) and grid hash for efficient collision detection.
bun add @darkroom.engineering/elasticaHow It Works
Elastica simulates elastic collisions using Aligned Axis Bounding Boxes (AABBs) and a spatial hash grid for efficient broad-phase collision detection.
Features
Elastic Collisions
Realistic elastic collision response with configurable restitution and friction.
AABB Detection
Fast Aligned Axis Bounding Box collision detection for rectangular bodies.
Grid Hash
Spatial partitioning with grid hash for efficient broad-phase collision detection.
React Integration
Built-in React hooks powered by Hamo for seamless integration.
Lightweight
Small bundle size with zero dependencies except Hamo.
DVD Screensaver
Perfect for creating nostalgic DVD logo bouncing animations.
Quick Start
Vanilla JavaScript
import { Elastica, Body } from '@darkroom.engineering/elastica'
// Create the physics engine
const elastica = new Elastica({
width: window.innerWidth,
height: window.innerHeight,
})
// Add bodies
const body = new Body({
x: 100,
y: 100,
width: 50,
height: 50,
velocityX: 2,
velocityY: 3,
})
elastica.addBody(body)
// Update loop
function animate() {
elastica.update()
// body.x and body.y are now updated
console.log(body.x, body.y)
requestAnimationFrame(animate)
}
animate()React
'use client'
import { useElastica, useBody } from '@darkroom.engineering/elastica/react'
import { useRef } from 'react'
export function BouncingBox() {
const ref = useRef<HTMLDivElement>(null)
// Initialize the physics engine
useElastica({
width: window.innerWidth,
height: window.innerHeight,
})
// Create a body that syncs with the DOM element
useBody(ref, {
velocityX: 2,
velocityY: 3,
})
return (
<div
ref={ref}
style={{
width: 50,
height: 50,
background: 'red',
position: 'absolute',
}}
/>
)
}Configuration
Elastica Options
| Property | Type | Default | Description |
|---|---|---|---|
width | number | — | Width of the simulation area |
height | number | — | Height of the simulation area |
cellSize | number | 100 | Size of grid cells for spatial hashing |
restitution | number | 1 | Bounciness (0-1, 1 = perfectly elastic) |
friction | number | 0 | Friction coefficient (0-1) |
Body Options
| Property | Type | Default | Description |
|---|---|---|---|
x | number | 0 | Initial X position |
y | number | 0 | Initial Y position |
width | number | — | Width of the body |
height | number | — | Height of the body |
velocityX | number | 0 | Initial X velocity |
velocityY | number | 0 | Initial Y velocity |
mass | number | 1 | Mass of the body |
static | boolean | false | If true, body does not move |
Methods
| Property | Type | Default | Description |
|---|---|---|---|
addBody(body) | (body: Body) => void | — | Add a body to the simulation |
removeBody(body) | (body: Body) => void | — | Remove a body from the simulation |
update() | () => void | — | Step the simulation forward |
resize(width, height) | (w, h) => void | — | Resize the simulation bounds |
clear() | () => void | — | Remove all bodies |
Common Patterns
DVD Screensaver Effect
import { Elastica, Body } from '@darkroom.engineering/elastica'
const elastica = new Elastica({
width: window.innerWidth,
height: window.innerHeight,
restitution: 1, // Perfect bounce
friction: 0, // No energy loss
})
const logo = new Body({
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
width: 100,
height: 50,
velocityX: 3,
velocityY: 2,
})
elastica.addBody(logo)
// The logo will bounce forever like the classic DVD screensaverMultiple Colliding Bodies
const elastica = new Elastica({
width: 800,
height: 600,
restitution: 0.8, // Slight energy loss
})
// Create multiple bodies that will collide with each other
for (let i = 0; i < 10; i++) {
elastica.addBody(new Body({
x: Math.random() * 700,
y: Math.random() * 500,
width: 40,
height: 40,
velocityX: (Math.random() - 0.5) * 10,
velocityY: (Math.random() - 0.5) * 10,
}))
}