About
An image reveal for generation progress. A one bit stencil rises out of the paper as the threshold drops, then tone floods in from the shadows until the image is done. Works in light and dark.
Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Threshold Reveal to your project and fits it to your theme.
Code
How Threshold Reveal is used: the demo's code. The component's own source comes with a free account.
Usage.tsx
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
import { Toggle } from "@base-ui/react/toggle"
import { ToggleGroup } from "@base-ui/react/toggle-group"
import { Button, RotateCcwIcon, ThresholdReveal } from "@/components/ui/threshold-reveal"
/** A run counter: bump it to remount a reveal and play it again from the first frame. */
function useRun() {
const [run, setRun] = React.useState(0)
return [run, React.useCallback(() => setRun((n) => n + 1), [])] as const
}
interface SimulatedJob {
/** 0 to 1, or null before the first step reports. */
progress: number | null
step: number
total: number
running: boolean
start: () => void
}
/**
* A generation job on a script: queued for a beat with no numbers, then diffusion steps that
* arrive every 60 to 170 ms, one stall of about a second, then done.
*/
function useSimulatedJob({ total = 30, autoStart = true, seed = 7 } = {}): SimulatedJob {
const [step, setStep] = React.useState(-1)
const [runId, setRunId] = React.useState(autoStart ? 1 : 0)
React.useEffect(() => {
if (!runId) return
let alive = true
let s = -1
let r = (seed * 9301 + runId * 49297) % 233280
const rand = () => {
r = (r * 9301 + 49297) % 233280
return r / 233280
}
setStep(-1)
const tick = () => {
if (!alive || s >= total) return
s += 1
setStep(s)
const stall = s === Math.round(total * 0.62) ? 900 : 0
timer = window.setTimeout(tick, 60 + rand() * 110 + stall)
}
let timer = window.setTimeout(tick, 700)
return () => {
alive = false
window.clearTimeout(timer)
}
}, [runId, total, seed])
// Reset the step in the same render as the new run, so a remounted reveal never sees the old 100%.
const start = React.useCallback(() => {
setStep(-1)
setRunId((n) => n + 1)
}, [])
return {
progress: step < 0 ? null : step / total,
step: Math.max(0, step),
total,
running: runId > 0 && step < total,
start,
}
}
function ReplayButton({
onClick,
label = "Replay reveal",
className,
}: {
onClick: () => void
label?: string
className?: string
}) {
return (
<Button variant="outline" size="sm" onClick={onClick} className={className}>
<RotateCcwIcon aria-hidden />
{label}
</Button>
)
}
/** Media on top, an optional caption, then controls with the replay button at the end. */
function DemoShell({
media,
caption,
controls,
onReplay,
replayLabel,
className,
}: {
media: React.ReactNode
caption?: React.ReactNode
controls?: React.ReactNode
onReplay: () => void
replayLabel?: string
className?: string
}) {
return (
<div className={cn("flex w-full max-w-md flex-col gap-4", className)}>
{media}
{caption}
<div className="flex flex-wrap items-end justify-between gap-3">
<div className="flex flex-wrap items-end gap-x-4 gap-y-3">{controls}</div>
<ReplayButton onClick={onReplay} label={replayLabel} />
</div>
</div>
)
}
// The photo ships inline (picsum.photos id 1027, 800 x 1000), so the preview needs no image host.
const PORTRAIT_SRC =
"data:image/webp;base64,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"
/** Prompt and job line under a generation. Numbers are tabular so the line never jitters. */
function GenerationCaption({
prompt,
job,
className,
}: {
prompt: string
job: SimulatedJob
className?: string
}) {
const label =
job.progress === null && job.running
? "Queued"
: job.running
? `Step ${job.step} of ${job.total}`
: "Done"
return (
<div className={cn("flex min-w-0 items-baseline justify-between gap-4", className)}>
<p className="text-[0.8125rem]/[1.25rem] text-(color:--chatcn-fg-muted) min-w-0 truncate">{prompt}</p>
<span className="text-[0.75rem]/[1rem] text-(color:--chatcn-fg-subtle) shrink-0 tabular-nums">{label}</span>
</div>
)
}
/** A labeled segmented control on Base UI ToggleGroup. One value is always selected. */
function Segmented<T extends string>({
label,
value,
onValueChange,
options,
className,
}: {
label: string
value: T
onValueChange: (value: T) => void
options: readonly { value: T; label: string }[]
className?: string
}) {
return (
<div className={cn("flex min-w-0 flex-col gap-1.5", className)}>
<span className="text-[0.75rem]/[1rem] text-(color:--chatcn-fg-subtle) font-medium">{label}</span>
<ToggleGroup
value={[value]}
onValueChange={(next) => {
const picked = next[0] as T | undefined
if (picked) onValueChange(picked)
}}
aria-label={label}
className="bg-(color:--chatcn-fill) rounded-(--chatcn-radius-md) flex h-8 w-fit max-w-full items-center gap-0.5 overflow-x-auto p-0.5 pointer-coarse:h-11"
>
{options.map((option) => (
<Toggle
key={option.value}
value={option.value}
className={cn(
"chatcn-focus rounded-(--chatcn-radius-sm) text-[0.8125rem]/[1.25rem] inline-flex h-full shrink-0 items-center px-2.5 font-medium whitespace-nowrap",
"text-(color:--chatcn-fg-subtle) ease-(--chatcn-ease-standard) transition-[color,background-color,box-shadow] duration-150",
"hover:text-(color:--chatcn-fg) data-[pressed]:bg-(color:--chatcn-card) data-[pressed]:text-(color:--chatcn-fg) data-[pressed]:shadow-(--chatcn-shadow-xs)",
)}
>
{option.label}
</Toggle>
))}
</ToggleGroup>
</div>
)
}
const SOFTNESS = [
{ value: "0", label: "Hard" },
{ value: "0.025", label: "Soft" },
{ value: "0.08", label: "Softer" },
] as const
/** The line under each 21st demo that points back to the kit. */
function MoreOn({ slug, children }: { slug: string; children: React.ReactNode }) {
return (
<p className="text-[0.75rem]/[1rem] text-(color:--chatcn-fg-faint) text-center text-balance">
{children}{" "}
<a
href={`https://chatcn.dev/docs/components/${slug}`}
target="_blank"
rel="noopener"
className="text-(color:--chatcn-fg-subtle) hover:text-(color:--chatcn-fg) underline underline-offset-2"
>
chatcn.dev
</a>
</p>
)
}
/**
* A generation job reports uneven diffusion steps with a stall. The stencil rises out of the
* paper first, then tone floods in from the shadows as the job finishes.
*/
export default function ThresholdRevealPreview() {
const [run, replay] = useRun()
const [soft, setSoft] = React.useState<"0" | "0.025" | "0.08">("0.025")
const job = useSimulatedJob({ total: 28 })
const restart = () => {
replay()
job.start()
}
return (
<div className="flex min-h-[520px] w-full flex-col items-center justify-center gap-8 p-6">
<DemoShell
className="max-w-lg"
onReplay={restart}
replayLabel="Generate again"
media={
<ThresholdReveal
key={run}
src={PORTRAIT_SRC}
alt="Portrait of a woman with dark curly hair and red lipstick, looking past the camera in soft light"
progress={job.progress}
softness={Number(soft)}
aspectRatio="4:5"
className="rounded-(--chatcn-radius-lg) w-full"
/>
}
caption={
<GenerationCaption
prompt="Portrait in soft window light, red lipstick, 85 mm, shallow focus"
job={job}
/>
}
controls={
<Segmented label="Edge" value={soft} onValueChange={setSoft} options={SOFTNESS} />
}
/>
<MoreOn slug="threshold-reveal">Dither, halftone, scan and pixel reveals live on</MoreOn>
</div>
)
}















