<!DOCTYPE html>
<html lang="en" data-theme="aurora">
<head>
<meta charset="utf-8"><title>Animation + FX Showcase — html-ppt</title>
<link rel="stylesheet" href="../assets/fonts.css">
<link rel="stylesheet" href="../assets/base.css">
<link rel="stylesheet" id="theme-link" href="../assets/themes/aurora.css">
<link rel="stylesheet" href="../assets/animations/animations.css">
<style>
  .fx-stage{
    position:relative;
    margin:20px auto 0;
    width:min(900px, 92%);
    height:380px;
    border-radius:var(--radius-lg, 16px);
    background:rgba(10,12,22,0.55);
    border:1px solid var(--border,#2a2a3a);
    box-shadow:var(--shadow-lg, 0 20px 60px rgba(0,0,0,.4));
    overflow:hidden;
  }
  .fx-label{
    position:absolute;top:14px;left:16px;z-index:5;
    font-family:var(--font-mono, ui-monospace,Menlo,monospace);
    font-size:11px;letter-spacing:.14em;color:var(--text-3,#a0a0b8);
    text-transform:uppercase;
    background:rgba(0,0,0,0.35);padding:4px 10px;border-radius:999px;
    border:1px solid rgba(255,255,255,0.08);
  }
  .fx-replay{
    position:absolute;top:12px;right:14px;z-index:5;
    appearance:none;cursor:pointer;
    padding:7px 14px;border-radius:999px;
    background:linear-gradient(135deg, var(--accent,#7c5cff), var(--accent-2,#22d3ee));
    color:#fff;font:600 12px system-ui,sans-serif;
    border:0;letter-spacing:.05em;
    box-shadow:0 4px 16px rgba(124,92,255,0.35);
  }
  .fx-replay:hover{ filter:brightness(1.1); transform:translateY(-1px); }
  .fx-indicator{position:absolute;top:24px;right:40px;font-family:var(--font-mono);font-size:11px;color:var(--text-3);letter-spacing:.1em}
  .anim-box{margin:24px auto 0;width:640px;height:240px;border-radius:var(--radius-lg);background:var(--grad-soft);display:flex;align-items:center;justify-content:center;font-size:44px;font-weight:800;color:var(--text-1);box-shadow:var(--shadow-lg);border:1px solid var(--border)}
</style>
</head>
<body>
<div class="deck"></div>

<script>
const FX = [
  ['particle-burst',    'Particles explode from center, gravity + fade, re-bursts every ~2.5s.'],
  ['confetti-cannon',   'Colored rotating rects arcing from both bottom corners.'],
  ['firework',          'Rockets launch from the bottom and burst into colored sparks.'],
  ['starfield',         '3D perspective starfield — infinite flythrough.'],
  ['matrix-rain',       'Classic green katakana + hex columns raining down.'],
  ['knowledge-graph',   'Force-directed graph, 28 labeled nodes, live physics + springs.'],
  ['neural-net',        '4-6-6-3 feedforward net with pulses traveling along edges.'],
  ['constellation',     'Drifting points connect when close — ambient background.'],
  ['orbit-ring',        '5 concentric rings with dots rotating at different speeds.'],
  ['galaxy-swirl',      'Logarithmic spiral with ~800 particles.'],
  ['word-cascade',      'Words fall from top and pile up at the bottom.'],
  ['letter-explode',    'Letters fly in from random directions, loops.'],
  ['chain-react',       'Row of 8 circles — a wave pulse dominoes across them.'],
  ['magnetic-field',    'Particles follow sine curves leaving gradient trails.'],
  ['data-stream',       'Rows of scrolling hex/binary text, cyberpunk feel.'],
  ['gradient-blob',     '4 drifting blurred radial gradients (additive blending).'],
  ['sparkle-trail',     'Sparkles emit at your cursor (auto-wiggles if idle).'],
  ['shockwave',         'Expanding rings emanating from center, looping.'],
  ['typewriter-multi',  'Three lines typing concurrently with blinking block cursors.'],
  ['counter-explosion', 'Number counts 0 → 2400, bursts particles, resets.']
];

const CSS_ANIMS = [
  ['fade-up','Translate from +32 px, fade.'],
  ['fade-down','Translate from -32 px, fade.'],
  ['fade-left','From left.'],
  ['fade-right','From right.'],
  ['rise-in','Rise + blur-off.'],
  ['drop-in','Drop from above.'],
  ['zoom-pop','Elastic scale pop.'],
  ['blur-in','Blur clears.'],
  ['glitch-in','Glitch jitter.'],
  ['typewriter','Typewriter reveal.'],
  ['neon-glow','Neon pulse.'],
  ['shimmer-sweep','Sheen sweep.'],
  ['gradient-flow','Gradient flow.'],
  ['stagger-list','Staggered children.'],
  ['counter-up','Number tick.'],
  ['path-draw','SVG strokes draw.'],
  ['parallax-tilt','3D hover tilt.'],
  ['card-flip-3d','Y-axis flip.'],
  ['cube-rotate-3d','Cube rotate.'],
  ['page-turn-3d','Page turn.'],
  ['perspective-zoom','Pull from -400 Z.'],
  ['marquee-scroll','Infinite marquee.'],
  ['kenburns','Ken Burns zoom.'],
  ['confetti-burst','Pseudo confetti.'],
  ['spotlight','Circular clip reveal.'],
  ['morph-shape','SVG d morph.'],
  ['ripple-reveal','Corner ripple.']
];

const deck = document.querySelector('.deck');
const total = FX.length + CSS_ANIMS.length;

// Build FX slides (1..20)
FX.forEach((f, i) => {
  const idx = i + 1;
  const [name, desc] = f;
  const sec = document.createElement('section');
  sec.className = 'slide';
  sec.setAttribute('data-title', 'fx / ' + name);

  const extraAttrs = name === 'letter-explode'
      ? 'data-fx-text-value="' + name.toUpperCase() + '"'
    : name === 'counter-explosion'
      ? 'data-fx-to="2400"'
    : name === 'typewriter-multi'
      ? 'data-fx-line1="> initializing knowledge graph..." data-fx-line2="> loading 28 concept nodes" data-fx-line3="> agent ready. awaiting prompt_"'
    : '';

  sec.innerHTML = `
    <span class="fx-indicator">${idx}/${total}</span>
    <p class="kicker">FX · canvas · ${String(idx).padStart(2,'0')}</p>
    <h1 class="h1"><span class="gradient-text">${name}</span></h1>
    <p class="lede">${desc}</p>
    <div class="fx-stage">
      <span class="fx-label">data-fx="${name}"</span>
      <button class="fx-replay" type="button">Replay</button>
      <div class="fx-host" style="position:absolute;inset:0;" data-fx="${name}" ${extraAttrs}></div>
    </div>
    <div class="deck-footer"><span class="dim2">Press → for next slide</span><span class="slide-number" data-current="${idx}" data-total="${total}"></span></div>
  `;
  deck.appendChild(sec);

  // Wire Replay button
  sec.querySelector('.fx-replay').addEventListener('click', () => {
    const host = sec.querySelector('.fx-host');
    const name2 = host.getAttribute('data-fx');
    const attrs = {};
    for (const a of host.attributes) attrs[a.name] = a.value;
    const parent = host.parentNode;
    // stop existing
    if (window.__hpxActive && window.__hpxActive.has(host)){
      try{ window.__hpxActive.get(host).stop(); }catch(e){}
      window.__hpxActive.delete(host);
    }
    const fresh = document.createElement('div');
    for (const k in attrs) fresh.setAttribute(k, attrs[k]);
    fresh.style.cssText = host.style.cssText;
    parent.replaceChild(fresh, host);
    if (window.__hpxReinit) window.__hpxReinit(sec);
  });
});

// Build CSS animation slides (legacy, kept for completeness)
CSS_ANIMS.forEach((a, i) => {
  const idx = FX.length + i + 1;
  const sec = document.createElement('section');
  sec.className = 'slide';
  sec.setAttribute('data-title', a[0]);
  sec.innerHTML = `
    <span class="fx-indicator">${idx}/${total}</span>
    <p class="kicker">CSS anim · ${String(idx).padStart(2,'0')}</p>
    <h1 class="h1"><span class="gradient-text">${a[0]}</span></h1>
    <p class="lede">${a[1]}</p>
    <div class="anim-box anim-${a[0]}" data-anim="${a[0]}" data-anim-target>${a[0]}</div>
    <div class="deck-footer"><span class="dim2">Press A to cycle</span><span class="slide-number" data-current="${idx}" data-total="${total}"></span></div>
  `;
  deck.appendChild(sec);
});
</script>
<script src="../assets/runtime.js"></script>
<script src="../assets/animations/fx-runtime.js"></script>
</body></html>
