KQ-1133 · RATIO/MORPH
Ratio Morph
An aspect-ratio picker that reframes a picture: choosing a shape glides the frame's width and height to the new ratio on the glide spring, with four corner brackets riding its corners, while the picture is re-laid every frame so its focal point stays as near the centre as its edges allow. Pressing the stage brings the focal reticle to the finger 1:1 (it swells on flick) while a ghost of the whole picture fades in round the frame; past the picture's edge the reticle rubber-bands, and on release the throw is projected and the picture glides to re-centre on the new point. The chips are a radiogroup whose arrows choose and whose Home and End jump; the stage takes arrow keys (Shift for bigger steps) to move the focal point with the same glide and sounds.
Harbour at dusk with a lighthouse on the headland. Drag or tap to place the focal point, or use the arrow keys; Shift moves further.
4:5 portrait · focus 25% across, 54% down
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/ratio-morph
Props
- ratios
- "social" | "photo" | "screen" | string[]
- default "social"
- The shapes offered, in chip order: social is 1:1, 4:5, 16:9 and 9:16; photo is 3:2, 4:3, 1:1 and 2:3; screen is 16:9, 16:10, 21:9 and 4:3. Or your own list of "w:h" strings. RATIO_MORPH_SETS exports the named sets.
- value / defaultValue
- string
- default the first of ratios
- The chosen ratio, as "w:h". A value that is not in the list shows the first ratio.
- onValueChange
- (ratio: string) => void
- default —
- Fires from the press or key that chose a new ratio. In controlled mode the frame morphs once the host passes the new value back.
- focalPoint / defaultFocalPoint
- { x: number; y: number }
- default { x: 0.5, y: 0.5 }
- The point the frame keeps in view as it changes shape, as fractions of the picture's width and height.
- onFocalPointChange
- (point: { x: number; y: number }) => void
- default —
- Fires once per drag release, tap or arrow key, with the new point rounded to three places.
- brackets
- number
- default 16
- The corner brackets' arm length in px, 6 to 40: short ticks to nearly closed corners.
- focal
- boolean
- default true
- Marks the focal point with a reticle on the picture.
- grid
- boolean
- default false
- Rule-of-thirds lines inside the frame that ride the morph; faint at rest, brighter while the picture is held.
- picture
- ReactNode
- default a procedural harbour at dusk
- What is framed. It is laid out in a box of pictureRatio and scaled, so pass something that fills its box, such as an img with object-cover.
- pictureRatio
- number
- default 1.5
- The picture's own width over its height.
- alt
- string
- default —
- What the picture shows, read with the stage's instructions. Defaults to a description of the built-in harbour.
- label
- string
- default "Aspect ratio"
- The ratio chips' accessible name.
- sound
- boolean
- default false
- A detent when a ratio is chosen and a click on the frame the morph lands, both pitched by the shape; a detent when a drag meets the picture's edge and a click on release. Nothing plays, and no audio context exists, unless this is on.
- disabled
- boolean
- default false
- Dims the picker and blocks the chips, drags, taps and keys.
- className
- string
- default —
- Merged onto the wrapper that holds the stage and the chips.
| Prop | Type | Default | Description |
|---|---|---|---|
| ratios | "social" | "photo" | "screen" | string[] | "social" | The shapes offered, in chip order: social is 1:1, 4:5, 16:9 and 9:16; photo is 3:2, 4:3, 1:1 and 2:3; screen is 16:9, 16:10, 21:9 and 4:3. Or your own list of "w:h" strings. RATIO_MORPH_SETS exports the named sets. |
| value / defaultValue | string | the first of ratios | The chosen ratio, as "w:h". A value that is not in the list shows the first ratio. |
| onValueChange | (ratio: string) => void | — | Fires from the press or key that chose a new ratio. In controlled mode the frame morphs once the host passes the new value back. |
| focalPoint / defaultFocalPoint | { x: number; y: number } | { x: 0.5, y: 0.5 } | The point the frame keeps in view as it changes shape, as fractions of the picture's width and height. |
| onFocalPointChange | (point: { x: number; y: number }) => void | — | Fires once per drag release, tap or arrow key, with the new point rounded to three places. |
| brackets | number | 16 | The corner brackets' arm length in px, 6 to 40: short ticks to nearly closed corners. |
| focal | boolean | true | Marks the focal point with a reticle on the picture. |
| grid | boolean | false | Rule-of-thirds lines inside the frame that ride the morph; faint at rest, brighter while the picture is held. |
| picture | ReactNode | a procedural harbour at dusk | What is framed. It is laid out in a box of pictureRatio and scaled, so pass something that fills its box, such as an img with object-cover. |
| pictureRatio | number | 1.5 | The picture's own width over its height. |
| alt | string | — | What the picture shows, read with the stage's instructions. Defaults to a description of the built-in harbour. |
| label | string | "Aspect ratio" | The ratio chips' accessible name. |
| sound | boolean | false | A detent when a ratio is chosen and a click on the frame the morph lands, both pitched by the shape; a detent when a drag meets the picture's edge and a click on release. Nothing plays, and no audio context exists, unless this is on. |
| disabled | boolean | false | Dims the picker and blocks the chips, drags, taps and keys. |
| className | string | — | Merged onto the wrapper that holds the stage and the chips. |