diff --git a/package.json b/package.json index 8d21e3484f..f825aa04ca 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "@types/koa__multer": "2.0.2", "@types/koa__router": "8.0.2", "@types/markdown-it": "10.0.3", + "@types/matter-js": "0.14.7", "@types/mocha": "7.0.2", "@types/node": "14.0.22", "@types/node-fetch": "2.5.7", @@ -175,6 +176,7 @@ "lookup-dns-cache": "2.1.0", "markdown-it": "11.0.1", "markdown-it-anchor": "6.0.1", + "matter-js": "0.14.2", "mocha": "8.2.1", "moji": "0.5.1", "ms": "2.1.2", diff --git a/src/client/pages/about-misskey.vue b/src/client/pages/about-misskey.vue index 4e0e74bfa1..77922fc966 100644 --- a/src/client/pages/about-misskey.vue +++ b/src/client/pages/about-misskey.vue @@ -1,50 +1,54 @@ diff --git a/src/client/scripts/physics.ts b/src/client/scripts/physics.ts new file mode 100644 index 0000000000..c7f6b44a9f --- /dev/null +++ b/src/client/scripts/physics.ts @@ -0,0 +1,168 @@ +import Matter from 'matter-js'; + +export function physics(container: HTMLElement) { + const containerWidth = container.offsetWidth; + const containerHeight = container.offsetHeight; + const containerCenterX = containerWidth / 2; + + // サイズ固定化(要らないかも?) + container.style.position = 'relative'; + container.style.boxSizing = 'border-box'; + container.style.width = `${containerWidth}px`; + container.style.height = `${containerHeight}px`; + + // create engine + const engine = Matter.Engine.create(); + const world = engine.world; + + // create renderer + const render = Matter.Render.create({ + engine: engine, + //element: document.getElementById('debug'), + options: { + width: containerWidth, + height: containerHeight, + background: 'transparent', // transparent to hide + wireframeBackground: 'transparent', // transparent to hide + hasBounds: false, + enabled: true, + wireframes: false, + showSleeping: true, + showDebug: false, + showBroadphase: false, + showBounds: false, + showVelocity: false, + showCollisions: false, + showAxes: false, + showPositions: false, + showAngleIndicator: false, + showIds: false, + showShadows: false + } + }); + + // Disable to hide debug + Matter.Render.run(render); + + // create runner + const runner = Matter.Runner.create(); + Matter.Runner.run(runner, engine); + + // add walls + const wallopts = { + isStatic: true, + restitution: 0.2, + friction: 1 + }; + const groundopts = { + isStatic: true, + restitution: 0.1, + friction: 2 + }; + + const groundThickness = 100; + const ground = Matter.Bodies.rectangle(containerCenterX, containerHeight + (groundThickness / 2), containerWidth, groundThickness, groundopts); + //const wallRight = Matter.Bodies.rectangle(window.innerWidth+50, window.innerHeight/2, 100, window.innerHeight, wallopts); + //const wallLeft = Matter.Bodies.rectangle(-50, window.innerHeight/2, 100, window.innerHeight, wallopts); + + Matter.World.add(world, [ + ground, + //wallRight, + //wallLeft, + ]); + + const objEls = Array.from(container.children); + const objs = []; + for (const objEl of objEls) { + let obj; + if (objEl.classList.contains('_physics_circle_')) { + obj = Matter.Bodies.circle( + objEl.offsetLeft + (objEl.offsetWidth / 2), + objEl.offsetTop + (objEl.offsetHeight / 2), + Math.max(objEl.offsetWidth, objEl.offsetHeight) / 2, + { + restitution: 0.1, + friction: 4, + frictionAir: 0, + frictionStatic: 50, + density: 100, + } + ); + } else { + const style = window.getComputedStyle(objEl); + obj = Matter.Bodies.rectangle( + objEl.offsetLeft + (objEl.offsetWidth / 2), + objEl.offsetTop + (objEl.offsetHeight / 2), + objEl.offsetWidth, + objEl.offsetHeight, + { + restitution: 0.1, + friction: 4, + frictionAir: 0, + frictionStatic: 50, + density: 100, + chamfer: { radius: parseInt(style.borderRadius, 10) }, + } + ); + } + objEl.id = obj.id; + objs.push(obj); + } + + Matter.World.add(engine.world, objs); + + // Add mouse control + + const mouse = Matter.Mouse.create(container); + const mouseConstraint = Matter.MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 1, + render: { + visible: false + } + } + }); + + Matter.World.add(engine.world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + for (const objEl of objEls) { + objEl.style.position = `absolute`; + objEl.style.top = 0; + objEl.style.left = 0; + objEl.style.margin = 0; + objEl.style.userSelect = 'none'; + objEl.style.willChange = 'transform'; + } + + window.requestAnimationFrame(update); + + let stop = false; + + function update() { + for (const objEl of objEls) { + const obj = objs.find(obj => obj.id.toString() === objEl.id.toString()); + if (obj == null) continue; + + const x = (obj.position.x - objEl.offsetWidth / 2); + const y = (obj.position.y - objEl.offsetHeight / 2); + const angle = obj.angle; + + objEl.style.transform = `translate(${x}px, ${y}px) rotate(${angle}rad)`; + } + + if (!stop) { + window.requestAnimationFrame(update); + } + } + + return { + stop: () => { + stop = true; + Matter.Runner.stop(runner); + } + }; +} diff --git a/yarn.lock b/yarn.lock index e56214ff75..6919719791 100644 --- a/yarn.lock +++ b/yarn.lock @@ -661,6 +661,11 @@ "@types/mdurl" "*" highlight.js "^9.7.0" +"@types/matter-js@0.14.7": + version "0.14.7" + resolved "https://registry.yarnpkg.com/@types/matter-js/-/matter-js-0.14.7.tgz#b816f1e7b441ee7499027f9566e4fb5baea637b3" + integrity sha512-HLUhVTUoKsibpPZ2tCzoCC/f/UYRWPP9WCOUh5F61BlrUESFV5fE7eKq/CmdoEGkNrLW9v407zYlfrTc9hnGIw== + "@types/mdurl@*": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" @@ -6116,6 +6121,11 @@ material-colors@^1.0.0: resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== +matter-js@0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/matter-js/-/matter-js-0.14.2.tgz#8169af9e06fdc356ba9e72b49624eb329839883b" + integrity sha512-3ttVT8cJlQnGRjBa8MyVrGyvGmnmOkZ3YsyemIw+KwEEdVi70mo32FH1Eta2b3GfdDJFbMDRqyMQt4heNKBUEA== + mdn-data@2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"