# Split-Flap Board

> Airport-departure-board character flipping for headlines, stats and status rows, with each cell rolling on a real 3D hinge and the board resolving as a staggered wave.

Canonical: https://gsapvault.com/effects/split-flap-board
Live demo: https://gsapvault.com/demos/split-flap-board/index.html

| Property | Value |
|----------|-------|
| Type | effect |
| Tier | paid |
| Price | £5 |
| Difficulty | advanced |
| Plugins | ScrollTrigger |
| Techniques | split-flap, text-animation, 3d-transforms, stagger, count-up |
| Uses Lenis | No |

## Overview

A mechanical split-flap effect that turns headlines, stats and status rows into an airport departure board. Every character is a real hinge built from four clipped glyph layers: a top leaf falls 180 degrees onto the half below it, shadowing it deepest mid-flip, so the flipping is visibly hinged rather than a fade or a scramble.

Cells roll through a configurable character set and decelerate into their destination, and rows lag columns so a whole board resolves as a wave running out of the top-left corner. The final flap overshoots its stop a few degrees and settles, then a light sweeps across the glass as the last cell lands.

A shuffle control re-flips every cell to a new destination on demand, which is what turns a reveal into something a visitor will press repeatedly.

## Features

- True hinged flaps: a leaf rotating a full 180 degrees on the split line, not a fade, slide or character scramble
- Shadow that tracks the flip, peaking with the leaf edge-on and gone by the time it lands
- Decelerating rolls: each flap is slower than the last, so cells ease into their destination instead of ticking uniformly
- Per-cell stagger across rows and columns, resolving the board as a wave from the top-left corner
- Overshoot-and-settle on the final flap, tuned to read as mechanical rather than bouncy
- Light sweep across the board as the last cell lands, switchable with one attribute
- Shuffle control that re-flips every cell to a fresh destination, with alternate strings set per row
- Cells are generated from the text in your markup, so screen readers read the real text and JS-off leaves plain styled type

## Use Cases

- Agency and studio landing pages with a departures-board hero that resolves as you scroll to it
- Stat and metrics strips where the numbers should feel mechanically counted, not faded in
- Live status and availability rows on product or service pages, with wording that can change
- Event, travel and venue sites wanting genuine departure-board character rather than a stock counter
- Portfolio and case-study intros needing one memorable, repeatable interaction above the fold

## How It Works

Each character becomes a cell of four absolutely positioned glyph layers clipped with clip-path: two static halves, plus a leaf carrying a front face (the outgoing character's top half) and a back face (the incoming character's bottom half, pre-rotated 180 degrees in CSS). One continuous rotationX from 0 to -180 therefore lands the incoming character upright over the bottom half, exactly like the hardware.

Every cell's roll is a single gsap.timeline() with one tween per flap. That tween animates a proxy value and drives both response channels through gsap.quickSetter: the leaf's rotationX and the opacity of the shade over the lower half, which follows a sine curve so it peaks mid-flip. Per-flap durations follow a cubic ramp for the deceleration, and the last flap uses back.out so the leaf overshoots its stop and settles.

A master timeline positions each cell's roll at rowIndex plus columnIndex offsets to build the wave, rewrites the hidden screen-reader mirrors on completion, and fires the glint sweep. ScrollTrigger (once) or a delayed call kicks off the first resolve, and gsap.matchMedia routes reduced-motion visitors to the plain text that shipped in the HTML.

## Integration Preview

How this effect integrates into a page. The full documentation (examples, events, programmatic API, customization guide) ships with the download.

### Quick Start

**1. Add to your HTML `<head>`:**

```html
<link rel="stylesheet" href="path/to/style.css">
<script data-cfasync="false">document.documentElement.classList.add('has-js')</script>
```

The one-line inline script sets a JS flag so controls that need JavaScript can hide themselves when it is unavailable. Keep `data-cfasync="false"` if you are behind Cloudflare Rocket Loader.

**2. Add the board anywhere in your `<body>`:**

```html
<div class="flap-board" id="studio-board" data-flap data-trigger="load">
  <div class="flap-board__rows" data-flap-rows>

    <div class="flap-row flap-row--head">
      <span class="flap-row__label">Now boarding</span>
      <span class="flap-text" data-flap-text data-flap-alts="LAUNCH DAY|FULL SEND">DEPARTURES</span>
    </div>

    <div class="flap-row">
      <span class="flap-row__label">Projects shipped</span>
      <span class="flap-text" data-flap-text data-charset="0123456789" data-flap-alts="318|327">312</span>
      <span class="flap-row__unit">total</span>
    </div>

  </div>
</div>

<div class="showcase-actions">
  <button type="button" class="flap-shuffle" data-flap-shuffle="studio-board">
    Shuffle the board
  </button>
</div>
```

**3. Add before the closing `</body>` tag:**

```html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/ScrollTrigger.min.js"></script>
<script src="path/to/script.js"></script>
```

