> ## 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.

# Beat Pulse Background

> An accent-derived backdrop pulses its glow intensity and saturation on a deterministic, supplied beat grid.

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="beat-pulse-background 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/beat-pulse-background.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/beat-pulse-background.png");document.body.appendChild(p)});<\/script></body></html>`} />

## Install

<InstallCommand command="npx hyperframes add beat-pulse-background" />

That writes one file: `compositions/components/beat-pulse-background.html`.

## Paste it into your composition

Open `compositions/components/beat-pulse-background.html` and copy what is inside into your own composition.

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                                                                                                                   |
| ----------- | ----------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `beats`     | `0.5,1.0,1.5,2.0,2.5,3.0,3.5` | string                    | Comma-separated beat times in seconds. Invalid entries are ignored and numeric values are clamped to the composition duration. |
| `accent`    | `green`                       | `green`, `blue`, `violet` | Accent token family used by the pulsing glow.                                                                                  |
| `intensity` | `subtle`                      | `subtle`, `club`          | Strength of the glow and saturation pulse.                                                                                     |

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="beat-pulse-background"
  data-composition-src="compositions/components/beat-pulse-background.html"
  data-variable-values='{"beats":"0.5,1.0,1.5,2.0,2.5,3.0,3.5","accent":"green","intensity":"subtle"}'
></div>
```

## Source

