# Thumb streams 01

> Streams of small video thumbnails that curve across the section and grow toward the end, with a heading, line and two buttons at the start and a preview card in the corner.

URL: https://apogee.avaui.dev/docs/hero-sections/thumb-streams-01
Last updated: 2026-10-20

Streams of small video thumbnails that curve across the section and grow toward the end, with a heading, line and two buttons at the start and a preview card in the corner.

Last updated October 20, 2026

Live example: https://apogee.avaui.dev/examples/hero/thumb-streams-01

```astro
---
/**
 * Thumb streams 01: Streams of small video thumbnails that curve across the section and grow toward the end, with a heading, line and two buttons at the start and a preview card in the corner.
 *
 * @block hero
 * @order 66
 */
import { ArrowUp, ArrowUpRight } from '@lucide/astro'
import Section from '@/components/apogee/Section/Section.astro'
import Heading from '@/components/apogee/Heading/Heading.astro'
import Button from '@/components/apogee/Button/Button.astro'
import Badge from '@/components/apogee/Badge/Badge.astro'
import { plain, type HeroContent } from '@/components/apogee/sections/_shared/spine.ts'

/** @composable */
interface Props extends HeroContent {}

const {
  heading = 'See what your footage knows',
  description = 'Every moment, every play, every decision is already on video. Finding it used to take days. Now it takes a question.',
  primaryAction = { label: 'Try it now', href: '#' },
  secondaryAction = { label: 'Talk to sales', href: '#' },
} = Astro.props

// Three streams along gentle curves; thumbnails get bigger and brighter toward the end.
const ids = [10, 11, 15, 16, 17, 18, 19, 20, 22, 24, 27, 28, 29, 33, 34, 37, 39, 40, 42, 43, 47, 49, 50, 54]
const streams = [
  { y: 22, amp: -14, phase: 0.6 },
  { y: 52, amp: 6, phase: 0 },
  { y: 78, amp: -10, phase: 1.2 },
]
const thumbs = streams.flatMap((s, si) => Array.from({ length: 11 }, (_, i) => {
  const t = i / 10
  return { id: ids[(si * 11 + i) % ids.length], x: 5 + t * 88, y: s.y + s.amp * Math.sin(t * Math.PI + s.phase), w: 3.5 + t * t * 7, o: 0.25 + t * 0.75 }
}))
---

<Section spacing="none" container={false} class="overflow-hidden">
  <div class="relative min-h-[48rem] md:min-h-[56rem]">
    <div class="pointer-events-none absolute inset-0" aria-hidden="true">
      {thumbs.map((t) => (
        <img src={`https://picsum.photos/id/${t.id}/320/200`} alt="" loading="lazy" class="absolute aspect-16/10 -translate-x-1/2 -translate-y-1/2 rounded-md object-cover shadow-md rtl:translate-x-1/2" style={`inset-inline-start: ${t.x}%; top: ${t.y}%; width: ${t.w}rem; opacity: ${t.o}`} />
      ))}
    </div>
    <!-- Page colour behind the text so it reads over the thumbnails. -->
    <div class="pointer-events-none absolute inset-0 bg-[linear-gradient(to_right,var(--background-page)_25%,transparent_65%)] rtl:bg-[linear-gradient(to_left,var(--background-page)_25%,transparent_65%)]" aria-hidden="true"></div>

    <div class="relative flex max-w-3xl flex-col gap-6 px-gutter pt-40 md:pt-56">
      <Heading as="h1" size="display" class="font-normal text-balance">{plain(heading)}</Heading>
      {description && <p class="max-w-2xl text-lg md:text-xl">{description}</p>}
      {(primaryAction || secondaryAction) && (
        <div class="mt-2 flex flex-wrap gap-3">
          {primaryAction && <Button href={primaryAction.href} size="xlarge" rounded>{primaryAction.label}<ArrowUpRight slot="end" aria-hidden="true" /></Button>}
          {secondaryAction && <Button href={secondaryAction.href} size="xlarge" rounded variant="outline" color="neutral">{secondaryAction.label}</Button>}
        </div>
      )}
    </div>

    <a href="#" class="relative mx-gutter mt-16 flex max-w-sm flex-col gap-4 rounded-2xl border border-neutral-faded bg-neutral-faded p-4 backdrop-blur-md md:absolute md:bottom-8 md:end-8 md:mx-0 md:mt-0">
      <div data-theme="dark" class="flex flex-col items-center gap-3 rounded-lg bg-page p-6 text-neutral">
        <span class="text-lg">Scout</span>
        <span class="flex w-full items-center justify-between gap-3 rounded-full border border-neutral-faded px-3 py-1.5 text-xs">Sum up what works across our ad archive<ArrowUp class="size-4 shrink-0" aria-hidden="true" /></span>
      </div>
      <Badge variant="outline" color="primary" class="self-start">Research preview</Badge>
      <span class="text-lg leading-snug">Meet Scout, an agent that watches and understands video</span>
    </a>
  </div>
</Section>
```

## Add

```sh
npx @ava-ui/apogee add hero/thumb-streams-01
```

Every piece of copy is a prop, with the sample copy as its default. Pass yours, or `null` to hide a part; see [copy is props](https://apogee.avaui.dev/docs/hero-sections#copy-is-props).
