Naar inhoud
Inloggen

/showcases · Brand

Hero-motionloop: van tekstprompt naar productieasset van 460 KB

Hoe we de hero-video van AudioLab.tools genereerden, encodeerden en integreerden: een subtiele, ademende loop van 5 seconden met een cyaankleurig lint. End-to-end-pipeline inclusief generatie met Higgsfield seedance, ffmpeg WebM- + H.264-encoding, afbeeldingsfallback en afhandeling van prefers-reduced-motion.

4 juni 2026 10 min read
Higgsfield seedance 2.0 ffmpeg libvpx-vp9 libx264 Astro Image

Outcome

460 KB totaal geleverd (WebM + MP4). 5 seconden subtiele beweging. Statische afbeeldingsfallback voor trage netwerken. Volledig verwijderd voor gebruikers met prefers-reduced-motion.


Een bewegende hero op een tech-website is een riskante zet. Doe je het verkeerd, dan is het een afleidende, automatisch afspelende advertentie; doe je het goed, dan is het het verschil tussen “weer een developersite” en “premium merk”. De voorwaarden die we stelden:

  • Subtiel. De beweging is ademhaling, geen actie. Niets mag de aandacht weghalen van de tekstoverlay.
  • Klein. Onder de 500 KB totaal transport, punt uit.
  • Fallback-first. De pagina moet er prima uitzien zonder enige video.
  • Met respect voor reduced-motion. Gebruikers die zich hebben afgemeld, krijgen niets geanimeerds.

Zo kregen we het voor elkaar in ongeveer 20 minuten echt werk.

Stap 1: Genereer de beweging (Higgsfield seedance 2.0)

Seedance is hiervoor het juiste model: image-to-video, identiteitsbehoudend, met sterke ondersteuning voor subtiele beweging. We gebruikten dezelfde 21:9-afbeelding met cyaan lint die we bouwden voor de statische hero (zie brand imagery pipeline) als referentieframe.

{
  model: 'seedance_2_0',
  prompt: `The luminous cyan ribbon of light breathes and slowly rotates
           in pitch-black space, with subtle volumetric particles drifting
           through the frame. Very slow, gentle motion — the ribbon appears
           to inhale and exhale, with soft glow pulses. Camera completely
           static. The lighting and composition match the reference image
           exactly. Premium, calm, atmospheric, ambient. No camera movement,
           no cuts, just subtle organic motion of the light ribbon itself.`,
  duration: 5,
  resolution: '720p',
  aspect_ratio: '21:9',
  mode: 'std',
  medias: [{ value: heroImageUrl, role: 'image' }],
}

Twee promptvoorwaarden die de output bruikbaar maakten:

  1. “Camera completely static.” Zonder dit valt seedance terug op een langzame inzoom die er net zo uitziet als elke andere tech-video.
  2. “No camera movement, no cuts, just subtle organic motion.” Versterkt punt 1 en voorkomt dat het model stilistische cuts toevoegt.

Kosten: 22 credits. Rendertijd: ~70 seconden.

Stap 2: Verwijder de audio

Seedance levert een MP4 met audio op. Die hebben we niet nodig: de hero is stil, en audio zou sowieso betekenen dat we in de meeste browsers niet konden autoplayen.

ffmpeg -i hero.mp4 -an -c:v copy hero-noaudio.mp4

De -an-flag verwijdert de audio; -c:v copy slaat het opnieuw encoderen van de video over. Snelle pass, geen kwaliteitsverlies. We gebruiken deze output als bron voor beide volgende encodes.

Stap 3: Encodeer VP9 WebM (moderne browsers)

VP9 in een WebM-container comprimeert beter dan H.264 en is de juiste keuze voor browsers die het ondersteunen (~90 % van het verkeer).

ffmpeg -i hero.mp4 -an \
  -c:v libvpx-vp9 \
  -b:v 800k -crf 36 \
  -row-mt 1 -tile-columns 2 -threads 4 \
  -deadline good -cpu-used 2 \
  hero.webm

