← Blurr Motion process-rive-interactive-playful
Categorie process Tier 2 Techniek #29 Deps gsap
idle
1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: process-rive-interactive-playful
// Optie A — echte Rive runtime met publieke .riv:
// <script src="https://unpkg.com/@rive-app/canvas@2.21.0"></script>
// new rive.Rive({ src: '/your-file.riv', canvas, autoplay: true, stateMachines: 'State Machine 1' });
//
// Optie B — state-machine simulatie via SVG-morph (gebruikt hier):
import gsap from 'https://esm.sh/gsap@3.12.5';
(() => {
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
  const root = document.querySelector('[data-rive-sim]');
  if (!root) return;
  const states = ['idle','wave','bounce','spin'];
  let i = 0;
  const label = root.querySelector('[data-state]');
  const eye = root.querySelectorAll('.eye');
  const mouth = root.querySelector('.mouth');
  const body = root.querySelector('.char-body');
  const apply = (name) => {
    label.textContent = name;
    gsap.killTweensOf([body, mouth, ...eye]);
    if (name === 'idle')   { gsap.to(body, { y: 0, rotate: 0, scale: 1, duration: 0.4 }); gsap.to(mouth, { scaleX: 1, scaleY: 1, duration: 0.3 }); }
    if (name === 'wave')   { gsap.to(body, { rotate: 8, y: -4, duration: 0.4, yoyo: true, repeat: -1, ease: 'sine.inOut' }); gsap.to(mouth, { scaleX: 1.4, scaleY: 0.7, duration: 0.3 }); }
    if (name === 'bounce') { gsap.to(body, { y: -28, duration: 0.35, yoyo: true, repeat: -1, ease: 'power2.out' }); gsap.to(mouth, { scaleY: 1.4, duration: 0.3 }); }
    if (name === 'spin')   { gsap.to(body, { rotate: 360, duration: 1.2, repeat: -1, ease: 'none' }); gsap.to(mouth, { scaleX: 0.6, scaleY: 0.6, duration: 0.3 }); }
  };
  apply(states[i]);
  const timer = setInterval(() => { i = (i + 1) % states.length; apply(states[i]); }, 2200);
  root.addEventListener('click', () => { clearInterval(timer); i = (i + 1) % states.length; apply(states[i]); });
})();
2. Skeleton — DOM + class-namen, mag herschikken
<!-- Skeleton: process-rive-interactive-playful -->
<div data-rive-sim class="rive-sim">
  <svg viewBox="0 0 200 200" class="rive-svg">
    <g class="char-body">
      <circle cx="100" cy="100" r="70" fill="var(--accent)" />
      <circle class="eye" cx="80" cy="90" r="8" fill="#000"/>
      <circle class="eye" cx="120" cy="90" r="8" fill="#000"/>
      <ellipse class="mouth" cx="100" cy="125" rx="20" ry="10" fill="#000"/>
    </g>
  </svg>
  <span data-state class="rive-label"></span>
</div>
3. Styling-template — verplicht eigen invulling per merk
/* Styling: process-rive-interactive-playful */
.rive-sim { position: relative; width: 100%; height: 60vh; display: grid; place-items: center; cursor: pointer; }
.rive-svg { width: clamp(200px, 30vw, 360px); height: auto; }
.char-body { transform-origin: 100px 100px; transform-box: fill-box; }
.mouth { transform-origin: center; transform-box: fill-box; }
.rive-label { position: absolute; bottom: 1.5rem; font: 600 0.85rem/1 ui-monospace, monospace; letter-spacing: 0.1em; text-transform: uppercase; padding: 0.4rem 0.75rem; border-radius: 999px; background: #000; color: #fff; }