diff --git a/package.json b/package.json
index 8d21e3484..f825aa04c 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 4e0e74bfa..77922fc96 100644
--- a/src/client/pages/about-misskey.vue
+++ b/src/client/pages/about-misskey.vue
@@ -1,50 +1,54 @@
-
-
-
-
-
-
- {{ $t('_aboutMisskey.source') }}
- GitHub
-
-
-
- {{ $t('_aboutMisskey.translation') }}
- Crowdin
-
-
-
- {{ $t('_aboutMisskey.donate') }}
- Patreon
-
-
-
- {{ $t('_aboutMisskey.contributors') }}
- @syuilo
- @AyaMorisawa
- @mei23
- @acid-chicken
- @tamaina
- @rinsuki
- @Xeltica
- @u1-liquid
- {{ $t('_aboutMisskey.allContributors') }}
-
-
- {{ $t('_aboutMisskey.patrons') }}
- {{ patron }}
- {{ $t('_aboutMisskey.morePatrons') }}
-
-
+
+
+
+
+
+
+
+
+ {{ $t('_aboutMisskey.source') }}
+ GitHub
+
+
+
+ {{ $t('_aboutMisskey.translation') }}
+ Crowdin
+
+
+
+ {{ $t('_aboutMisskey.donate') }}
+ Patreon
+
+
+
+ {{ $t('_aboutMisskey.contributors') }}
+ @syuilo
+ @AyaMorisawa
+ @mei23
+ @acid-chicken
+ @tamaina
+ @rinsuki
+ @Xeltica
+ @u1-liquid
+ {{ $t('_aboutMisskey.allContributors') }}
+
+
+ {{ $t('_aboutMisskey.patrons') }}
+ {{ patron }}
+ {{ $t('_aboutMisskey.morePatrons') }}
+
+
+
diff --git a/src/client/scripts/physics.ts b/src/client/scripts/physics.ts
new file mode 100644
index 000000000..c7f6b44a9
--- /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 e56214ff7..691971979 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"