---
title: "Chromatic Aberration Wipe"
description: "A fast slide wipe with RGB channel split on peak frames."
---

import { InstallCommand } from "/snippets/install-command.jsx";
import { VariablesExplorer } from "/snippets/variables-explorer.jsx";

<VariablesExplorer
  previewSrc="/public/catalog/components/chromatic-aberration-wipe.json"
  compositionId="chromatic-aberration-wipe"
  compositionSrc="compositions/components/chromatic-aberration-wipe.html"
  variables={[{"id":"direction","type":"enum","role":"motion","label":"Direction","description":"The direction the reveal travels; both scenes slide the same way and the wipe edge follows.","default":"left","options":[{"value":"left","label":"Left"},{"value":"right","label":"Right"},{"value":"up","label":"Up"},{"value":"down","label":"Down"}]},{"id":"accent","type":"enum","role":"style","label":"Accent","description":"Colour family of the incoming scene's gradient.","default":"blue","options":[{"value":"blue","label":"Blue"},{"value":"green","label":"Green"},{"value":"violet","label":"Violet"}]},{"id":"aberration","type":"number","role":"style","label":"Aberration","description":"Multiplies the red/cyan channel split: 0 removes it, 1 is the stock strength, 2 doubles the offset and saturates the flash.","default":1,"min":0,"max":2,"step":0.1,"unit":"x"}]}
>

