Soft blur in
Content fades in from a soft blur.
Customize
import {Scene, Video} from "odori";
import {SoftBlurIn} from "../components/soft-blur-in/soft-blur-in";
<Video>
<Scene id="soft-blur-in" duration="4s">
<SoftBlurIn
title="Built for focus."
detail="Everything you need, nothing you do not."
blur={26}
/>
</Scene>
</Video>Installation
pnpm odori add component soft-blur-innpx odori add component soft-blur-inbunx odori add component soft-blur-inEdit the source in videos/components/soft-blur-in/. Use odori diff to compare upstream changes and odori update to apply updates.
Copy these files into your project
videos/components/soft-blur-in/soft-blur-in.tsx
import {Fill, Easing, interpolate, useBrand, useFrame, useDesignScale} from "odori";
export type SoftBlurInProps = {
title: string;
detail?: string;
/** Blur radius at the start of the reveal, in design pixels. */
blur?: number;
};
/**
* A restrained opening: the headline resolves out of a blur while it settles
* a few pixels upward. Useful when a hard word stagger would feel too busy.
*/
export const SoftBlurIn = ({title, detail, blur = 26}: SoftBlurInProps) => {
const frame = useFrame();
const brand = useBrand();
const scale = useDesignScale();
const progress = interpolate(frame, [0, 34], [0, 1], {easing: Easing.standard});
const detailProgress = interpolate(frame, [18, 46], [0, 1], {easing: Easing.standard});
return (
<Fill
style={{
alignItems: "center",
gap: 32 * scale,
justifyContent: "center",
padding: `${120 * scale}px ${160 * scale}px`,
textAlign: "center",
}}
>
<div
style={{
filter: `blur(${(1 - progress) * blur * scale}px)`,
fontSize: 124 * scale,
fontWeight: 560,
letterSpacing: "-0.05em",
lineHeight: 1.04,
maxWidth: 1500 * scale,
opacity: progress,
transform: `translateY(${(1 - progress) * 26 * scale}px) scale(${0.98 + progress * 0.02})`,
}}
>
{title}
</div>
{detail ? (
<div
style={{
color: brand.colors.muted,
filter: `blur(${(1 - detailProgress) * 10 * scale}px)`,
fontSize: 36 * scale,
maxWidth: 1100 * scale,
opacity: detailProgress,
}}
>
{detail}
</div>
) : null}
</Fill>
);
};
videos/components/soft-blur-in/soft-blur-in.preview.tsx
import {defineComponentPreview} from "odori/preview";
import {SoftBlurIn} from "./soft-blur-in";
export default defineComponentPreview({
title: "Soft blur in",
category: "Typography/Titles",
description: "Content fades in from a soft blur.",
component: SoftBlurIn,
canvas: {width: 1920, height: 1080, duration: "4s"},
controls: {
title: {type: "text", defaultValue: "Built for focus.", maxLength: 64},
detail: {type: "text", defaultValue: "Everything you need, nothing you do not."},
blur: {type: "number", defaultValue: 26, min: 0, max: 60},
},
examples: [
{name: "Default", props: {title: "Built for focus."}},
{name: "Subtle", props: {title: "Quietly precise.", blur: 10}},
],
});
Add it to a scene
import {Scene, Video} from "odori";
import {SoftBlurIn} from "../components/soft-blur-in/soft-blur-in";
<Video>
<Scene id="soft-blur-in" duration="4s">
<SoftBlurIn
title="Built for focus."
detail="Everything you need, nothing you do not."
blur={26}
/>
</Scene>
</Video>Timing contract
Use these durations and content limits when composing a scene. Run odori test to check your video.
- Family
- Typography
- Recommended duration
- 120 frames · 4s
- Minimum duration
- 45 frames · 1.5s
- Entrance
- 34 frames
- Exit
- 10 frames
- Reduced motion
- fades without blur
- Requires
- sans font
- Content limits
- title ≤ 64, detail ≤ 96
Props
| Prop | Type | Default | Required |
|---|---|---|---|
title | string | — | Yes |
detail | string | — | — |
blurBlur radius at the start of the reveal, in design pixels. | number | 26 | — |
Related components
All componentsCaptionsFrame-accurate caption cues for sound-off playback.Character riseCharacters rise with a crisp per-letter stagger.Draw titleAn outline draws across the line, then fills solid.Flap boardA split-flap board clatters through to the target string.Focus inWords settle from a soft blur into a crisp line.Glitch textA title that arrives through brief seeded interference bursts.