Write the real text inside each `[data-flap-text]` element. The script reads it, replaces it with generated flap cells, and keeps the true text in a hidden mirror for screen readers, so the plain text is what ships in your HTML. This example matches the included demo: it resolves on load and points an external shuffle button at the board's `id`; switch `data-trigger` to `scroll` when the board begins below the fold.

### Options

Set these on the container that carries `data-flap`.

| Attribute | Values | Default | Description |
|-----------|--------|---------|-------------|
| `data-flap` | (present) | n/a | Marks the board. Required. |
| `data-charset` | Any string | `ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:%` | Characters a cell rolls through on its way to its destination. Uppercased automatically. |
| `data-speed` | Any number | `1` | Roll speed multiplier. `2` is twice as fast, `0.5` half. |
| `data-stagger` | Seconds | `0.045` | Delay between neighbouring cells. Rows lag by four times this, which is what makes the wave. `0` resolves the whole board at once. |
| `data-rolls` | Whole number | `8` | How many characters a cell passes through before landing. Below `3` the roll reads as a single flip; above about `14` the board takes too long to settle. |
| `data-trigger` | `scroll`, `load` | `scroll` | `scroll` resolves the board when it comes into view (once). `load` resolves it shortly after the page is ready. |
| `data-glint` | `true`, `false` | `true` | The light sweep across the board as the last cell lands. |

Per-row attributes, on each `[data-flap-text]` element:

| Attribute | Values | Default | Description |
|-----------|--------|---------|-------------|
| `data-flap-text` | (present) | n/a | Marks text to be turned into flap cells. Required on every row. |
| `data-flap-alts` | Strings split by `\|` | none | Alternative destinations for this row. Each shuffle picks one at random (never the current one). Without alts, a shuffle re-rolls the row back to the same text. |
| `data-charset` | Any string | inherits the board's | Overrides the roll characters for this row. Numeric rows look much better rolling digits only. |

Markup hooks:

| Attribute | Goes on | Description |
|-----------|---------|-------------|
| `data-flap-rows` | The wrapper around the rows | Gets `aria-live="polite"` so a resolve is announced once. Optional; the board itself is used if absent. |
| `data-flap-shuffle` | A `<button>` | Re-flips every cell to a new destination. Put it inside the board, or anywhere on the page with `data-flap-shuffle="board-id"` pointing at the board's `id`. |

### Accessibility

- **Screen readers** never hear the roll. The generated cells are inside an `aria-hidden="true"` wrapper, and the true text lives in a visually hidden mirror inside the same element, so the row reads as "312", never as a stream of rolling characters. The rows wrapper is marked `aria-live="polite"` and the mirrors are all rewritten once, when the board finishes resolving.
- **Reduced motion**: no cells are generated at all. Every row stays as the plain styled text that shipped in your HTML, and the shuffle control hides itself, since there is nothing for it to flip.
- **JavaScript off, or a blocked CDN**: identical to the reduced-motion state. Nothing is hidden by CSS that only JavaScript can un-hide.
- **Keyboard**: the shuffle control is a real `<button>`, so Enter and Space work, and it carries a visible `:focus-visible` ring.
- **Touch**: the board is time-driven rather than pointer-driven, so it behaves the same on a phone, with a slightly shorter roll to keep frames cheap. The shuffle button is a 48px-minimum touch target and goes full width on small screens.

### Dependencies

**Required:**
- GSAP 3.14.2
- ScrollTrigger plugin (only used by `data-trigger="scroll"`)

No other libraries, no images, no fonts beyond the mono face you choose for the cells.

## What You Get

- `index.html`: working demo page
- `assets/script.js`: commented, readable source
- `assets/style.css`: effect styles
- `README.md`: full documentation with examples and framework integration notes
- `LICENSE.txt`: standard license terms
- Lifetime updates: re-download anytime from your library

## Get the Code

This is a premium effect. The standard license costs £5 one-time and covers unlimited personal and commercial projects with no attribution required. The only restrictions: no redistribution of the code itself and no competing effect libraries.

- [Buy Split-Flap Board](https://gsapvault.com/effects/split-flap-board)
- [Effects & Templates Vault (£39 one-time, best value): every current and future effect and template](https://gsapvault.com/effects)

## Judge the Code Quality First

These related effects are free with complete source published, written to the same production standard (cleanup functions, reduced-motion support, framework-agnostic):

- [Typewriter Text](https://gsapvault.com/effects/typewriter-text.md): Text types out character by character with a blinking cursor when scrolled into view. Supports looping phrases, custom speed, and delay controls.
- [Scroll Text Highlight](https://gsapvault.com/effects/scroll-text-highlight.md): Scroll-linked reading highlight that lights a paragraph word by word as you scroll, with the leading word flashing an accent colour before settling to full foreground.

---

From [GSAP Vault](https://gsapvault.com): production-ready GSAP animation effects. Full catalog for agents: https://gsapvault.com/llms-full.txt
