Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a416451
feat: Add Houdini CSS paint worklet for G2-continuous pill shapes
claude Sep 15, 2026
5351d58
fix: Make paint worklet methods public for TypeScript compilation
claude Sep 15, 2026
7748543
fix: Remove unused imports and variables
claude Sep 15, 2026
dae05bb
fix: format tailwind-pill.ts
claude Sep 15, 2026
ebfdcd4
docs: add pill shapes documentation with framework examples
claude Sep 15, 2026
1379100
feat: add visual demo components for pill shapes
claude Sep 15, 2026
7cea1a0
fix: add pill shapes section to README table of contents
claude Sep 15, 2026
8162571
Fix PillPandaDemo import error by using simple className strings
claude Sep 15, 2026
e462131
refactor: simplify pill utilities - auto-calculate radius from elemen…
claude Sep 15, 2026
4dd7de5
build: add pill-test.html to .gitignore
claude Sep 15, 2026
e5eb5bc
feat: add pill-test.html to repo for local testing
claude Sep 16, 2026
29163d0
feat: add dev server script for pill shape testing
claude Sep 16, 2026
8e48bcc
fix: rename dev-pill.html to index.html for vite dev server
claude Sep 16, 2026
65bae40
chore: remove dev-pill.html (renamed to index.html)
claude Sep 16, 2026
92b3783
fix: build worklet before dev server in pill-dev task
claude Sep 16, 2026
9114e45
refactor: use vite-plus task dependencies for pill dev
claude Sep 16, 2026
164d363
feat(pill): draw G2-continuous pill caps with a clothoid transition
dogmar Sep 16, 2026
aa42d32
fix(pill): back off amount and falloff together, and sample by sagitta
dogmar Sep 16, 2026
8cbb69f
feat(pill): stop clamping the ease falloff to the clothoid
dogmar Sep 16, 2026
fe8f21f
refactor(pill)!: rename the ease falloff to --pill-ease-spread, based…
dogmar Sep 16, 2026
e60d4f9
feat(pill): default the ease spread to 1
dogmar Sep 16, 2026
7674889
fix(pill): fall back to a plain full radius, not a superellipse
dogmar Sep 16, 2026
19d28dd
refactor(pill): use FULL_RADIUS for the no-worklet fallback
dogmar Sep 16, 2026
59a9d6d
fix(pill): make the utility self-sufficient, drop the inert attribute…
dogmar Sep 16, 2026
0c10b0a
feat(pill)!: shape the element with a mask so any background works
dogmar Sep 16, 2026
3d399cb
docs(pill): demonstrate backgrounds and decorations on the dev page
dogmar Sep 16, 2026
1263207
fix(pill): clip the stroke to its own outline so rings are even
dogmar Sep 17, 2026
32d8840
feat(pill): drive the drawn border's style from --tw-border-style
dogmar Sep 17, 2026
6218231
feat(pill)!: ship Tailwind-only, and teach border-* to drive the draw…
dogmar Sep 17, 2026
1c48f5d
fix: format pill-shape.test.ts
claude Sep 17, 2026
2e202bc
refactor(pill)!: namespace the pill custom properties, configurable a…
dogmar Sep 17, 2026
46e3cb7
refactor!: default the namespace to "squircle", deprecate amtVar and …
dogmar Sep 17, 2026
d588e08
docs: update pill shape documentation to reflect single-utility design
claude Sep 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ We're all excited about `corner-shape: squircle`, but we're in a pickle right no