```html chromatic-aberration-wipe.html
<!--
  Chromatic Aberration Wipe - catalog component for HyperFrames.

  Paste the markup and CSS into a composition. Drive the timeline integration
  from a paused GSAP timeline so renders remain deterministic.

  Variables. The script reads each one, falls back to the declared default on
  anything missing or unrecognised, and writes the result as a custom property
  the CSS consumes. The timeline recipe below is untouched by them: it keeps
  driving one clip edge, one pair of offsets and one channel-split flash, and
  these decide which way that edge sweeps and how hard the flash reads.

    - direction (left | right | up | down, default left): the direction the
      reveal travels. Both scenes slide the same way and the wipe edge follows,
      so up and down turn the horizontal wipe into a vertical one.
    - accent (blue | green | violet, default blue): the incoming scene's
      gradient family.
    - aberration (0 to 2, default 1): multiplies the red/cyan channel split.
      0 removes it entirely, 2 doubles the offset and saturates the flash.

  On every default the result is identical to the original: a left-to-right
  wipe into the blue/violet scene with the stock RGB split.

  The white sheen sweeps horizontally in every direction; it is a flash rather
  than an edge, so it is left alone.
-->

<div
  class="hf-catalog-chromatic-aberration-wipe"
  data-composition-variables='[
    { "id": "direction", "type": "enum", "role": "motion", "label": "Direction", "description": "The direction the reveal travels; both scenes slide the same way and the wipe edge follows.", "default": "left", "options": [{ "value": "left", "label": "Left" }, { "value": "right", "label": "Right" }, { "value": "up", "label": "Up" }, { "value": "down", "label": "Down" }] },
    { "id": "accent", "type": "enum", "role": "style", "label": "Accent", "description": "Colour family of the incoming scene&#39;s gradient.", "default": "blue", "options": [{ "value": "blue", "label": "Blue" }, { "value": "green", "label": "Green" }, { "value": "violet", "label": "Violet" }] },
    { "id": "aberration", "type": "number", "role": "style", "label": "Aberration", "description": "Multiplies the red/cyan channel split: 0 removes it, 1 is the stock strength, 2 doubles the offset and saturates the flash.", "default": 1, "min": 0, "max": 2, "step": 0.1, "unit": "x" }
  ]'
>
  <div class="scene from">Before</div>
  <div class="scene to">Chromatic Aberration Wipe</div>
  <div class="fx"></div>
  <div class="rgb"></div>
</div>

<style>
  .hf-catalog-chromatic-aberration-wipe {
    --hf-accent: #2563eb;
    --hf-ink: #111827;
    --hf-muted: #6b7280;
    --hf-surface: #ffffff;
    color: var(--hf-ink);
    font-family: Inter, system-ui, sans-serif;
  }
  .hf-catalog-chromatic-aberration-wipe {
    position: relative;
    width: 760px;
    height: 428px;
    overflow: hidden;
    border-radius: 30px;
    background: #111827;
    box-shadow: 0 28px 80px rgba(15, 23, 42, 0.2);
  }
  .hf-catalog-chromatic-aberration-wipe .scene {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-weight: 900;
    font-size: 58px;
    letter-spacing: -0.05em;
    color: #fff;
  }
  .hf-catalog-chromatic-aberration-wipe .from {
    background: linear-gradient(135deg, #111827, #374151);
    transform: translate(
        calc(var(--hf-from-x, 0px) * var(--hf-wipe-ax, 1)),
        calc(var(--hf-from-y, 0px) + var(--hf-from-x, 0px) * var(--hf-wipe-ay, 0))
      )
      scale(var(--hf-from-scale, 1));
    filter: blur(var(--hf-from-blur, 0px));
  }
  .hf-catalog-chromatic-aberration-wipe .to {
    background: linear-gradient(135deg, var(--hf-scene-a, #2563eb), var(--hf-scene-b, #7c3aed));
    transform: translate(
        calc(var(--hf-to-x, 0px) * var(--hf-wipe-ax, 1)),
        calc(var(--hf-to-y, 0px) + var(--hf-to-x, 0px) * var(--hf-wipe-ay, 0))
      )
      scale(var(--hf-to-scale, 1));
    clip-path: inset(
      calc(var(--hf-clip-top, 0%) + var(--hf-clip-right, 100%) * var(--hf-wipe-t, 0))
        calc(var(--hf-clip-right, 100%) * var(--hf-wipe-r, 1))
        calc(var(--hf-clip-bottom, 0%) + var(--hf-clip-right, 100%) * var(--hf-wipe-b, 0))
        calc(var(--hf-clip-left, 0%) + var(--hf-clip-right, 100%) * var(--hf-wipe-l, 0))
    );
  }
  .hf-catalog-chromatic-aberration-wipe .fx {
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.75), transparent);
    mix-blend-mode: screen;
    transform: translateX(var(--hf-fx-x, -110%));
  }
  .hf-catalog-chromatic-aberration-wipe .rgb {
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: calc(var(--hf-rgb-opacity, 0) * var(--hf-rgb-strength, 1));
    background: linear-gradient(
      90deg,
      rgba(239, 68, 68, 0.35),
      transparent,
      rgba(34, 211, 238, 0.35)
    );
    transform: translateX(calc(var(--hf-rgb-x, 0px) * var(--hf-rgb-strength, 1)));
  }
</style>

<script>
  (function () {
    "use strict";

    var vars =
      window.__hyperframes && window.__hyperframes.getVariables
        ? window.__hyperframes.getVariables()
        : {};

    // Unrecognised overrides return to their declared defaults.
    var directions = {
      left: { ax: "1", ay: "0", t: "0", r: "1", b: "0", l: "0" },
      right: { ax: "-1", ay: "0", t: "0", r: "0", b: "0", l: "1" },
      up: { ax: "0", ay: "1", t: "1", r: "0", b: "0", l: "0" },
      down: { ax: "0", ay: "-1", t: "0", r: "0", b: "1", l: "0" },
    };
    var accents = {
      blue: ["#2563eb", "#7c3aed"],
      green: ["#047857", "#34d399"],
      violet: ["#6d28d9", "#a78bfa"],
    };

    function pick(table, value, fallback) {
      return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
    }

    var direction = directions[pick(directions, vars.direction, "left")];
    var accent = accents[pick(accents, vars.accent, "blue")];

    var raw = typeof vars.aberration === "string" ? parseFloat(vars.aberration) : vars.aberration;
    var aberration = typeof raw === "number" && isFinite(raw) ? Math.min(2, Math.max(0, raw)) : 1;

    var roots = document.querySelectorAll(".hf-catalog-chromatic-aberration-wipe");
    for (var i = 0; i < roots.length; i += 1) {
      roots[i].style.setProperty("--hf-wipe-ax", direction.ax);
      roots[i].style.setProperty("--hf-wipe-ay", direction.ay);
      roots[i].style.setProperty("--hf-wipe-t", direction.t);
      roots[i].style.setProperty("--hf-wipe-r", direction.r);
      roots[i].style.setProperty("--hf-wipe-b", direction.b);
      roots[i].style.setProperty("--hf-wipe-l", direction.l);
      roots[i].style.setProperty("--hf-scene-a", accent[0]);
      roots[i].style.setProperty("--hf-scene-b", accent[1]);
      roots[i].style.setProperty("--hf-rgb-strength", String(aberration));
    }
  })();
</script>

<!--
  Timeline integration:
  tl.fromTo('.hf-catalog-chromatic-aberration-wipe .to', { '--hf-clip-right': '100%', '--hf-to-x': '60px', '--hf-to-scale': 1.04 }, { '--hf-clip-right': '0%', '--hf-to-x': '0px', '--hf-to-scale': 1, duration: 0.9, ease: 'power3.inOut' }, startTime); tl.to('.hf-catalog-chromatic-aberration-wipe .from', { '--hf-from-x': '-70px', '--hf-from-scale': 0.96, '--hf-from-blur': '5px', duration: 0.9, ease: 'power3.inOut' }, startTime); tl.fromTo('.hf-catalog-chromatic-aberration-wipe .fx', { '--hf-fx-x': '-110%' }, { '--hf-fx-x': '110%', duration: 0.58, ease: 'power2.inOut' }, startTime + 0.18); tl.fromTo('.hf-catalog-chromatic-aberration-wipe .rgb', { '--hf-rgb-opacity': 0, '--hf-rgb-x': '-16px' }, { '--hf-rgb-opacity': 1, '--hf-rgb-x': '16px', repeat: 3, yoyo: true, duration: 0.07, ease: 'steps(1)' }, startTime + 0.32);
-->
```