Instellingen die het vermelden waard zijn:

  • -crf 36: kwaliteitsdoel. 36 is aan de agressieve kant; het bronmateriaal (een traag bewegend abstract lichtlint over zwart) comprimeert uitzonderlijk goed, dus we kunnen het ons veroorloven.
  • -b:v 800k: bitrateplafond. Voorkomt dat VP9 te veel toewijst aan de paar frames met beweging.
  • -row-mt 1 -tile-columns 2 -threads 4: multi-threaded encoding. Sneller lokaal encoderen zonder invloed op de outputkwaliteit.
  • -deadline good -cpu-used 2: afweging tussen kwaliteit en snelheid. good/2 is de sweet spot voor eenmalige assets.

Output: 252 KB voor 5 seconden op 720p.

Stap 4: Encodeer H.264 MP4 (Safari-fallback)

Safari (en enkele oudere browsers) ondersteunt VP9 niet. We hebben een H.264 MP4 nodig als fallback.

ffmpeg -i hero-noaudio.mp4 -an \
  -c:v libx264 -crf 28 -preset slow \
  -movflags +faststart -pix_fmt yuv420p \
  hero.mp4

Instellingen:

  • -crf 28: iets behoudender dan de WebM-crf, omdat H.264 dit materiaal niet zo efficiënt comprimeert.
  • -preset slow: betere compressie. We encoderen één keer, niet in real time.
  • -movflags +faststart: verplaatst de MP4-metadata-atom naar voren zodat de browser het afspelen kan starten voordat het hele bestand is gedownload.
  • -pix_fmt yuv420p: vereist voor Safari-compatibiliteit op iOS.

Output: 209 KB voor 5 seconden op 720p.

Stap 5: Zet de markup op

<section class="relative isolate overflow-hidden">
  {/* Static image fallback — renders first, hidden when video plays */}
  <Image
    src={heroWideImg}
    alt=""
    widths={[1280, 1920, 2560, 3168]}
    sizes="100vw"
    loading="eager"
    fetchpriority="high"
    class="absolute inset-0 -z-10 h-full w-full object-cover"
  />

  {/* Motion video — slow ambient loop */}
  <video
    class="absolute inset-0 -z-10 h-full w-full object-cover opacity-0
           transition-opacity duration-700 motion-reduce:hidden"
    id="hero-video"
    autoplay loop muted playsinline
    preload="metadata"
    aria-hidden="true"
  >
    <source src="/media/hero.webm" type="video/webm" />
    <source src="/media/hero.mp4" type="video/mp4" />
  </video>

  {/* Contrast overlays + text layer */}
  ...
</section>

<script is:inline>
  // Fade the video in once it actually starts playing
  const v = document.getElementById('hero-video');
  v?.addEventListener('playing', () => { v.style.opacity = '1'; });
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) v?.remove();
</script>

Drie patronen die het benoemen waard zijn:

  1. De afbeelding wordt eerst getoond, de video fadet in. De gebruiker ziet meteen een prachtige statische hero. Pas wanneer de video een frame heeft gedecodeerd en is begonnen met afspelen, fadet die over de afbeelding heen in. Geen schokkerige zwarte flits, geen waargenomen laadtijd.
  2. motion-reduce:hidden Tailwind-class: declaratieve afhandeling van reduced-motion.
  3. Imperatieve verwijdering in het inline-script: als de gebruiker reduced motion heeft ingeschakeld, wordt het <video>-element volledig uit de DOM verwijderd. Geen netwerkverzoek, geen decoding, geen stroomverbruik.

Wat (even) misging

  • De eerste WebM-encode was 800 KB. Te groot. -crf opgehoogd van 30 naar 36 en -cpu-used van 4 naar 2; daarmee op 252 KB gekomen.
  • Aanvankelijke autoplay-problemen op iOS. playsinline vergeten. iOS vereist dit voor inline video; zonder probeert de video bij het afspelen naar fullscreen te gaan.
  • De MP4 was 1,2 MB vóór het opnieuw encoderen. De output van seedance is getrouw maar groter dan nodig voor het web. De re-encode-pass met -crf 28 bracht het terug naar 209 KB.

Resultaat

Totaal transport: 460 KB in het slechtste geval (beide bestanden gecachet na de eerste keer laden). Visuele signatuur: een lichtgevend, ademend cyaan lint dat de hele homepage naar een hoger niveau tilt. Tijd van idee tot productie: ~20 minuten.

Het algemene principe: wanneer je beweging op een merk-hero uitrolt, doe het encodingwerk. De output van het model is de bronasset, niet de productieasset.

Gerelateerd