Custom Stencil
The stencil is the draggable, resizable overlay that marks the crop area. You can write your own stencil component by following the stencil contract.
Built-in stencils
Use CircleStencil for circular crop (automatically 1:1):
CircleStencil example
No image loaded
<script lang="ts">
import { Cropper, CircleStencil } from '@we-are-singular/svelte-chop-chop';
import '@we-are-singular/svelte-chop-chop/themes/default';
</script>
<Cropper src="/avatar.jpg" stencil={CircleStencil} /> Stencil contract
A stencil component receives these props from the cropper engine:
| Prop | Type | Description |
|---|---|---|
rect | Rect | Current crop rect in viewport pixels: { x, y, width, height } . |
onmove | (delta: Point) => void | Call with pixel delta { x, y } to move the stencil. |
onresize | (handle: HandlePosition, delta: Point) => void | Call with handle position and delta to resize from a handle. |
grid | boolean | Whether to show the rule-of-thirds grid. |
gridOnlyActive | boolean | Only show the grid during active interaction. |
HandlePosition
HandlePosition is 'n' | 's' | 'e' | 'w' | 'nw' | 'ne' | 'sw' | 'se' .
Using DragHandle
The built-in DragHandle component handles pointer events and emits resize deltas. Use it for the corner
and edge handles of your stencil:
<script lang="ts">
import { DragHandle } from '@we-are-singular/svelte-chop-chop';
import type { StencilProps, Point, HandlePosition } from '@we-are-singular/svelte-chop-chop';
import { createDragHandler } from '@we-are-singular/svelte-chop-chop';
let { rect, onmove, onresize, onresizestart, onresizeend }: StencilProps & {
onmove: (delta: Point) => void;
onresize: (handle: HandlePosition, delta: Point) => void;
onresizestart?: () => void;
onresizeend?: () => void;
} = $props();
const drag = createDragHandler({ onMove: onmove });
</script>
<div
class="my-stencil"
style="left:{rect.x}px; top:{rect.y}px; width:{rect.width}px; height:{rect.height}px"
role="region"
aria-label="Crop area"
onpointerdown={drag.onpointerdown}
onpointermove={drag.onpointermove}
onpointerup={drag.onpointerup}
>
<DragHandle position="nw" {onresize} {onresizestart} {onresizeend} />
<DragHandle position="ne" {onresize} {onresizestart} {onresizeend} />
<DragHandle position="sw" {onresize} {onresizestart} {onresizeend} />
<DragHandle position="se" {onresize} {onresizestart} {onresizeend} />
</div> Passing the custom stencil
<script lang="ts">
import { Cropper } from '@we-are-singular/svelte-chop-chop';
import MyStencil from './MyStencil.svelte';
</script>
<Cropper src="/photo.jpg" stencil={MyStencil} /> CropOverlay
Use the built-in CropOverlay component to render the dark semi-transparent overlay with a transparent cutout
over the crop rect:
import { CropOverlay } from '@we-are-singular/svelte-chop-chop';
<CropOverlay rect={rect} imageBounds={imageBounds} /> GridOverlay
GridOverlay draws rule-of-thirds lines, a full grid, or a golden ratio guide:
import { GridOverlay } from '@we-are-singular/svelte-chop-chop';
<GridOverlay
{cropRect}
type="rule-of-thirds"
visible={grid && (!gridOnlyActive || isDragging)}
/>