IntersectionObserver for any two elements. Proximity, collision, and time-to-collision — with real metrics.
DOM-first by default, shape-agnostic underneath. Batched RAF reads, rich metrics, TypeScript-strict.
Watch two elements. Fires near, collide, separate with distance + overlap.
const p = Collide.watch(a, b); p.on('collide', (m) => ...);
Watch a source element against many targets — drag-to-drop zones, closest-match, etc.
const g = Collide.group(drag, zones); g.on('near', (t, m) => ...);
N×N observer over a set. Every pairwise collision as it happens — avoidance, layout packing, boids.
const a = Collide.all(nodes); a.on('collide', (a,b,m)=>...);
Auto-tracks relative velocity and estimates time-to-collision in seconds.
m.velocity // {x,y} px/s m.ttc // seconds m.closingSpeed
AABB by default. Opt into circles for organic UI. Cross-shape (AABB↔circle) handled.
Collide.watch(a, b, { shape: 'circle' });
All observers share one loop. Reads batched, zero layout thrash. Stops when idle.
Collide.check(a, b); // instant Collide.shapes(sA, sB); // raw
Drop zones glow orange when the card is near (≤ 80px), turn green on collision. No polling — one RAF read per frame, regardless of zone count.
Drag the purple node. As it gets within 120px, collide.js feeds the direction vector into a simple easing loop that pulls it toward the target. Release inside the target to lock in.
The green ball drifts. Drag the pink ring anywhere. TTC is computed from the relative velocity and reported before the collision happens.
An N×N observer pushes every node away from every other when they get within 20px. Classic separation steering, driven entirely by collide.js metrics.
Every near, collide, and separate from every observer on this page streams here.
2.1KB gzipped. Zero runtime dependencies. Ships ESM, UMD, and TypeScript declarations.
npm install @techzunction/collide.js
import Collide from '@techzunction/collide.js'; // Watch two elements — fires near, collide, separate const pair = Collide.watch(cardA, cardB, { near: 80 }); pair.on('collide', (m) => console.log(m.overlap, m.ttc)); pair.on('near', (m) => console.log(m.distance)); // Drag-to-drop zones — one source vs many targets const g = Collide.group(drag, zones, { near: 60 }); g.on('near', (zone, m) => zone.classList.add('near')); g.on('collide', (zone, m) => commitDrop(zone)); // Many-to-many — crowd avoidance, packing const all = Collide.all(nodes); all.on('collide', (a, b, m) => separate(a, b, m.direction)); // One-shot — no observer, no RAF const hit = Collide.check(bullet, target).colliding;