npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

svelte-clipper

v0.1.2

Published

Responsive, reactive SVG clip paths for Svelte 5 — project clip shapes across elements with independent coordinate spaces.

Readme

svelte-clipper

Responsive, reactive SVG clip paths for Svelte 5. Define a clip shape anywhere in the DOM, apply it to anything anywhere else — across independent coordinate spaces, transforms, scroll containers, and CSS animations. Compose multiple shapes together with real boolean operations (union, difference, intersection, …).

<script lang="ts">
 import { Clipper, ClippedBy } from 'svelte-clipper';
</script>

<Clipper id="hole">
 <svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" /></svg>
</Clipper>

<ClippedBy clipper="hole">
 <img src="/cat.jpg" />
</ClippedBy>

Installation

npm i svelte-clipper

Svelte 5 is a peer dependency.

Why

clip-path: url(#id) works, but the clip shape has to live in a coordinate system the target understands. The moment the shape and target have different transforms, sit in different scroll containers, scale differently, or animate independently, the math gets painful fast. svelte-clipper watches both sides and continuously re-projects the shape into the target's local space, so you can put the clipper anywhere and the target anywhere and they just line up.

Core components

<Clipper>

Wraps the element(s) that define the clip shape. The shape can be any SVG graphics element (path, circle, ellipse, rect, polygon, polyline) or a container (svg, g) with any number of nested shapes.

<script lang="ts">
 import { Clipper } from 'svelte-clipper';
</script>

<Clipper id="my-shape" preview live>
 <svg viewBox="0 0 200 200">
  <polygon points="100,10 40,198 190,78 10,78 160,198" />
 </svg>
</Clipper>

Clipper props

| Prop | Type | Default | Description | | ---------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | id | string | — | Identifier that ClippedBy uses to find this shape. | | preview | boolean | false | Renders the shape with a dashed outline so you can see what's being used as the clipper. Otherwise the shape itself is invisible. | | live | boolean | false | Polls the shape's screen transform every animation frame. Turn on when the shape (or an ancestor) moves via CSS animation / transitions. | | children | Snippet | — | The SVG content. |

<ClippedBy>

Wraps the content that should be clipped. Accepts any HTML or SVG — images, divs, entire components.

<script lang="ts">
 import { ClippedBy } from 'svelte-clipper';
</script>

<ClippedBy clipper="my-shape" mode="clip">
 <div class="content">anything in here</div>
</ClippedBy>

ClippedBy props

| Prop | Type | Default | Description | | ---------- | ---------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | clipper | string \| string[] | — | One clipper id, or an array to combine several into a single clip. | | mode | 'clip' \| 'subtract' | 'clip' | 'clip' keeps only what's inside the shape. 'subtract' keeps everything except the shape (punches a hole). | | combine | CombineOp | 'concat' | How to fuse multiple clippers. 'concat' just appends them (with even-odd fill). The others run a real boolean op via path-bool: 'union', 'difference', 'intersection', 'exclusion', 'division', 'fracture'. | | class | string | — | Forwarded to the wrapper <div>. Use this to size the clipping region. | | children | Snippet | — | The content to clip. |

Examples

Multiple shapes as one clip

<script lang="ts">
 import { Clipper, ClippedBy } from 'svelte-clipper';
</script>

<Clipper id="circle-a"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" /></svg></Clipper>
<Clipper id="circle-b"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" /></svg></Clipper>

<ClippedBy clipper={['circle-a', 'circle-b']} combine="union" mode="subtract">
 <img src="/photo.jpg" />
</ClippedBy>

Two independent SVGs — possibly in very different parts of the page — combined into one hole.

CSS-animated clipper

<script lang="ts">
 import { Clipper } from 'svelte-clipper';
</script>

<div class="spinner">
 <Clipper id="star" live>
  <svg viewBox="0 0 200 200"><polygon points="..." /></svg>
 </Clipper>
</div>

<style>
 .spinner {
  animation: spin 6s linear infinite;
 }
 @keyframes spin {
  to {
   transform: rotate(360deg);
  }
 }
</style>

live polls each frame so the clip tracks the CSS transform. Without it, mutations to the shape itself are still observed, but ancestor CSS animations are not.

Complex, multi-path SVGs

The <Clipper> can wrap an entire <svg> containing nested <g> elements and many paths — all are combined into the clip shape, including multi-subpath paths with holes (via even-odd fill rule).

Boolean operations

When passing an array of clippers, combine controls how the paths are fused before the final clip is applied. This is powered by path-bool.

| Op | Meaning | | -------------- | ----------------------------- | | concat | Append paths (default, fast). | | union | A ∪ B (merge overlaps). | | difference | A − B. | | intersection | A ∩ B. | | exclusion | A XOR B. | | division | Slice A using B's boundaries. | | fracture | Emit every partition. |

Operations are folded left-to-right for more than two clippers.

How it works

Under the hood, each ClippedBy renders a hidden <svg><clipPath> and applies it via clip-path: url(#...). On every layout change (resize, scroll, mutation) or animation frame (in live mode), the library:

  1. Reads the clipper's current screen-space CTM.
  2. Reads the target's bounding rect.
  3. Composes them into a source → target matrix.
  4. Projects the shape's geometry through that matrix into a d string.
  5. Optionally runs a boolean operation against other clippers.
  6. Writes the result to the <clipPath>'s <path>.

Per-frame updates short-circuit when the composed matrix hasn't changed (e.g. during pure scroll where source and target move together), so the cost is effectively zero when nothing has actually shifted.

Advanced exports

The registry and projection helpers are exported for custom integrations:

import {
 registerClipper,
 unregisterClipper,
 getClipperEl,
 subscribeClipper,
 notifyClipper,
 shapeToPath,
 SUPPORTED_SHAPE_TAGS,
 observeLayout
} from 'svelte-clipper';

Acknowledgments

Boolean path operations are powered by path-bool by @r-flash (MIT).

License

MIT