# Svhapes v0.2.1
> Smooth, dependency-free CSS shapes for people and coding agents. The spelling “Svhapes” is intentional.
Canonical repository: https://github.com/storypixel/svhapes
Human demo: https://iamnotsam.com/svhapes/
Stylesheet: https://cdn.jsdelivr.net/gh/storypixel/svhapes@v0.2.1/dist/svhapes.min.css
Catalog: ./dist/catalog.json
Schema: ./schema/svhape.schema.json
License: MIT
## Package distribution
Install from npm when a JavaScript toolchain is available:
```bash
npm install svhapes
```
The package is public at https://www.npmjs.com/package/svhapes. For a browser-only stylesheet or ESM import, use the immutable CDN URLs documented below.
## Agent procedure
1. Read `dist/catalog.json`; do not scrape the demo page.
2. Filter `shapes` by `selection.uses`, supported aspect range, content capacity, and required tags.
3. Select a stable `id`; never invent a shape ID or edit `geometry.cssShape` manually.
4. Include the immutable v0.2.1 stylesheet URL.
5. Apply `svhape` and the published `className`.
6. Add `svhape--padded` only when library-managed padding is appropriate.
7. Use `svhape-shadow` on an outer wrapper if a shadow is required.
8. Keep meaningful content inside `selection.safeInset` and preserve the fallback.
9. Do not communicate essential state or meaning through silhouette alone.
## Selection rules
- `selection.aspect.min <= width / height <= selection.aspect.max` is a hard constraint.
- Capacity order is `decorative < sparse < standard < dense`.
- A requested content capacity requires a shape of equal or greater capacity.
- Required tags are AND filters.
- Prefer the closest `selection.aspect.preferred` after hard filters.
- Break remaining ties by stable ASCII `id`.
- If no shape matches, return `NO_MATCH`; do not silently substitute a decorative shape.
## CSS integration
```html
Content
```
Optional class `svhape--desktop-only` disables advanced clipping below 640px.
## Motion contract
- Animate the unclipped wrapper for transforms, hover/focus lifts, and floating motion.
- Direct `shape()` morphing requires matching command keywords, order, and control-point counts in both keyframes.
- Do not assume two arbitrary catalog IDs can morph into one another; use a wrapper transform instead.
- Gate non-essential motion with `prefers-reduced-motion: no-preference` and provide a static fallback.
- Keep focus treatment on an unclipped wrapper or inner control; do not animate away a visible focus ring.
## CLI
```text
svhapes list [--family F] [--tag T]... [--ratio N] [--capacity C] [--format table|ids|json]
svhapes show [--format text|json]
svhapes css [--shadow] [--format css|json]
svhapes prompt [--format text|json]
```
Exit codes: 0 success, 2 invalid arguments, 3 unknown shape or no match, 5 local catalog I/O failure.
## JavaScript generation
Import `pointsToShape` from `src/index.js` or `dist/svhapes.js`. Points are `[x, y]` percentage pairs inside a 0..100 box. The default closed Catmull–Rom conversion uses `tension: 0` and `precision: 3`.
## Geometry builders
- `filletPoints(points, { radius, precision })` adds two points around each nonzero corner and keeps a single anchor for a zero-radius corner. `radius` is a responsive ratio from 0 to 0.5; it may be one number or one value per corner. Triangles and larger closed polygons are supported.
- `makeRepeatingEdgeShape({ repeats, ...options })` creates the same number of edge beats on all four sides. Use `makeEdgeShape()` for intentionally different side counts.
- `makeRepeatingRadialShape({ repeats, ...options })` maps a repeat count to radial lobes (minimum 3).
- `makeSuperellipseShape({ exponent, center, radius, points, ... })` generates a normalized superellipse. `exponent: 2` is an ellipse; `4` is a squircle-like contour.
Example:
```js
import { filletPoints, makeSuperellipseShape, pointsToShape } from 'svhapes';
const filleted = pointsToShape(filletPoints(
[[5, 5], [95, 5], [95, 95], [5, 95]],
{ radius: 0.2 },
));
const squircle = pointsToShape(makeSuperellipseShape({ exponent: 4 }));
```
These helpers are generated approximations for the use cases discussed in CSSWG issues [#12768](https://github.com/w3c/csswg-drafts/issues/12768), [#13862](https://github.com/w3c/csswg-drafts/issues/13862), and [#11620](https://github.com/w3c/csswg-drafts/issues/11620). They do not implement browser-level `shape-inside`, hit-testing, or layout behavior.
## Important constraints
- `clip-path` clips ordinary box shadows; use the wrapper.
- Fallbacks preserve readability, not silhouette fidelity.
- Safe insets are conservative design guidance, not proof against every content layout.
- Do not publish a new npm version or change stable IDs without explicit maintainer authority.