Projectile Motion
Launch a ball with initial velocity, apply gravity, bounce on the floor, and draw a fading trail.
Paste into main.js in the editor, then click Restart.
Complete example
javascript
if (!state.init) {
state.init = true;
state.x = 80;
state.y = h - 60;
state.vx = 200;
state.vy = -300;
state.trail = [];
}
const g = 400;
state.vy += g * dt;
state.x += state.vx * dt;
state.y += state.vy * dt;
if (state.y > h - 20) {
state.y = h - 20;
state.vy *= -0.6;
state.vx *= 0.8;
}
state.trail.push({ x: state.x, y: state.y });
if (state.trail.length > 200) state.trail.shift();
const trailLines = [];
for (let i = 1; i < state.trail.length; i++) {
trailLines.push({
x1: state.trail[i - 1].x, y1: state.trail[i - 1].y,
x2: state.trail[i].x, y2: state.trail[i].y,
color: 'rgba(139,92,246,' + (i / state.trail.length * 0.6) + ')',
width: 1.5,
});
}
return {
particles: [
{ x: state.x, y: state.y, r: 8, color: '#8B5CF6', label: 'ball' },
],
lines: [
...trailLines,
{ x1: 0, y1: h - 20, x2: w, y2: h - 20, color: 'rgba(255,255,255,0.1)', width: 1 },
],
vectors: [
{ x: state.vx * 0.2, y: state.vy * 0.2, ox: state.x, oy: state.y, color: '#22C55E', label: 'v' },
],
text: {
vx: state.vx.toFixed(0) + ' px/s',
vy: state.vy.toFixed(0) + ' px/s',
x: state.x.toFixed(0),
y: state.y.toFixed(0),
},
};What's going on
| Piece | Role |
|---|---|
vx, vy | Launch velocity (px/s). Negative vy is up on screen |
g = 400 | Downward acceleration (Y increases downward) |
| Floor bounce | Restitution 0.6, friction on vx |
| Trail | Cap at 200; alpha fades with age |
MATH
Ideal range (no bounce): ( R = v_0^2 \sin 2\theta / g ). Here units are pixels — tune g and launch speed for a readable arc.
Try next
- Click to relaunch from
state.clickX/Y - Draw the analytic parabola as a dashed
linesoverlay - Add air drag:
vx *= (1 - c * dt)