Files
zooqueen 75094e0d60 frames: publish the toolchain as @hanzo/frames
@hanzo/frame is taken by the hero video primitive — one full-bleed video
element — which has held that name on npm since it shipped. This repo is the
video toolchain: a CLI, a renderer, a studio, a player. Plural is what it is,
so the CLI publishes as @hanzo/frames and the workspace packages follow it
(@hanzo/frames-core, @hanzo/frames-engine, and the rest).

The binary stays `frames`, and now actually ships. The manifest mapped it to
bin/frames.mjs while the file on disk was bin/hyperframes.mjs, so a global
install produced no working command.

The paths that name a package to fetch were pointing elsewhere. The update
check read registry.npmjs.org/frames, a different author's package, and the
npm, bun and pnpm installers would have pulled it over the CLI; the render
image installed the upstream hyperframes; scaffolded projects and the docs
pinned the unscoped name. All of them now name @hanzo/frames.
2026-08-13 18:10:14 -07:00

71 lines
2.5 KiB
Plaintext

---
title: "Motion Blur"
description: "Velocity-driven directional motion blur — samples element position each frame and applies a one-sided ghost trail proportional to speed"
---
# Motion Blur
Velocity-driven directional motion blur — samples element position each frame and applies a one-sided ghost trail proportional to speed.
`effect` `motion-blur` `velocity` `animation` `physics`
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="/images/catalog/components/motion-blur.mp4" poster="/images/catalog/components/motion-blur.png" autoPlay muted loop playsInline />
## Install
<CodeGroup>
```bash Terminal
npx @hanzo/frames add motion-blur
```
</CodeGroup>
## Details
| Property | Value |
| --- | --- |
| Type | Component |
## Files
| File | Target | Type |
| --- | --- | --- |
| `motion-blur.html` | `compositions/components/motion-blur.html` | frames:snippet |
## Usage
Paste the snippet into your composition, then call `attachMotionBlur()` after your GSAP tweens and before registering `window.__timelines`.
```html
<!-- Extend the timeline to data-duration before calling attachMotionBlur -->
tl.set(document.body, {}, DATA_DURATION);
attachMotionBlur("#my-box", tl, {
axis: "x", // "x" | "y" | "both"
blurMax: 40, // max blur radius in px (default 20)
});
window.__timelines = window.__timelines || {};
window.__timelines["my-composition"] = tl;
```
## How it works
Each target element gets its own SVG filter. On every timeline seek, `attachMotionBlur` samples the element's GSAP `x`/`y` position, computes velocity, and drives three SVG filter primitives:
1. **Ghost copies** — three faded, blurred copies of the element placed behind it at increasing offsets proportional to speed. Inherently one-sided: no forward blur.
2. **Top blur** — a small symmetric Gaussian at the current position so the element looks in-motion rather than crisp on top of the trail.
Blur scales linearly with velocity up to `blurMax`. Both the ghost trail and top blur clear automatically when the element decelerates to rest.
## Options
| Option | Default | Description |
| --- | --- | --- |
| `axis` | `"both"` | Motion axis — `"x"`, `"y"`, or `"both"` |
| `blurScale` | `0.008` | Blur per px/s of velocity |
| `blurMax` | `20` | Max blur radius on the motion axis (px) |
| `stretchScale` | `0.0002` | scaleX/Y added per px/s (requires `stretchMax > 0`) |
| `stretchMax` | `0` | Max stretch above 1.0 — disabled by default |