Created
June 6, 2025 23:48
-
-
Save shimarin/6a17578ae950698f7f13f347b8f6dbd1 to your computer and use it in GitHub Desktop.
ティウンティウン
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Tiuntiun</title> | |
</head> | |
<body> | |
<rockman-explosion style="--particle-color: blue;" count="30"> | |
<img src="rockman.png" width="300" height="300" alt="Rockman"> | |
</rockman-explosion> | |
<script type="module" src="tiuntiun.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { LitElement, html, css } from 'https://unpkg.com/lit?module'; | |
export class RockmanExplosion extends LitElement { | |
static properties = { | |
count: { type: Number }, | |
}; | |
static styles = css` | |
:host { | |
position: relative; | |
cursor: pointer; | |
/* スロット内の要素を中央に収める */ | |
display: inline-flex; | |
align-items: center; | |
justify-content: center; | |
} | |
:host(.exploding) ::slotted(*) { | |
visibility: hidden; | |
} | |
.particle { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
/* 粒子サイズは --particle-size で制御 */ | |
width: var(--particle-size, 4px); | |
height: var(--particle-size, 4px); | |
background: var(--particle-color, #48c); | |
border-radius: 50%; | |
animation: explode 600ms ease-out forwards; | |
} | |
@keyframes explode { | |
to { | |
transform: translate(var(--dx), var(--dy)) scale(0); | |
opacity: 0; | |
} | |
} | |
`; | |
constructor() { | |
super(); | |
this.count = 20; | |
} | |
render() { | |
return html`<slot></slot>`; | |
} | |
firstUpdated() { | |
this.addEventListener('click', () => this._explode()); | |
} | |
_explode() { | |
this.classList.add('exploding'); | |
this._playSound(); | |
// 要素サイズ取得・最小辺を基準に | |
const { width, height } = this.getBoundingClientRect(); | |
const minSide = Math.min(width, height); | |
// 半径は最小辺の 0.4~0.8 倍の範囲でランダム | |
const baseRadius = minSide * 0.6; | |
// 粒子サイズは最小辺の 5% ~ 10% | |
const particleSize = Math.max(2, minSide * 0.06); | |
// CSS 変数として粒子サイズをセット | |
this.style.setProperty('--particle-size', `${particleSize}px`); | |
for (let i = 0; i < this.count; i++) { | |
const p = document.createElement('div'); | |
p.classList.add('particle'); | |
// ランダム方向と距離 | |
const angle = Math.random() * Math.PI * 2; | |
const distance = baseRadius * (0.6 + Math.random() * 0.4); | |
p.style.setProperty('--dx', `${Math.cos(angle) * distance}px`); | |
p.style.setProperty('--dy', `${Math.sin(angle) * distance}px`); | |
this.shadowRoot.appendChild(p); | |
p.addEventListener('animationend', () => p.remove()); | |
} | |
} | |
_playSound() { | |
const ctx = new AudioContext(); | |
const osc = ctx.createOscillator(); | |
osc.type = 'square'; | |
osc.frequency.setValueAtTime(880, ctx.currentTime); | |
osc.frequency.exponentialRampToValueAtTime(440, ctx.currentTime + 0.15); | |
osc.connect(ctx.destination); | |
osc.start(); | |
osc.stop(ctx.currentTime + 0.2); | |
} | |
} | |
customElements.define('rockman-explosion', RockmanExplosion); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment