initial commit

This commit is contained in:
ultrablob 2025-04-16 19:26:35 -04:00
commit 6d6dbc8c13
8 changed files with 863 additions and 0 deletions

1
src/javascript.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path fill="#F7DF1E" d="M0 0h256v256H0V0Z"></path><path d="m67.312 213.932l19.59-11.856c3.78 6.701 7.218 12.371 15.465 12.371c7.905 0 12.89-3.092 12.89-15.12v-81.798h24.057v82.138c0 24.917-14.606 36.259-35.916 36.259c-19.245 0-30.416-9.967-36.087-21.996m85.07-2.576l19.588-11.341c5.157 8.421 11.859 14.607 23.715 14.607c9.969 0 16.325-4.984 16.325-11.858c0-8.248-6.53-11.17-17.528-15.98l-6.013-2.58c-17.357-7.387-28.87-16.667-28.87-36.257c0-18.044 13.747-31.792 35.228-31.792c15.294 0 26.292 5.328 34.196 19.247l-18.732 12.03c-4.125-7.389-8.591-10.31-15.465-10.31c-7.046 0-11.514 4.468-11.514 10.31c0 7.217 4.468 10.14 14.778 14.608l6.014 2.577c20.45 8.765 31.963 17.7 31.963 37.804c0 21.654-17.012 33.51-39.867 33.51c-22.339 0-36.774-10.654-43.819-24.574"></path></svg>

After

Width:  |  Height:  |  Size: 995 B

180
src/main.js Normal file
View file

@ -0,0 +1,180 @@
import * as p2 from 'p2-es'
const SCALE = 100;
const DENSITY = 0.0001; // Ratio of area to mass of elements
// Create a physics world, where bodies and constraints live
const world = new p2.World({
gravity: [0, -10],
broadphase: new p2.SAPBroadphase()
})
world.sleepMode = p2.World.BODY_SLEEPING
const borderMaterial = new p2.Material()
const boxMaterial = new p2.Material()
var border = new p2.ContactMaterial(borderMaterial, boxMaterial, {
friction: 0.8,
});
world.addContactMaterial(border);
// Add planes for browser window "walls"
var body = document.body,
html = document.documentElement;
var height = Math.max(body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight);
var planeBottomBody = new p2.Body({
position: [0, - (height) / SCALE],
type: p2.Body.KINEMATIC
});
planeBottomBody.addShape(new p2.Plane({ material: borderMaterial }));
world.addBody(planeBottomBody);
var planeTopBody = new p2.Body({
position: [0, 0],
type: p2.Body.KINEMATIC
});
planeTopBody.addShape(new p2.Plane({ material: borderMaterial }), [0, 0], Math.PI);
world.addBody(planeTopBody);
var planeLeftBody = new p2.Body({ type: p2.Body.KINEMATIC });
planeLeftBody.addShape(new p2.Plane({ material: borderMaterial }), [0, 0], -Math.PI / 2);
world.addBody(planeLeftBody);
var planeRightBody = new p2.Body({
position: [(document.body.getBoundingClientRect().width) / SCALE, 0],
type: p2.Body.KINEMATIC
});
planeRightBody.addShape(new p2.Plane({ material: borderMaterial }), [0, 0], Math.PI / 2);
world.addBody(planeRightBody);
let currentWindowSize = {
x: window.screenLeft,
y: window.screenTop,
w: window.innerWidth,
h: window.innerHeight
}
// To animate the bodies, we must step the world forward in time, using a fixed time step size.
// The World will run substeps and interpolate automatically for us, to get smooth animation.
const fixedTimeStep = 1 / 60 // seconds
const maxSubSteps = 10 // Max sub steps to catch up with the wall clock
const bodies = [];
let lastTime = 0
document.querySelectorAll(".box").forEach(element => {
createBody(element)
console.log("body created!")
});
function createBody(element) {
var rect = element.getBoundingClientRect();
var body = new p2.Body({
mass: rect.width * rect.height * DENSITY,
position: [
(rect.left + rect.width / 2) / SCALE,
-(rect.top + rect.height / 2) / SCALE
],
angle: 0
});
console.log(body.mass)
var shape = new p2.Box({
width: rect.width / SCALE,
height: rect.height / SCALE,
material: boxMaterial
});
body.allowSleep = true;
body.sleepSpeedLimit = 0.05;
body.sleepTimeLimit = 1;
body.addShape(shape);
world.addBody(body);
bodies.push({ physics: body, dom: element })
element.style.position = 'absolute';
element.style.top = 0;
element.style.left = 0;
element.style.transformOrigin = '50% 50%';
updateTransform(body, element);
}
function resizeWindow(event) {
const delta = {
top: window.screenTop - currentWindowSize.y,
bottom: (window.screenTop + window.innerHeight) - (currentWindowSize.y + currentWindowSize.h),
left: window.screenLeft - currentWindowSize.x,
right: (window.screenLeft + window.innerWidth) - (currentWindowSize.x + currentWindowSize.w)
}
if (Object.values(delta).some(item => item !== 0)) {
console.log(delta)
bodies.forEach(element => {
element.physics.wakeUp()
});
planeRightBody.velocity = [delta.right / SCALE, 0]
planeBottomBody.velocity = [0, -delta.bottom]
} else {
const height = window.innerHeight;
const adjustment = Math.round(-height - planeBottomBody.position[1]*SCALE)/SCALE
planeBottomBody.velocity = [0, Math.max(Math.abs(Math.sign(adjustment)), Math.abs(adjustment)) * Math.sign(adjustment)]
// console.log(-height - planeBottomBody.position[1]*SCALE)
}
currentWindowSize = {
x: window.screenLeft,
y: window.screenTop,
w: window.innerWidth,
h: window.innerHeight
}
}
world.on('postStep', resizeWindow)
function updateTransform(body, element) {
// Convert physics coordinates to pixels
var x = SCALE * (body.interpolatedPosition[0] - body.shapes[0].width / 2);
var y = -SCALE * (body.interpolatedPosition[1] + body.shapes[0].height / 2);
element.style.background = ["green", "orange", "gray"][body.sleepState]
// Set element style
var style = 'translate(' + x + 'px, ' + y + 'px) rotate(' + (-body.interpolatedAngle * 57.2957795) + 'deg)';
element.style.transform = style;
element.style.WebkitTransform = style + ' translateZ(0)'; // Force HW Acceleration
element.style.MozTransform = style;
element.style.OTransform = style;
element.style.msTransform = style;
}
// Animation loop
function animate(time) {
requestAnimationFrame(animate)
// Compute elapsed time since last render frame
const deltaTime = (time - lastTime) / 1000
// Move bodies forward in time
world.step(fixedTimeStep, deltaTime, maxSubSteps)
bodies.forEach(body => {
updateTransform(body.physics, body.dom)
});
lastTime = time
}
// Start the animation loop
requestAnimationFrame(animate)

13
src/styles.css Normal file
View file

@ -0,0 +1,13 @@
.box {
/* aspect-ratio: 1; */
background-color: white;
padding: 1vw;
text-align: center;
position: absolute;
transform-origin: 50% 50%;
}
body {
overflow: hidden;
background-color: aliceblue;
}