1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: process-rive-interactive-brutalist
// 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','HOVER','ACTIVE','ERROR'];
let i = 0;
const label = root.querySelector('[data-state]');
const box = root.querySelector('.brut-box');
const dot = root.querySelector('.brut-dot');
const apply = (name) => {
label.textContent = name;
gsap.killTweensOf([box, dot]);
if (name === 'IDLE') { gsap.to(box, { rotate: 0, x: 0, scale: 1, backgroundColor: '#ffd60a', duration: 0.3 }); gsap.to(dot, { x: 0, duration: 0.3 }); }
if (name === 'HOVER') { gsap.to(box, { rotate: -3, x: -6, scale: 1.05, backgroundColor: '#ffffff', duration: 0.3 }); gsap.to(dot, { x: 30, duration: 0.4 }); }
if (name === 'ACTIVE') { gsap.to(box, { rotate: 3, x: 6, scale: 0.95, backgroundColor: '#0a84ff', duration: 0.2 }); gsap.to(dot, { x: 60, duration: 0.4 }); }
if (name === 'ERROR') { gsap.to(box, { x: '+=10', backgroundColor: '#ff2d55', duration: 0.06, yoyo: true, repeat: 5 }); gsap.to(dot, { x: 0, duration: 0.2 }); }
};
apply(states[i]);
const timer = setInterval(() => { i = (i + 1) % states.length; apply(states[i]); }, 2000);
root.addEventListener('click', () => { clearInterval(timer); i = (i + 1) % states.length; apply(states[i]); });
})(); 3. Styling-template — verplicht eigen invulling per merk
/* Styling: process-rive-interactive-brutalist */
.rive-sim { position: relative; width: 100%; height: 60vh; display: grid; place-items: center; cursor: pointer; background: #f4f4f0; border: 4px solid #000; }
.brut-box { width: clamp(160px, 22vw, 240px); height: clamp(160px, 22vw, 240px); background: #ffd60a; border: 4px solid #000; box-shadow: 8px 8px 0 #000; display: grid; place-items: center; }
.brut-dot { display: block; width: 28px; height: 28px; background: #000; border-radius: 50%; }
.rive-label { position: absolute; top: 1rem; left: 1rem; font: 700 0.85rem/1 ui-monospace, monospace; letter-spacing: 0.15em; padding: 0.5rem 0.75rem; background: #000; color: #fff; }