X-Ray Scan
A glowing scanner bar sweeps across a device and reveals its white-line internals, with one part marked in red
$ pnpm dlx shadcn@latest add @remocn/x-ray-scanUsage
XRayScan is a full-frame scene. It starts on the outside of a device. A thin
glowing bar sweeps across it, and behind the bar the shell is gone: the device
shows as white linework on a dark plate, with one part highlighted in the
accent color. A freshly exposed band just behind the bar glows brighter and
fades as the bar moves on.
import { XRayScan } from "@/components/remocn/x-ray-scan";
export const Inside = () => <XRayScan />;Without outside and inside it draws the back of a phone and its internals:
the camera array, the logic board with the SoC in the accent color, the
battery with a wireless charging coil, and the speaker grille. direction
picks a left-to-right or a top-to-bottom sweep.
Your own layers
Pass outside and inside to scan your own product. Both are full-frame
layers stacked on each other, so draw them in the same coordinates, for
example as two aligned images.
import { AbsoluteFill, Img, staticFile } from "remotion";
import { XRayScan } from "@/components/remocn/x-ray-scan";
export const Watch = () => (
<XRayScan
direction="vertical"
outside={
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
<Img src={staticFile("watch-front.png")} style={{ height: 560 }} />
</AbsoluteFill>
}
inside={
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
<Img src={staticFile("watch-xray.png")} style={{ height: 560 }} />
</AbsoluteFill>
}
/>
);The sweep is sized to the default device, a centered box 80% of the frame height tall and about 39% of the height wide. The bar starts 12% of the frame width before that box and stops 12% past it, or 10% of the frame height for a vertical sweep. Content outside that span never changes: before the start it shows the inside layer from the first frame, and past the end it keeps the outside layer. Keep custom products centered and about that size.
Timing
At 30 fps and speed={1}:
| Frames | Motion |
|---|---|
| 0–5 | The outside of the device holds |
| 5–32 | The bar sweeps across on an ease-in-out, revealing the inside |
| 32+ | The bar is gone and the inside holds |
xRayScanLength is 32. speed scales the sweep.
Notes
The inside layer renders twice: once as the revealed view and once under a
glow filter for the bright band behind the bar. Heavy custom inside content
costs twice.
| Prop | Type | Default | Description |
|---|---|---|---|
outside | React.ReactNode | — | Full-frame exterior shown ahead of the bar. Defaults to the back of a phone |
inside | React.ReactNode | — | Full-frame interior revealed behind the bar. Defaults to white-line phone internals |
direction | "horizontal" | "vertical" | "horizontal" | Horizontal sweeps left to right, vertical sweeps top to bottom |
shell | string | "#E5322D" | Shell of the default device. Overrides colors.shell when set |
accent | string | "#E5322D" | Highlighted part inside the default device. Overrides colors.accent when set |
line | string | "#FFFFFF" | Interior linework and the scan bar. Overrides colors.line when set |
background | string | "#111111" | Frame background. Overrides colors.background when set |
colors | { background?, shell?, detail?, xray?, line?, accent?: string } | { background: "#111111", shell: "#E5322D", detail: "#111111", xray: "#07080A", line: "#FFFFFF", accent: "#E5322D" } | All colors as one object: frame background, default shell and its camera bump, x-ray plate, linework and scan bar, highlighted part. The flat props above take precedence, missing keys keep their defaults; shell, detail, xray and accent only affect the default device |
speed | number | 1 | Playback multiplier |