</VariablesExplorer>

## Install

<InstallCommand command="npx hyperframes add chromatic-aberration-wipe" item="chromatic-aberration-wipe" />

That writes one file: `compositions/components/chromatic-aberration-wipe.html`.

## Variables

Every one of these has a default, so the piece works untouched. Set the ones you
want to change on the element:

| Variable | Default | Accepts | What it does |
| --- | --- | --- | --- |
| `direction` | `left` | `left`, `right`, `up`, `down` | The direction the reveal travels; both scenes slide the same way and the wipe edge follows. |
| `accent` | `blue` | `blue`, `green`, `violet` | Colour family of the incoming scene's gradient. |
| `aberration` | `1` | 0x to 2x, step 0.1x | Multiplies the red/cyan channel split: 0 removes it, 1 is the stock strength, 2 doubles the offset and saturates the flash. |

Set them with `data-variable-values` on the element that mounts it. These are the
defaults, so this behaves exactly like the preview above until you change one:

```html wrap
<div
  data-composition-id="chromatic-aberration-wipe"
  data-composition-src="compositions/components/chromatic-aberration-wipe.html"
  data-variable-values='{"direction":"left","accent":"blue","aberration":1}'
></div>
```

## Source

<Accordion title={`chromatic-aberration-wipe.html`}>

