㊙️
This commit is contained in:
		
							parent
							
								
									2112fb3896
								
							
						
					
					
						commit
						9a270e59a4
					
				
					 4 changed files with 266 additions and 46 deletions
				
			
		|  | @ -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", | ||||
|  |  | |||
|  | @ -1,13 +1,16 @@ | |||
| <template> | ||||
| <div style="overflow: hidden;"> | ||||
| 	<FormBase class="znqjceqz"> | ||||
| 		<div id="debug"></div> | ||||
| 		<section class="_formItem"> | ||||
| 		<div class="_formPanel" style="text-align: center; padding: 16px;"> | ||||
| 			<img src="/assets/icons/512.png" alt="" style="display: block; width: 100px; margin: 0 auto; border-radius: 16px;" ref="icon"/> | ||||
| 			<div style="margin-top: 0.75em;">Misskey</div> | ||||
| 			<div style="opacity: 0.5;">v{{ version }}</div> | ||||
| 			<div class="_formPanel" style="text-align: center; padding: 16px;" ref="about"> | ||||
| 				<img src="/assets/icons/512.png" alt="" style="display: block; width: 100px; margin: 0 auto; border-radius: 16px;" ref="icon" @load="iconLoaded" draggable="false"/> | ||||
| 				<div style="margin: 0.75em auto 0 auto; width: max-content;">Misskey</div> | ||||
| 				<div style="margin: 0 auto; opacity: 0.5; width: max-content;">v{{ version }}</div> | ||||
| 				<span v-for="emoji in easterEggEmojis" :key="emoji.emoji" class="_physics_circle_" :style="{ position: 'absolute', top: emoji.top, left: emoji.left, userSelect: 'none' }"><MkEmoji style="pointer-events: none; font-size: 24px; width: 24px;" :emoji="emoji.emoji" :custom-emojis="$store.state.instance.meta.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span> | ||||
| 			</div> | ||||
| 		</section> | ||||
| 	<section class="_formItem" style="text-align: center; padding: 0 16px;"> | ||||
| 		<section class="_formItem" style="text-align: center; padding: 0 16px;" @click="gravity"> | ||||
| 			{{ $t('_aboutMisskey.about') }} | ||||
| 		</section> | ||||
| 		<FormGroup> | ||||
|  | @ -45,6 +48,7 @@ | |||
| 			<template #caption>{{ $t('_aboutMisskey.morePatrons') }}</template> | ||||
| 		</FormGroup> | ||||
| 	</FormBase> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
|  | @ -57,6 +61,7 @@ import FormBase from '@/components/form/base.vue'; | |||
| import FormGroup from '@/components/form/group.vue'; | ||||
| import FormKeyValueView from '@/components/form/key-value-view.vue'; | ||||
| import MkLink from '@/components/link.vue'; | ||||
| import { physics } from '@/scripts/physics.ts'; | ||||
| import * as os from '@/os'; | ||||
| 
 | ||||
| const patrons = [ | ||||
|  | @ -115,10 +120,24 @@ export default defineComponent({ | |||
| 			}, | ||||
| 			version, | ||||
| 			patrons, | ||||
| 			easterEggReady: false, | ||||
| 			easterEggEmojis: [], | ||||
| 			easterEggEngine: null, | ||||
| 			faInfoCircle, faCode, faLanguage, faHandHoldingMedical, | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	created() { | ||||
| 		const emojis = this.$store.state.settings.reactions; | ||||
| 		for (let i = 0; i < 32; i++) { | ||||
| 			this.easterEggEmojis.push({ | ||||
| 				top: -(32 + (Math.random() * 256)) + 'px', | ||||
| 				left: (Math.random() * 99) + '%', | ||||
| 				emoji: emojis[Math.floor(Math.random() * emojis.length)], | ||||
| 			}); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	mounted() { | ||||
| 		VanillaTilt.init(this.$refs.icon, { | ||||
| 			max: 30, | ||||
|  | @ -127,6 +146,27 @@ export default defineComponent({ | |||
| 			speed: 1000, | ||||
| 		}); | ||||
| 	}, | ||||
| 
 | ||||
| 	beforeUnmount() { | ||||
| 		if (this.easterEggEngine) { | ||||
| 			this.easterEggEngine.stop(); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	methods: { | ||||
| 		iconLoaded() { | ||||
| 			this.$nextTick(() => { | ||||
| 				this.easterEggReady = true; | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		gravity() { | ||||
| 			if (!this.easterEggReady) return; | ||||
| 			this.easterEggReady = false; | ||||
| 			this.$refs.icon.vanillaTilt.destroy(); | ||||
| 			this.easterEggEngine = physics(this.$refs.about); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										168
									
								
								src/client/scripts/physics.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/client/scripts/physics.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
							
								
								
									
										10
									
								
								yarn.lock
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								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" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue