← Blurr Motion cta-shader-orb-kinetic
Categorie cta Tier 3 Techniek #36 Deps gsap, webgl2

FREQUENTIE 04

RAW
SIGNAL.

No softeners. Press the button, get the heat.

START NOW →
1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: cta-shader-orb-kinetic (techniek #36 — Custom GLSL fragment shader)
// WebGL2 fullscreen quad in ronde clip. Radiale gradient + sin-wave puls op uTime.
// Kleur cycelt zwart -> acid -> coral via 3 sin-waves met phase-offset.
// Auto-running rAF loop, geen click nodig. CTA-button er overheen.
// Fallback: animated CSS radial-gradient orb met @keyframes pulse.
import gsap from 'https://esm.sh/[email protected]';
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const root = document.querySelector('.shader-orb-kinetic');
if (root) {
  const canvas = root.querySelector('canvas');
  const fallback = root.querySelector('.orb-fallback');
  const gl = canvas && canvas.getContext('webgl2', { antialias: true, premultipliedAlpha: true });
  if (!gl) {
    if (fallback) fallback.style.display = 'block';
    if (canvas) canvas.style.display = 'none';
  } else {
    // ... compile vs+fs, link program, fullscreen quad VBO,
    // uniform uT (time) + uRes, draw loop via rAF.
  }
}
2. Skeleton — DOM + class-namen, mag herschikken
<!-- Skeleton: cta-shader-orb-kinetic -->
<section class="cta-orb-kinetic-section">
  <div class="orb-grid">
    <p class="orb-eyebrow">FREQUENTIE 04</p>
    <h2 class="orb-title">RAW<br/>SIGNAL.</h2>
    <p class="orb-sub">No softeners. Press the button, get the heat.</p>
    <a class="orb-cta" data-intro href="#">START NOW →</a>
  </div>
  <div class="shader-orb-kinetic" aria-hidden="true">
    <canvas></canvas>
    <div class="orb-fallback"></div>
  </div>
</section>
3. Styling-template — verplicht eigen invulling per merk
/* Styling: cta-shader-orb-kinetic — black + acid yellow + coral, Archivo Black, oversize */
:root {
  --block-bg: #0A0A0A;
  --block-fg: #FFE600;
  --block-accent: #FF4D2E;
}
.cta-orb-kinetic-section {
  background: var(--block-bg);
  color: var(--block-fg);
  font-family: 'Archivo Black', 'Anton', sans-serif;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4rem);
  padding: clamp(3rem, 6vw, 6rem);
  align-items: center;
  min-height: 80vh;
}
.orb-eyebrow {
  font-family: 'Archivo', sans-serif; font-weight: 700;
  font-size: 0.8rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--block-accent); margin: 0 0 1.5rem;
}
.orb-title {
  font-size: clamp(4rem, 12vw, 12rem); line-height: 0.85;
  letter-spacing: -0.05em; margin: 0; text-transform: uppercase;
}
.orb-sub {
  font-family: 'Archivo', sans-serif; font-weight: 500;
  font-size: clamp(1rem, 1.4vw, 1.25rem); line-height: 1.4;
  max-width: 28ch; margin: 2rem 0;
  color: rgba(255, 230, 0, 0.7);
}
.orb-cta {
  display: inline-block;
  font-family: 'Archivo Black', sans-serif;
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  color: var(--block-bg); background: var(--block-fg);
  padding: 1.25rem 2.5rem; text-decoration: none; text-transform: uppercase;
  transition: background 0.2s, color 0.2s;
}
.orb-cta:hover { background: var(--block-accent); color: var(--block-fg); }
.shader-orb-kinetic { position: relative; aspect-ratio: 1; width: 100%; max-width: 520px; }
.shader-orb-kinetic canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.shader-orb-kinetic .orb-fallback {
  position: absolute; inset: 0; display: none; border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, #FFE600 0%, #FF4D2E 50%, #0A0A0A 100%);
  animation: orbPulse 1.2s ease-in-out infinite;
}
@keyframes orbPulse {
  0%, 100% { transform: scale(0.92); }
  50% { transform: scale(1); }
}