Componentregistry:component
Cyanotype
Turns any image into a hand-coated cyanotype: Prussian-blue tones, a brushed emulsion edge with an exposed border, uneven coating and paper tooth. Photogram mode prints objects as white silhouettes, and an optional develop wash plays when the print scrolls into view. Pure SVG filters, no CORS needed.
Installation
$ npx shadcn@latest add @creative-ui/cyanotypeOn an older shadcn CLI, use the URL: npx shadcn@latest add https://ui.krutikraut.com/r/cyanotype.json
Preview
Subject
Tone
Exposure0.00
Brush edge0.60
Mottle0.40
Usage
Example.tsx
import Image from "next/image"
import { Cyanotype } from "@/components/cyanotype"
export function Plate() {
return (
<Cyanotype
src="https://images.unsplash.com/photo-1576773689115-5cd2b0223523?w=900&q=80&auto=format&fit=crop"
alt="Pre-Raphaelite painting of a woman in robes"
develop
className="aspect-[4/5] w-80"
/>
)
}
// A photogram: dark or opaque shapes on a light ground print as white silhouettes.
<Cyanotype mode="photogram" border={0} contrast={1.4} seed={8} className="aspect-[4/5] w-80">
<Image src="/pressed-fern.png" alt="Pressed fern" fill className="object-cover" />
</Cyanotype>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| src | string | — | Image URL. Omit when wrapping your own element with children. |
| alt | string | "" | Accessible description. Leave empty for decorative images. |
| mode | "print" | "photogram" | "print" | print contact-prints the image as a positive. photogram treats it as objects laid on the paper: dark or opaque shapes stay white and everything else exposes to blue. |
| preset | "classic" | "deep" | "tea" | "faded" | "classic" | A named tone ramp. tea is tannin-toned, faded is a sun-bleached print. Overridden by ramp. |
| ramp | string[] | — | Custom tone stops from full exposure to bare paper, as hex. The last stop is also the paper colour. |
| exposure | number | 0 | -1 to 1. Higher prints darker and deeper, lower leaves it pale. |
| contrast | number | 1.15 | Tone contrast, roughly 0.5 to 2. |
| roughness | number | 0.6 | Ragged, streaky brush edge on the coating, 0 to 1. 0 gives a clean rectangle. |
| mottle | number | 0.4 | Uneven coating and exposure, 0 to 1. |
| texture | number | 0.5 | Paper tooth over the whole sheet, 0 to 1. |
| margin | number | 24 | Bare paper around the brushed coating, in px. |
| border | number | 18 | Fully exposed blue border between the brush edge and the image, in px. 0 lets the brush edge eat into the image. |
| seed | number | 3 | Seed for the brush edge and mottle. Give each print in a set its own so the edges differ. |
| develop | boolean | false | Wash the print from unexposed yellow-green to blue the first time it scrolls into view. Plays once, and not at all for reduced motion. |
| developDuration | number | 1800 | Length of the develop wash in ms. |
| fit | "cover" | "contain" | "cover" | How the image fills the box. |
| imageClassName | string | — | Class names for the img element. |
| children | React.ReactNode | — | Print an existing element, such as next/image or an SVG, instead of rendering an img. |
Also accepts every div prop, which is spread onto the root element.
Also exported
- cyanotypePresets
- The four tone ramps as arrays of hex stops, darkest first, for building your own picker.
Notes
- Give the component a size, such as
aspect-[4/5] w-80. The image fills the area insidemarginandborder. - Everything is SVG filters, so cross-origin images work without CORS headers. Nothing is drawn to a canvas.
- Ramp colours are baked into the filter, so they must be hex. CSS variables and named colours are not supported.
- To replay the develop wash, remount the component with a new
key. - It is a client component because of the develop wash. Without
developit renders the same markup on the server and adds no observers.
Dependencies
shadcn/utils
