absolute-stage
Full-frame surface with stable clipping and positioning.
import {Scene, Video} from "odori";
import {AbsoluteStage} from "../components/absolute-stage/absolute-stage";
<Video>
<Scene id="absolute-stage" duration="3s">
<AbsoluteStage
align="center"
padding={120}
showBounds={true}
/>
</Scene>
</Video>The same runtime that renders the export. Scrub to any frame, switch format, and edit the fixture props.
Installation
pnpm odori add @odori/absolute-stagenpx odori add @odori/absolute-stagebunx odori add @odori/absolute-stageSource is copied into videos/components/absolute-stage/ and belongs to your repository. odori diff compares it with upstream later; odori update applies the change you accept. It has no registry dependencies.
Copy and paste the following code into your project.
videos/components/absolute-stage/absolute-stage.tsx
import type {CSSProperties, ReactNode} from "react";
import {Fill, useBrand, useDesignScale, useVideo} from "odori";
export type AbsoluteStageProps = {
children?: ReactNode;
/** Where the content sits inside the frame. */
align?: "center" | "start" | "end";
/** Inset from the frame edge, in design pixels. */
padding?: number;
/** Draw the frame edge, useful while composing. */
showBounds?: boolean;
style?: CSSProperties;
};
/**
* The plainest full-frame surface: predictable clipping, one alignment
* decision, and padding that scales with the format. Reach for this when a
* scene needs structure without the grid and glow of the branded stage.
*/
export const AbsoluteStage = ({children, align = "center", padding = 120, showBounds = false, style}: AbsoluteStageProps) => {
const brand = useBrand();
const scale = useDesignScale();
const {width, height} = useVideo();
return (
<Fill style={{background: brand.colors.background, overflow: "hidden", ...style}}>
<Fill
style={{
alignItems: "center",
display: "flex",
justifyContent: align === "center" ? "center" : align === "start" ? "flex-start" : "flex-end",
flexDirection: "column",
padding: padding * scale,
}}
>
{children}
</Fill>
{showBounds ? (
<Fill
style={{
border: `${2 * scale}px dashed ${brand.colors.border}`,
inset: padding * scale,
pointerEvents: "none",
}}
>
<span
style={{
color: brand.colors.muted,
fontFamily: brand.typography.mono,
fontSize: 22 * scale,
padding: 12 * scale,
}}
>
{width} x {height}
</span>
</Fill>
) : null}
</Fill>
);
};
videos/components/absolute-stage/absolute-stage.preview.tsx
import {defineComponentPreview} from "odori/preview";
import {AbsoluteStage} from "./absolute-stage";
export default defineComponentPreview({
title: "Absolute stage",
category: "Foundation",
description: "Full-frame surface with stable clipping and positioning.",
component: AbsoluteStage,
canvas: {width: 1920, height: 1080, duration: "3s"},
controls: {
align: {type: "select", defaultValue: "center", options: ["center", "start", "end"]},
padding: {type: "number", defaultValue: 120, min: 0, max: 320},
showBounds: {type: "boolean", defaultValue: true},
},
examples: [
{name: "Bounds", props: {showBounds: true, children: "Content sits here"}},
{name: "Clean", props: {showBounds: false, children: "Content sits here"}},
],
});
Use it in a scene.
import {Scene, Video} from "odori";
import {AbsoluteStage} from "../components/absolute-stage/absolute-stage";
<Video>
<Scene id="absolute-stage" duration="3s">
<AbsoluteStage
align="center"
padding={120}
showBounds={true}
/>
</Scene>
</Video>Nothing else to install.
The component imports only from odori, so there are no dependencies to add and no import paths to rewrite.
Timing contract
Every registry component declares how it behaves in time.odori test fails a cut that violates these.
- Family
- Foundation
- Aspect ratios
- 16:9 · 9:16 · 1:1
- Recommended duration
- 90 frames · 3s
- Minimum duration
- 24 frames · 0.8s
- Entrance
- 0 frames
- Exit
- 0 frames
- Reduced motion
- no motion of its own
- Requires
- sans font
- Content limits
- none
Props
| Prop | Type | Default | Required |
|---|---|---|---|
children | ReactNode | — | — |
alignWhere the content sits inside the frame. | "center" | "start" | "end" | "center" | — |
paddingInset from the frame edge, in design pixels. | number | 120 | — |
showBoundsDraw the frame edge, useful while composing. | boolean | false | — |
style | CSSProperties | — | — |