```html
<!--
  Chromatic Aberration Wipe - catalog component for HyperFrames.

  Paste the markup and CSS into a composition. Drive the timeline integration
  from a paused GSAP timeline so renders remain deterministic.

  Variables. The script reads each one, falls back to the declared default on
  anything missing or unrecognised, and writes the result as a custom property
  the CSS consumes. The timeline recipe below is untouched by them: it keeps
  driving one clip edge, one pair of offsets and one channel-split flash, and
  these decide which way that edge sweeps and how hard the flash reads.

    - direction (left | right | up | down, default left): the direction the
      reveal travels. Both scenes slide the same way and the wipe edge follows,
      so up and down turn the horizontal wipe into a vertical one.
    - accent (blue | green | violet, default blue): the incoming scene's
      gradient family.
    - aberration (0 to 2, default 1): multiplies the red/cyan channel split.
      0 removes it entirely, 2 doubles the offset and saturates the flash.

  On every default the result is identical to the original: a left-to-right
  wipe into the blue/violet scene with the stock RGB split.

  The white sheen sweeps horizontally in every direction; it is a flash rather
  than an edge, so it is left alone.
-->

<div
  class="hf-catalog-chromatic-aberration-wipe"
  data-composition-variables='[
    { "id": "direction", "type": "enum", "role": "motion", "label": "Direction", "description": "The direction the reveal travels; both scenes slide the same way and the wipe edge follows.", "default": "left", "options": [{ "value": "left", "label": "Left" }, { "value": "right", "label": "Right" }, { "value": "up", "label": "Up" }, { "value": "down", "label": "Down" }] },
    { "id": "accent", "type": "enum", "role": "style", "label": "Accent", "description": "Colour family of the incoming scene&#39;s gradient.", "default": "blue", "options": [{ "value": "blue", "label": "Blue" }, { "value": "green", "label": "Green" }, { "value": "violet", "label": "Violet" }] },
    { "id": "aberration", "type": "number", "role": "style", "label": "Aberration", "description": "Multiplies the red/cyan channel split: 0 removes it, 1 is the stock strength, 2 doubles the offset and saturates the flash.", "default": 1, "min": 0, "max": 2, "step": 0.1, "unit": "x" }
  ]'
>
  <div class="scene from">Before</div>
  <div class="scene to">Chromatic Aberration Wipe</div>
  <div class="fx"></div>
  <div class="rgb"></div>
</div>

<style>
  .hf-catalog-chromatic-aberration-wipe {
    --hf-accent: #2563eb;
    --hf-ink: #111827;
    --hf-muted: #6b7280;
    --hf-surface: #ffffff;
    color: var(--hf-ink);
    font-family: Inter, system-ui, sans-serif;
  }
  .hf-catalog-chromatic-aberration-wipe {
    position: relative;
    width: 760px;
    height: 428px;
    overflow: hidden;
    border-radius: 30px;
    background: #111827;
    box-shadow: 0 28px 80px rgba(15, 23, 42, 0.2);
  }
  .hf-catalog-chromatic-aberration-wipe .scene {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-weight: 900;
    font-size: 58px;
    letter-spacing: -0.05em;
    color: #fff;
  }
  .hf-catalog-chromatic-aberration-wipe .from {
    background: linear-gradient(135deg, #111827, #374151);
    transform: translate(
        calc(var(--hf-from-x, 0px) * var(--hf-wipe-ax, 1)),
        calc(var(--hf-from-y, 0px) + var(--hf-from-x, 0px) * var(--hf-wipe-ay, 0))
      )
      scale(var(--hf-from-scale, 1));
    filter: blur(var(--hf-from-blur, 0px));
  }
  .hf-catalog-chromatic-aberration-wipe .to {
    background: linear-gradient(135deg, var(--hf-scene-a, #2563eb), var(--hf-scene-b, #7c3aed));
    transform: translate(
        calc(var(--hf-to-x, 0px) * var(--hf-wipe-ax, 1)),
        calc(var(--hf-to-y, 0px) + var(--hf-to-x, 0px) * var(--hf-wipe-ay, 0))
      )
      scale(var(--hf-to-scale, 1));
    clip-path: inset(
      calc(var(--hf-clip-top, 0%) + var(--hf-clip-right, 100%) * var(--hf-wipe-t, 0))
        calc(var(--hf-clip-right, 100%) * var(--hf-wipe-r, 1))
        calc(var(--hf-clip-bottom, 0%) + var(--hf-clip-right, 100%) * var(--hf-wipe-b, 0))
        calc(var(--hf-clip-left, 0%) + var(--hf-clip-right, 100%) * var(--hf-wipe-l, 0))
    );
  }
  .hf-catalog-chromatic-aberration-wipe .fx {
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.75), transparent);
    mix-blend-mode: screen;
    transform: translateX(var(--hf-fx-x, -110%));
  }
  .hf-catalog-chromatic-aberration-wipe .rgb {
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: calc(var(--hf-rgb-opacity, 0) * var(--hf-rgb-strength, 1));
    background: linear-gradient(
      90deg,
      rgba(239, 68, 68, 0.35),
      transparent,
      rgba(34, 211, 238, 0.35)
    );
    transform: translateX(calc(var(--hf-rgb-x, 0px) * var(--hf-rgb-strength, 1)));
  }
</style>

<script>
  (function () {
    "use strict";

    var vars =
      window.__hyperframes && window.__hyperframes.getVariables
        ? window.__hyperframes.getVariables()
        : {};

    // Unrecognised overrides return to their declared defaults.
    var directions = {
      left: { ax: "1", ay: "0", t: "0", r: "1", b: "0", l: "0" },
      right: { ax: "-1", ay: "0", t: "0", r: "0", b: "0", l: "1" },
      up: { ax: "0", ay: "1", t: "1", r: "0", b: "0", l: "0" },
      down: { ax: "0", ay: "-1", t: "0", r: "0", b: "1", l: "0" },
    };
    var accents = {
      blue: ["#2563eb", "#7c3aed"],
      green: ["#047857", "#34d399"],
      violet: ["#6d28d9", "#a78bfa"],
    };

    function pick(table, value, fallback) {
      return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
    }

    var direction = directions[pick(directions, vars.direction, "left")];
    var accent = accents[pick(accents, vars.accent, "blue")];

    var raw = typeof vars.aberration === "string" ? parseFloat(vars.aberration) : vars.aberration;
    var aberration = typeof raw === "number" && isFinite(raw) ? Math.min(2, Math.max(0, raw)) : 1;

    var roots = document.querySelectorAll(".hf-catalog-chromatic-aberration-wipe");
    for (var i = 0; i < roots.length; i += 1) {
      roots[i].style.setProperty("--hf-wipe-ax", direction.ax);
      roots[i].style.setProperty("--hf-wipe-ay", direction.ay);
      roots[i].style.setProperty("--hf-wipe-t", direction.t);
      roots[i].style.setProperty("--hf-wipe-r", direction.r);
      roots[i].style.setProperty("--hf-wipe-b", direction.b);
      roots[i].style.setProperty("--hf-wipe-l", direction.l);
      roots[i].style.setProperty("--hf-scene-a", accent[0]);
      roots[i].style.setProperty("--hf-scene-b", accent[1]);
      roots[i].style.setProperty("--hf-rgb-strength", String(aberration));
    }
  })();
</script>

<!--
  Timeline integration:
  tl.fromTo('.hf-catalog-chromatic-aberration-wipe .to', { '--hf-clip-right': '100%', '--hf-to-x': '60px', '--hf-to-scale': 1.04 }, { '--hf-clip-right': '0%', '--hf-to-x': '0px', '--hf-to-scale': 1, duration: 0.9, ease: 'power3.inOut' }, startTime); tl.to('.hf-catalog-chromatic-aberration-wipe .from', { '--hf-from-x': '-70px', '--hf-from-scale': 0.96, '--hf-from-blur': '5px', duration: 0.9, ease: 'power3.inOut' }, startTime); tl.fromTo('.hf-catalog-chromatic-aberration-wipe .fx', { '--hf-fx-x': '-110%' }, { '--hf-fx-x': '110%', duration: 0.58, ease: 'power2.inOut' }, startTime + 0.18); tl.fromTo('.hf-catalog-chromatic-aberration-wipe .rgb', { '--hf-rgb-opacity': 0, '--hf-rgb-x': '-16px' }, { '--hf-rgb-opacity': 1, '--hf-rgb-x': '16px', repeat: 3, yoyo: true, duration: 0.07, ease: 'steps(1)' }, startTime + 0.32);
-->
```

</Accordion>

## Usage

Open `compositions/components/chromatic-aberration-wipe.html` and paste its contents into your composition. See the comment header in the file for timeline integration guidance.

{/* hf:generated-footer */}

Tagged `video-primitive` `transition-primitive`.

## Related topics

- [Browse the complete Catalog](/catalog)
- [Add assets and Catalog items in Studio](/studio/assets-and-blocks)
- [Build a richer composition](/go-further)