- [Requirements](#requirements)
- [Install & setup](#install--setup)
- [Pill Shapes with Houdini CSS Paint Worklet](#pill-shapes-with-houdini-css-paint-worklet)
- [How the radius correction works](#how-the-radius-correction-works)
- [Browser support & fallback strategy](#browser-support--fallback-strategy)
- [Why it called "squircle" when it use "superellipse()"?](#why-it-called-squircle-when-it-use-superellipse)
Expand Down Expand Up @@ -443,6 +444,94 @@ The parameters are deliberately untyped so relative units (`em`, `rem`, containe

</details>

## Pill Shapes with Houdini CSS Paint Worklet

The standard `corner-shape: superellipse()` can't perfectly render pill shapes because it creates hard corners where the curved ends meet the straight sides. **Pill shapes** use a Houdini CSS Paint API worklet to render mathematically smooth, G2-continuous transitions from semicircular ends to straight edges—ideal for button pills, badge pills, and other pill-shaped UI elements.

<details>
<summary><strong>Tailwind CSS v4</strong></summary>

### 1. Install the pill plugin

```bash
npm install @klinking/squircle
```

### 2. Add the pill plugin to your CSS

```css
@import "tailwindcss";
@import "@klinking/squircle/tailwind-pill";
@import "@klinking/squircle/squircle-pill.css";
```

Or with the JS plugin version:

```css
@import "tailwindcss";
@plugin "@klinking/squircle/tailwind-pill";
@import "@klinking/squircle/squircle-pill.css";
```

### 3. Register the paint worklet

In your entry point (e.g., `main.ts`), register the Houdini paint worklet:

```typescript
// Register the paint worklet
CSS.paintWorklet.addModule(
new URL("@klinking/squircle/pill-shape.worklet.js", import.meta.url).href
);
```

### 4. Use the pill utility

Use the `squircle-pill` class to apply pill shapes to any element:

```html
<!-- Perfect pill-shaped button -->
<button class="squircle-pill px-4 py-2 bg-blue-500 text-white">
Click me
</button>

<!-- Pill badge -->
<div class="squircle-pill bg-green-100 text-green-900 px-3 py-1">New</div>

<!-- Pill with side-specific variants -->
<div class="squircle-pill-t squircle-pill-r">…</div>

<!-- Customize superellipse transition smoothness -->
<div class="squircle-pill squircle-pill-amt-2.5">…</div>
```

**Available variants:**

- Base utility: `squircle-pill`
- Side variants: `squircle-pill-t`, `squircle-pill-r`, `squircle-pill-b`, `squircle-pill-l` (top, right, bottom, left)
- Corner variants: `squircle-pill-tl`, `squircle-pill-tr`, `squircle-pill-br`, `squircle-pill-bl` (and logical equivalents)
- Amount control: `squircle-pill-amt-*` (e.g., `squircle-pill-amt-1`, `squircle-pill-amt-2.5`, `squircle-pill-amt-3`) to adjust the smoothness of the semicircle-to-edge transition

The pill radius is automatically calculated from the element's dimensions: `radius = min(width, height) / 2`, ensuring perfect pills at any size.

### Browser support and fallback

- **Chrome/Edge 89+**: Full Houdini CSS Paint API support — perfect pill shapes with G2-continuous curves
- **Safari/Firefox**: Graceful fallback to `corner-shape: superellipse()` which approximates a pill shape

</details>

### How pill shapes work

Pill shapes render using Houdini's CSS Paint API to draw:

- **Horizontal pills** (width > height): Semicircles on left and right, straight top and bottom edges
- **Vertical pills** (height > width): Semicircles on top and bottom, straight left and right edges
- **Circular pills** (width = height): Full circles

The worklet computes G2-continuous Bezier curves at junctions between the semicircles and straight edges, using cubic Bezier approximation (magic constant `0.55228`) to smoothly transition from the semicircle's constant curvature to the straight edge's zero curvature.

**Fallback for unsupported browsers:** Falls back to `corner-shape: superellipse()` which approximates a pill shape without perfect mathematical continuity.

## How the radius correction works

A superellipse at the same outer `border-radius` as a circular arc pokes further into the corner. The fix is to scale the radius up by some maths, so the _apparent_ roundness matches what you'd get from `rounded-*`. That is, the distance from the corner to the maximum pokage will match for both the superelliptical corner and the circular corner.
Expand Down
Loading
Loading