> ## Documentation Index
> Fetch the complete documentation index at: https://hyperframes.heygen.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Separator

> A one-pixel structural separator with horizontal and vertical variants plus a seek-safe progress reveal

export const InstallCommand = ({command}) => {
  const [copied, setCopied] = React.useState(false);
  const copy = async () => {
    try {
      if (navigator.clipboard && window.isSecureContext) {
        await navigator.clipboard.writeText(command);
      } else {
        const previous = document.activeElement;
        const scratch = document.createElement("textarea");
        scratch.value = command;
        scratch.setAttribute("readonly", "");
        scratch.style.position = "fixed";
        scratch.style.opacity = "0";
        document.body.appendChild(scratch);
        scratch.select();
        document.execCommand("copy");
        document.body.removeChild(scratch);
        previous?.focus?.();
      }
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {}
  };
  return <div className="hf-install-command not-prose my-4 flex items-stretch overflow-hidden rounded-xl border border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900">
      <code className="flex-1 overflow-x-auto whitespace-nowrap border-r border-zinc-200 px-4 py-3 font-mono text-sm text-zinc-800 dark:border-zinc-800 dark:text-zinc-100">
        {command}
      </code>
      <button type="button" onClick={copy} data-copied={copied ? "true" : "false"} aria-label={`Copy ${command} to the clipboard`} className="hf-install-copy">
        <svg className="hf-install-copy-clipboard" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
          <path d="M14.25 5.25H7.25C6.14543 5.25 5.25 6.14543 5.25 7.25V14.25C5.25 15.3546 6.14543 16.25 7.25 16.25H14.25C15.3546 16.25 16.25 15.3546 16.25 14.25V7.25C16.25 6.14543 15.3546 5.25 14.25 5.25Z" />
          <path d="M2.80103 11.998L1.77203 5.07397C1.61003 3.98097 2.36403 2.96397 3.45603 2.80197L10.38 1.77297C11.313 1.63397 12.19 2.16297 12.528 3.00097" />
        </svg>
        <svg className="hf-install-copy-check" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
          <path d="M2.75 9.5L6.5 13.25L15.25 4.5" />
        </svg>
      </button>
      <span className="hf-install-copy-status" role="status" aria-live="polite">
        {copied ? "Copied" : ""}
      </span>
    </div>;
};

<iframe className="w-full aspect-video rounded-xl border-0 bg-zinc-100 dark:bg-zinc-800" title="separator preview" loading="lazy" srcDoc={`<!doctype html><html><head><meta charset="utf-8"><style>html,body{margin:0;height:100%;overflow:hidden;background:transparent}hyperframes-player{display:block;width:100%;height:100%}</style><script src="https://cdn.jsdelivr.net/npm/@hyperframes/player@0.7/dist/hyperframes-player.global.js"><\/script></head><body><script>fetch("/public/catalog/components/separator.json").then(function(r){return r.json()}).then(function(d){var p=document.createElement("hyperframes-player");p.setAttribute("srcdoc",d.html);p.setAttribute("controls","");p.setAttribute("autoplay","");p.setAttribute("loop","");p.setAttribute("muted","");p.setAttribute("poster","https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/separator.png");document.body.appendChild(p)});<\/script></body></html>`} />

## Install

<InstallCommand command="npx hyperframes add separator" />

That writes one file: `compositions/components/separator.html`.

## Paste it into your composition

Open `compositions/components/separator.html` and copy what is inside into your own composition.
The file opens with a comment header that walks you through it.

A component has no size or duration of its own. It takes both from the composition
you paste it into.

## 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                                                                     |
| ------------- | ------------ | ------------------------------ | -------------------------------------------------------------------------------- |
| `orientation` | `horizontal` | `horizontal`, `vertical`       | Which way the rule runs, and so which way the reveal travels.                    |
| `thickness`   | `hairline`   | `hairline`, `medium`, `bold`   | Size of the rule across its short edge, from a 1px hairline to a 4px bar.        |
| `tone`        | `neutral`    | `neutral`, `accent`, `warning` | Colour of the revealed fill: neutral grey, the theme accent, or the warning hue. |

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 theme={null}
<div
  data-composition-id="separator"
  data-composition-src="compositions/components/separator.html"
  data-variable-values='{"orientation":"horizontal","thickness":"hairline","tone":"neutral"}'
></div>
```

## Source

<Accordion title={`separator.html`}>
  ```html theme={null}
  <!--
    Separator - Operator Black structural rule primitive for HyperFrames.

    Paste the markup, CSS and script into a composition. Animate the CSS
    variables from a paused GSAP timeline for deterministic video renders.

    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
    or an attribute the CSS above consumes. The timeline recipe below is
    untouched by them: it still drives one progress value from 0 to 1, and these
    decide what that progress reveals.

      - orientation (horizontal | vertical, default horizontal): which way the
        rule runs. horizontal is a 360px wide rule wiping left to right,
        vertical is a 180px tall rule wiping top to bottom.
      - thickness (hairline | medium | bold, default hairline): the rule size
        across its short edge, 1px, 2px or 4px.
      - tone (neutral | accent | warning, default neutral): colour of the
        revealed fill. neutral keeps the control border grey, accent rides
        --hf-ui-accent, warning rides --hf-ui-warning.

    On every default the result is identical to the original: a 1px horizontal
    grey rule wiping left to right.
  -->

  <div
    data-hf-ui-root
    class="hf-ui-separator"
    role="separator"
    aria-orientation="horizontal"
    data-composition-variables='[
      { "id": "orientation", "type": "enum", "role": "layout", "label": "Orientation", "description": "Which way the rule runs, and so which way the reveal travels.", "default": "horizontal", "options": [{ "value": "horizontal", "label": "Horizontal" }, { "value": "vertical", "label": "Vertical" }] },
      { "id": "thickness", "type": "enum", "role": "style", "label": "Thickness", "description": "Size of the rule across its short edge, from a 1px hairline to a 4px bar.", "default": "hairline", "options": [{ "value": "hairline", "label": "Hairline" }, { "value": "medium", "label": "Medium" }, { "value": "bold", "label": "Bold" }] },
      { "id": "tone", "type": "enum", "role": "style", "label": "Tone", "description": "Colour of the revealed fill: neutral grey, the theme accent, or the warning hue.", "default": "neutral", "options": [{ "value": "neutral", "label": "Neutral" }, { "value": "accent", "label": "Accent" }, { "value": "warning", "label": "Warning" }] }
    ]'
  >
    <span></span>
  </div>

  <style>
    /* hf-ui:tokens:start */
    /* prettier-ignore */
    [data-hf-ui-root] {
      --_hf-ui-accent: var(--hf-ui-accent, #3ce6ac);
      --_hf-ui-action: var(--hf-ui-action, #eeeeee);
      --_hf-ui-action-contrast: var(--hf-ui-action-contrast, #111111);
      --_hf-ui-border: var(--hf-ui-border, #2a2a2a);
      --_hf-ui-border-strong: var(--hf-ui-border-strong, #383838);
      --_hf-ui-canvas: var(--hf-ui-canvas, #0a0a0a);
      --_hf-ui-control-border: var(--hf-ui-control-border, #686868);
      --_hf-ui-control-border-hover: var(--hf-ui-control-border-hover, #777777);
      --_hf-ui-control-height: var(--hf-ui-control-height, 40px);
      --_hf-ui-danger: var(--hf-ui-danger, #ff7878);
      --_hf-ui-data-1: var(--hf-ui-data-1, #3ce6ac);
      --_hf-ui-data-2: var(--hf-ui-data-2, #63a5ff);
      --_hf-ui-data-3: var(--hf-ui-data-3, #e9ab55);
      --_hf-ui-data-4: var(--hf-ui-data-4, #a78bfa);
      --_hf-ui-data-5: var(--hf-ui-data-5, #ff8a75);
      --_hf-ui-duration-drawer-enter: var(--hf-ui-duration-drawer-enter, 360ms);
      --_hf-ui-duration-drawer-exit: var(--hf-ui-duration-drawer-exit, 240ms);
      --_hf-ui-duration-modal-enter: var(--hf-ui-duration-modal-enter, 280ms);
      --_hf-ui-duration-modal-exit: var(--hf-ui-duration-modal-exit, 180ms);
      --_hf-ui-duration-overlay-enter: var(--hf-ui-duration-overlay-enter, 210ms);
      --_hf-ui-duration-overlay-exit: var(--hf-ui-duration-overlay-exit, 140ms);
      --_hf-ui-duration-press: var(--hf-ui-duration-press, 120ms);
      --_hf-ui-duration-state: var(--hf-ui-duration-state, 160ms);
      --_hf-ui-ease-enter: var(--hf-ui-ease-enter, cubic-bezier(0.32, 0.72, 0, 1));
      --_hf-ui-ease-exit: var(--hf-ui-ease-exit, cubic-bezier(0.23, 1, 0.32, 1));
      --_hf-ui-ease-response: var(--hf-ui-ease-response, cubic-bezier(0.23, 1, 0.32, 1));
      --_hf-ui-font-mono: var(--hf-ui-font-mono, ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace);
      --_hf-ui-font-sans: var(--hf-ui-font-sans, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
      --_hf-ui-hit-target: var(--hf-ui-hit-target, 44px);
      --_hf-ui-radius-control: var(--hf-ui-radius-control, 5px);
      --_hf-ui-radius-overlay: var(--hf-ui-radius-overlay, 10px);
      --_hf-ui-radius-surface: var(--hf-ui-radius-surface, 7px);
      --_hf-ui-shadow-contact: var(--hf-ui-shadow-contact, 0 8px 18px rgba(0, 0, 0, 0.38));
      --_hf-ui-shadow-inset: var(--hf-ui-shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.035));
      --_hf-ui-shadow-modal: var(--hf-ui-shadow-modal, 0 18px 46px rgba(0, 0, 0, 0.52));
      --_hf-ui-space-1: var(--hf-ui-space-1, 4px);
      --_hf-ui-space-12: var(--hf-ui-space-12, 48px);
      --_hf-ui-space-16: var(--hf-ui-space-16, 64px);
      --_hf-ui-space-2: var(--hf-ui-space-2, 8px);
      --_hf-ui-space-3: var(--hf-ui-space-3, 12px);
      --_hf-ui-space-4: var(--hf-ui-space-4, 16px);
      --_hf-ui-space-6: var(--hf-ui-space-6, 24px);
      --_hf-ui-space-8: var(--hf-ui-space-8, 32px);
      --_hf-ui-surface: var(--hf-ui-surface, #141414);
      --_hf-ui-surface-inset: var(--hf-ui-surface-inset, #101010);
      --_hf-ui-surface-raised: var(--hf-ui-surface-raised, #1a1a1a);
      --_hf-ui-text: var(--hf-ui-text, #e5e5e5);
      --_hf-ui-text-faint: var(--hf-ui-text-faint, #7e7e7e);
      --_hf-ui-text-muted: var(--hf-ui-text-muted, #929292);
      --_hf-ui-text-strong: var(--hf-ui-text-strong, #f3f3f3);
      --_hf-ui-warning: var(--hf-ui-warning, #e9ab55);
      --_hf-ui-weight-medium: var(--hf-ui-weight-medium, 500);
      --_hf-ui-weight-regular: var(--hf-ui-weight-regular, 400);
      --_hf-ui-weight-semibold: var(--hf-ui-weight-semibold, 600);
      box-sizing: border-box;
      color-scheme: dark;
      font-family: var(--_hf-ui-font-sans);
    }
    /* prettier-ignore */
    [data-hf-ui-root] *,
    [data-hf-ui-root] *::before,
    [data-hf-ui-root] *::after {
      box-sizing: border-box;
    }
    /* prettier-ignore */
    [data-hf-theme="light"] [data-hf-ui-root],
    [data-hf-ui-root][data-hf-theme="light"] {
      --_hf-ui-accent: var(--hf-ui-accent, #087a57);
      --_hf-ui-action: var(--hf-ui-action, #171717);
      --_hf-ui-action-contrast: var(--hf-ui-action-contrast, #ffffff);
      --_hf-ui-border: var(--hf-ui-border, #e0dfdb);
      --_hf-ui-border-strong: var(--hf-ui-border-strong, #cbc9c3);
      --_hf-ui-canvas: var(--hf-ui-canvas, #f6f5f1);
      --_hf-ui-control-border: var(--hf-ui-control-border, #888888);
      --_hf-ui-control-border-hover: var(--hf-ui-control-border-hover, #6f6e68);
      --_hf-ui-danger: var(--hf-ui-danger, #a61b1b);
      --_hf-ui-data-1: var(--hf-ui-data-1, #087a57);
      --_hf-ui-data-2: var(--hf-ui-data-2, #245ea8);
      --_hf-ui-data-3: var(--hf-ui-data-3, #8a4b00);
      --_hf-ui-data-4: var(--hf-ui-data-4, #6d3fc0);
      --_hf-ui-data-5: var(--hf-ui-data-5, #a83d2d);
      --_hf-ui-shadow-contact: var(--hf-ui-shadow-contact, 0 7px 16px rgba(26, 24, 20, 0.13));
      --_hf-ui-shadow-inset: var(--hf-ui-shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.78));
      --_hf-ui-shadow-modal: var(--hf-ui-shadow-modal, 0 18px 46px rgba(26, 24, 20, 0.18));
      --_hf-ui-surface: var(--hf-ui-surface, #ffffff);
      --_hf-ui-surface-inset: var(--hf-ui-surface-inset, #f0efeb);
      --_hf-ui-surface-raised: var(--hf-ui-surface-raised, #ffffff);
      --_hf-ui-text: var(--hf-ui-text, #171717);
      --_hf-ui-text-faint: var(--hf-ui-text-faint, #6f6e68);
      --_hf-ui-text-muted: var(--hf-ui-text-muted, #5f5f5a);
      --_hf-ui-text-strong: var(--hf-ui-text-strong, #0a0a0a);
      --_hf-ui-warning: var(--hf-ui-warning, #8a4b00);
      color-scheme: light;
    }
    /* prettier-ignore */
    [data-hf-ui-root]:focus-visible {
      outline: 2px solid var(--_hf-ui-accent);
      outline-offset: 3px;
    }
    /* prettier-ignore */
    [data-hf-rendering="true"][data-hf-ui-root],
    [data-hf-rendering="true"] [data-hf-ui-root],
    [data-hf-rendering="true"][data-hf-ui-root] *,
    [data-hf-rendering="true"] [data-hf-ui-root] *,
    [data-hf-rendering="true"][data-hf-ui-root]::before,
    [data-hf-rendering="true"][data-hf-ui-root]::after,
    [data-hf-rendering="true"] [data-hf-ui-root]::before,
    [data-hf-rendering="true"] [data-hf-ui-root]::after,
    [data-hf-rendering="true"][data-hf-ui-root] *::before,
    [data-hf-rendering="true"][data-hf-ui-root] *::after,
    [data-hf-rendering="true"] [data-hf-ui-root] *::before,
    [data-hf-rendering="true"] [data-hf-ui-root] *::after {
      animation-duration: 0s !important;
      animation-delay: 0s !important;
      transition-duration: 0s !important;
      transition-delay: 0s !important;
    }
    /* prettier-ignore */
    @media (prefers-reduced-motion: reduce) {
      [data-hf-ui-root],
      [data-hf-ui-root] *,
      [data-hf-ui-root] *::before,
      [data-hf-ui-root] *::after {
        animation-duration: 0s !important;
        animation-delay: 0s !important;
        transition-duration: 0s !important;
        transition-delay: 0s !important;
        scroll-behavior: auto !important;
      }
    }
    /* hf-ui:tokens:end */
    .hf-ui-separator {
      --hf-separator-progress: 1;
      width: min(360px, 100%);
      height: var(--hf-separator-thickness, 1px);
      background: var(--_hf-ui-border);
      overflow: hidden;
    }
    .hf-ui-separator span {
      display: block;
      width: calc(var(--hf-separator-progress) * 100%);
      height: 100%;
      background: var(--hf-separator-fill, var(--_hf-ui-control-border));
      transform-origin: left center;
    }
    .hf-ui-separator[data-orientation="vertical"] {
      width: var(--hf-separator-thickness, 1px);
      height: 180px;
    }
    .hf-ui-separator[data-orientation="vertical"] span {
      width: 100%;
      height: calc(var(--hf-separator-progress) * 100%);
    }
  </style>

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

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

      // Unrecognised overrides return to their declared defaults.
      var orientations = { horizontal: true, vertical: true };
      var thicknesses = { hairline: "1px", medium: "2px", bold: "4px" };
      var tones = {
        neutral: "var(--_hf-ui-control-border)",
        accent: "var(--_hf-ui-accent)",
        warning: "var(--_hf-ui-warning)",
      };

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

      var orientation = pick(orientations, vars.orientation, "horizontal");
      var thickness = thicknesses[pick(thicknesses, vars.thickness, "hairline")];
      var tone = tones[pick(tones, vars.tone, "neutral")];

      var roots = document.querySelectorAll(".hf-ui-separator");
      for (var i = 0; i < roots.length; i += 1) {
        roots[i].setAttribute("data-orientation", orientation);
        roots[i].setAttribute("aria-orientation", orientation);
        roots[i].style.setProperty("--hf-separator-thickness", thickness);
        roots[i].style.setProperty("--hf-separator-fill", tone);
      }
    })();
  </script>

  <!--
    Timeline integration:
    tl.fromTo('.hf-ui-separator', { '--hf-separator-progress': 0 }, { '--hf-separator-progress': 1, duration: 0.42, ease: 'power3.out' }, startTime);
  -->
  ```
</Accordion>

Tagged `video-primitive` `remocn-port` `separator` `layout`.

## Related topics

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


## Related topics

- [News Ticker](/catalog/blocks/news-ticker.md)
- [Liquid Background](/catalog/blocks/vfx-liquid-background.md)
- [Spiral Galaxy](/catalog/blocks/spiral-galaxy.md)
