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

# Sheet Spring-Up

> A bottom sheet rushes up from below the frame on a real spring sampled frame by frame from reference footage, overshooting its resting place and settling back without an approximated ease

# Sheet Spring-Up

A bottom sheet rushes up from below the frame on a real spring sampled frame by frame from reference footage, overshooting its resting place and settling back without an approximated ease

**Sheet Spring-Up**

```html sheet-spring-up.html theme={null}
<!--
  Sheet Spring-Up - bottom-sheet arrival primitive.

  Paste the markup, CSS and script into a composition. Use the timeline
  integration note at the bottom as the starting point for deterministic GSAP
  animation.

  The motion is a real spring, sampled frame by frame from reference footage
  rather than approximated with an ease: the sheet rushes up from below the
  frame, overshoots its resting place by 192px, and settles back over 0.72s.
  The integration note carries the full sampled table; play it verbatim and
  you get the reference feel, retime it proportionally and it stays a spring.

  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 below consumes. The spring table is untouched by them.

    - width (400 to 900, default 668, in px): sheet width.
    - radius (16 to 48, default 34, in px): sheet corner radius.
    - tone (light | dark, default light): light is the reference's near-white
      sheet; dark is the raised surface token for dark compositions.

  On every default the result matches the measured reference: a 668px light
  sheet with 34px corners.
-->

<div
  data-hf-ui-root
  class="hf-ui-sheet-spring-up"
  aria-label="Bottom sheet arriving"
  data-composition-variables='[
    { "id": "width", "type": "number", "role": "style", "label": "Width", "description": "Sheet width in pixels.", "default": 668, "min": 400, "max": 900, "step": 4, "unit": "px" },
    { "id": "radius", "type": "number", "role": "style", "label": "Radius", "description": "Sheet corner radius.", "default": 34, "min": 16, "max": 48, "step": 1, "unit": "px" },
    { "id": "tone", "type": "enum", "role": "style", "label": "Tone", "description": "Light is the reference near-white sheet; dark is the raised surface token.", "default": "light", "options": [{ "value": "light", "label": "Light" }, { "value": "dark", "label": "Dark" }] }
  ]'
>
  <div class="hf-ssu-sheet" id="hf-ssu-sheet-1">
    <div class="hf-ssu-title">Share</div>
    <div class="hf-ssu-body">Sheet content goes here.</div>
  </div>
</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;
  }
  /* hf-ui:tokens:end */

  .hf-ui-sheet-spring-up {
    position: relative;
  }
  .hf-ssu-sheet {
    position: relative;
    width: var(--hf-ssu-width, 668px);
    border-radius: var(--hf-ssu-radius, 34px);
    background: var(--hf-ssu-surface, #f9f9f9);
    color: var(--hf-ssu-ink, #101010);
    box-shadow: 0 18px 42px rgba(0, 0, 0, 0.28);
    padding: 49px 43px 43px;
    will-change: opacity, transform;
  }
  .hf-ssu-title {
    text-align: center;
    font-size: 44px;
    font-weight: var(--_hf-ui-weight-semibold);
    line-height: 1;
    letter-spacing: 0.2px;
  }
  .hf-ssu-body {
    margin-top: 24px;
    text-align: center;
    font-size: 29px;
    color: var(--hf-ssu-ink-muted, #313131);
  }
</style>

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

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

    // Unrecognised overrides return to their declared defaults.
    function pick(table, value, fallback) {
      return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
    }

    function clampNumber(value, min, max, fallback) {
      var n = typeof value === "number" ? value : parseFloat(value);
      if (!isFinite(n)) {
        return fallback;
      }
      return Math.min(max, Math.max(min, n));
    }

    var tones = {
      light: { surface: "#f9f9f9", ink: "#101010", inkMuted: "#313131" },
      dark: {
        surface: "var(--_hf-ui-surface-raised)",
        ink: "var(--_hf-ui-text-strong)",
        inkMuted: "var(--_hf-ui-text-muted)",
      },
    };

    var width = clampNumber(vars.width, 400, 900, 668);
    var radius = clampNumber(vars.radius, 16, 48, 34);
    var tone = tones[pick(tones, vars.tone, "light")];

    var roots = document.querySelectorAll(".hf-ui-sheet-spring-up");
    for (var i = 0; i < roots.length; i += 1) {
      roots[i].style.setProperty("--hf-ssu-width", width + "px");
      roots[i].style.setProperty("--hf-ssu-radius", radius + "px");
      roots[i].style.setProperty("--hf-ssu-surface", tone.surface);
      roots[i].style.setProperty("--hf-ssu-ink", tone.ink);
      roots[i].style.setProperty("--hf-ssu-ink-muted", tone.inkMuted);
    }
  })();
</script>

<!--
  Timeline integration - the spring, sampled frame by frame from reference
  footage. Offsets are seconds from the arrival beat; y is px relative to the
  resting place (positive = below); the third value fades the sheet in while
  it travels and stops mattering once it hits 1.

  var SPRING = [
    [0.000, 1450, 0.00], [0.057, 1198, 0.13], [0.090, 903, 0.21],
    [0.123, 648, 0.36], [0.157, 437, 0.43], [0.190, 262, 0.50],
    [0.223, 120, 0.62], [0.257, 8, 0.78], [0.290, -76, 0.89],
    [0.323, -138, 1.00], [0.357, -175, null], [0.390, -191, null],
    [0.423, -192, null], [0.457, -181, null], [0.490, -159, null],
    [0.523, -131, null], [0.557, -100, null], [0.590, -68, null],
    [0.623, -41, null], [0.657, -18, null], [0.690, -5, null],
    [0.723, 0, null],
  ];
  SPRING.forEach(function (s) {
    var props = { y: s[1] };
    if (s[2] !== null) props.autoAlpha = s[2];
    tl.set('#hf-ssu-sheet-1', props, startTime + s[0]);
  });
-->
```

Copy npx hyperframes add sheet-spring-up to the clipboard

That writes one file: `compositions/components/sheet-spring-up.html`.

## Paste it into your composition

Open `compositions/components/sheet-spring-up.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 |
| - | - | - | - |
| `width` | `668` | 400px to 900px, step 4px | Sheet width in pixels. |
| `radius` | `34` | 16px to 48px, step 1px | Sheet corner radius. |
| `tone` | `light` | `light`, `dark` | Light is the reference near-white sheet; dark is the raised surface token. |

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="sheet-spring-up"
  data-composition-src="compositions/components/sheet-spring-up.html"
  data-variable-values='{"width":668,"radius":34,"tone":"light"}'
></div>
```

Tagged `video-primitive` `sheet` `spring` `mock-ui` `overlay`.

Created by Miao Yang.

## Related topics

* [Browse the complete Catalog](/catalog.md)
* [Add assets and Catalog items in the browser editor](/studio/assets-and-blocks.md)
* [Put blocks together into one video](/concepts/compositions.md)


## Related topics

- [Share-Sheet Carousel](/catalog/blocks/share-sheet-carousel.md)
- [Spring Stack Shuffle](/catalog/components/spring-stack-shuffle.md)
- [Count Up](/catalog/components/count-up.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.