<Accordion title={`beat-pulse-background.html`}>
  ```html theme={null}
  <!doctype html>
  <!--
    beat-pulse-background: HyperFrames video primitive (backgrounds / rhythmic)

    Concept: a deep accent-derived backdrop pulses its glow intensity and
    saturation on a supplied beat grid. Each retained beat owns one fast attack
    and one slower decay. The pulses stay tasteful enough to carry foreground
    content without reading as a strobe.

    Variables:
      - beats (string, default "0.5,1.0,1.5,2.0,2.5,3.0,3.5"): comma-separated
        beat times in seconds. Junk and blank entries are ignored. Numeric times
        are clamped to the composition duration.
      - accent (green | blue | violet, default green): pulse color family.
      - intensity (subtle | club, default subtle): glow and saturation strength.

    Envelope: IN = 0, HOLD = the full elastic duration, OUT = 0. Beat times are
    absolute data inside HOLD, so a longer mount extends HOLD without retiming
    the supplied grid. Every pulse is constructed synchronously as one attack
    and one decay tween pair.

    Sound: none. Beats are supplied data, not audio analysis.

    Mount contract: the runtime clones only this template. #root fills the host
    box, establishes the container query basis, has no data-width or data-height,
    and registers one paused timeline under the hardcoded beat-pulse-background
    id.
  -->
  <html
    lang="en"
    data-composition-id="beat-pulse-background"
    data-composition-duration="4"
    data-composition-variables='[
      { "id": "beats", "type": "string", "role": "timing", "label": "Beats", "description": "Comma-separated beat times in seconds. Invalid entries are ignored and numeric values are clamped to the composition duration.", "default": "0.5,1.0,1.5,2.0,2.5,3.0,3.5" },
      { "id": "accent", "type": "enum", "role": "style", "label": "Accent", "description": "Accent token family used by the pulsing glow.", "default": "green", "options": [{ "value": "green", "label": "Green" }, { "value": "blue", "label": "Blue" }, { "value": "violet", "label": "Violet" }] },
      { "id": "intensity", "type": "enum", "role": "style", "label": "Intensity", "description": "Strength of the glow and saturation pulse.", "default": "subtle", "options": [{ "value": "subtle", "label": "Subtle" }, { "value": "club", "label": "Club" }] }
    ]'
  >
    <head>
      <meta charset="UTF-8" />
      <title>Beat Pulse Background</title>
    </head>
    <body>
      <template>
        <div id="root" data-composition-id="beat-pulse-background" data-duration="4" data-fps="30">
          <style>
            *,
            *::before,
            *::after {
              box-sizing: border-box;
            }

            #root {
              position: absolute;
              inset: 0;
              overflow: hidden;
              container-type: size;
              isolation: isolate;
              pointer-events: none;
            }

            .bpb-clip,
            .bpb-base,
            .bpb-pulse,
            .bpb-vignette {
              position: absolute;
              inset: 0;
            }

            .bpb-clip {
              overflow: hidden;
            }

            .bpb-base {
              background:
                radial-gradient(
                  ellipse at 50% 42%,
                  color-mix(in srgb, var(--bpb-accent) 10%, var(--bg, #070a12)) 0%,
                  var(--bg, #070a12) 70%
                ),
                var(--bg, #070a12);
            }

            .bpb-pulse {
              background:
                radial-gradient(
                  ellipse at 24% 30%,
                  color-mix(in srgb, var(--bpb-accent) 74%, transparent) 0%,
                  color-mix(in srgb, var(--bpb-accent) 28%, transparent) 34%,
                  transparent 66%
                ),
                radial-gradient(
                  ellipse at 76% 68%,
                  color-mix(in srgb, var(--bpb-accent) 60%, var(--accent-2, #a78bfa)) 0%,
                  color-mix(in srgb, var(--bpb-accent) 20%, transparent) 38%,
                  transparent 70%
                );
              filter: saturate(var(--bpb-saturation, 1));
              mix-blend-mode: screen;
              opacity: 0.2;
              will-change: opacity, filter;
            }

            .bpb-vignette {
              background: radial-gradient(
                ellipse at center,
                transparent 34%,
                color-mix(in srgb, var(--bg, #000000) 58%, transparent) 100%
              );
            }
          </style>

          <div
            id="beat-pulse-background-clip"
            class="bpb-clip clip"
            data-start="0"
            data-duration="4"
            data-track-index="0"
          >
            <div class="bpb-base"></div>
            <div class="bpb-pulse"></div>
            <div class="bpb-vignette"></div>
          </div>

          <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
          <script>
            (function () {
              "use strict";

              var root = document.getElementById("root");
              var pulse = root.querySelector(".bpb-pulse");
              var vars =
                window.__hyperframes && window.__hyperframes.getVariables
                  ? window.__hyperframes.getVariables()
                  : {};

              var accentTokens = {
                green: "var(--brand, #34d399)",
                blue: "var(--accent, #38bdf8)",
                violet: "var(--accent-2, #a78bfa)",
              };
              var intensityLevels = {
                subtle: { baseOpacity: 0.2, peakOpacity: 0.5, peakSaturation: 1.3 },
                club: { baseOpacity: 0.26, peakOpacity: 0.72, peakSaturation: 1.65 },
              };
              var accent = Object.prototype.hasOwnProperty.call(accentTokens, vars.accent)
                ? vars.accent
                : "green";
              var intensity = vars.intensity === "club" ? "club" : "subtle";
              var level = intensityLevels[intensity];

              root.style.setProperty("--bpb-accent", accentTokens[accent]);

              var durationValue = Number(root.dataset.duration);
              var duration = Number.isFinite(durationValue) && durationValue > 0 ? durationValue : 4;
              var defaultBeats = "0.5,1.0,1.5,2.0,2.5,3.0,3.5";
              var beatsValue = vars.beats == null ? defaultBeats : String(vars.beats);
              var beats = beatsValue.split(",").reduce(function (result, token) {
                var trimmed = token.trim();
                if (trimmed === "") return result;

                var seconds = Number(trimmed);
                if (!Number.isFinite(seconds)) return result;

                result.push(Math.max(0, Math.min(duration, seconds)));
                return result;
              }, []);

              var ATTACK = 0.08;
              var DECAY = 0.36;

              gsap.set(pulse, { opacity: level.baseOpacity, "--bpb-saturation": 1 });

              var tl = gsap.timeline({ paused: true });

              beats.forEach(function (beat) {
                tl.to(
                  pulse,
                  {
                    opacity: level.peakOpacity,
                    "--bpb-saturation": level.peakSaturation,
                    duration: ATTACK,
                    ease: "expo.out",
                  },
                  beat,
                );
                tl.to(
                  pulse,
                  {
                    opacity: level.baseOpacity,
                    "--bpb-saturation": 1,
                    duration: DECAY,
                    ease: "power2.in",
                  },
                  beat + ATTACK,
                );
              });

              tl.seek(0);

              window.__timelines = window.__timelines || {};
              window.__timelines["beat-pulse-background"] = tl;
            })();
          </script>
        </div>
      </template>
    </body>
  </html>
  ```
</Accordion>

Tagged `motion-primitive` `background` `beat` `pulse` `rhythmic` `reactive`.

## 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

- [Beat Accent](/catalog/components/beat-accent.md)
- [Icon Morph Beat](/catalog/components/icon-morph-beat.md)
- [Vocabulary that changes output](/prompting/vocabulary.md)
