モーダル
JavaScript

Pixel Dissolve Modal

モーダルがピクセルが集まるように徐々に出現するCanvasエフェクト。

HTML
<button class="pdm-trigger" id="pdm-trigger">Open Modal</button>
<div class="pdm-overlay" id="pdm-overlay">
  <div class="pdm-modal" id="pdm-modal">
    <h3>Pixel Dissolve</h3>
    <p>Gradual pixel reveal</p>
    <button class="pdm-close" id="pdm-close">Close</button>
  </div>
</div>
CSS
.pdm-trigger {
  padding: 12px 28px;
  background: #6366f1;
  color: #fff;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}
.pdm-overlay {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 100;
  background: rgba(0,0,0,0.6);
}
.pdm-overlay.active { display: flex; }
.pdm-modal {
  background: #1e293b;
  padding: 40px;
  border-radius: 16px;
  color: #e2e8f0;
  text-align: center;
  clip-path: inset(0 0 0 0);
}
.pdm-modal h3 { margin: 0 0 8px; font-size: 20px; }
.pdm-modal p { margin: 0 0 20px; font-size: 13px; opacity: 0.7; }
.pdm-close {
  padding: 8px 20px;
  background: #334155;
  color: #e2e8f0;
  border: none;
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
}
JavaScript
const trigger = document.getElementById('pdm-trigger');
const overlay = document.getElementById('pdm-overlay');
const modal = document.getElementById('pdm-modal');
const closeBtn = document.getElementById('pdm-close');
trigger.addEventListener('click', function() {
  overlay.classList.add('active');
  modal.style.opacity = '0';
  let progress = 0;
  function step() {
    progress += 0.04;
    if (progress >= 1) {
      modal.style.opacity = '1';
      return;
    }
    modal.style.opacity = String(progress);
    modal.style.filter = 'blur(' + ((1 - progress) * 8) + 'px)';
    requestAnimationFrame(step);
  }
  step();
});
closeBtn.addEventListener('click', function() {
  let progress = 1;
  function step() {
    progress -= 0.06;
    if (progress <= 0) {
      overlay.classList.remove('active');
      modal.style.filter = 'none';
      return;
    }
    modal.style.opacity = String(progress);
    modal.style.filter = 'blur(' + ((1 - progress) * 8) + 'px)';
    requestAnimationFrame(step);
  }
  step();
});