<div id="grin-guy" style="width:320px;aspect-ratio:1;cursor:pointer"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js"></script>
<script>
const el = document.getElementById('grin-guy');
const anim = lottie.loadAnimation({
container: el, renderer: 'svg', loop: false, autoplay: false,
path: 'https://risatrajin.com/playground/grin-guy.json'
});
const SEG = {"idle":[0,60],"hover":[80,140],"grin":[180,240],"idle>hover":[60,80],"hover>idle":[270,290],"hover>grin":[140,180],"grin>idle":[240,270]};
let stable = 'idle', moving = null, hovered = false, on = false;
const want = () => on ? 'grin' : hovered ? 'hover' : 'idle';
const next = to =>
stable === 'idle' ? 'idle>hover' :
stable === 'grin' ? 'grin>idle' :
to === 'idle' ? 'hover>idle' : 'hover>grin';
function go() {
const to = want();
if (to === stable) { moving = null; anim.playSegments(SEG[stable], true); return; }
moving = next(to); anim.playSegments(SEG[moving], true);
}
anim.addEventListener('complete', () => {
if (moving) { stable = moving.split('>')[1]; moving = null; }
go();
});
anim.addEventListener('DOMLoaded', go);
const nudge = () => { if (!moving) go(); };
el.addEventListener('pointerenter', e => { if (e.pointerType === 'mouse') { hovered = true; nudge(); } });
el.addEventListener('pointerleave', e => { if (e.pointerType === 'mouse') { hovered = false; on = false; nudge(); } });
el.addEventListener('click', () => { on = !on; nudge(); });
</script>