https://github.com/cyansalt/corner-smoothie
Create elements with Figma corner smoothing
https://github.com/cyansalt/corner-smoothie
Last synced: 5 months ago
JSON representation
Create elements with Figma corner smoothing
- Host: GitHub
- URL: https://github.com/cyansalt/corner-smoothie
- Owner: CyanSalt
- License: isc
- Created: 2025-02-14T06:57:29.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-11-28T02:30:19.000Z (8 months ago)
- Last Synced: 2025-11-29T20:34:08.490Z (8 months ago)
- Language: TypeScript
- Size: 132 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# corner-smoothie
[](https://www.npmjs.com/package/corner-smoothie)



Create elements with [Figma corner smoothing](https://www.figma.com/blog/desperately-seeking-squircles/).
[Live Demo](https://raw.githack.com/CyanSalt/corner-smoothie/main/playground/index.html)
## Usage
### CSS Painting API (Recommended)
> [!IMPORTANT]
> See [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Painting_API#browser_compatibility).
```js
CSS.paintWorklet.addModule('')
```
#### Using CDN (jsdelivr)
```js
CSS.paintWorklet.addModule('https://cdn.jsdelivr.net/npm/corner-smoothie/dist/worklet.js')
```
#### Using Vite
```js
import smoothieWorklet from 'corner-smoothie/worklet?url'
CSS.paintWorklet.addModule(smoothieWorklet)
```
### Registering (Required)
> [!NOTE]
> `registerProperties` relies on the CSS Properties and Values API, which [has different browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Properties_and_Values_API#api.css.registerproperty_static).
```js
import { registerProperties } from 'corner-smoothie'
registerProperties()
```
#### CSS Declarations
```css
.my-element {
border-radius: 12px;
}
@supports (mask-image: paint(smoothie-mask)) {
.my-element {
--smoothie-border-radius: 12px;
--smoothie-border-smoothing: 0.6;
border-radius: 0;
mask-image: paint(smoothie-mask);
}
}
```
```css
.my-element {
background-color: cyan;
border-radius: 12px;
}
@supports (background-image: paint(smoothie-background)) {
.my-element {
--smoothie-background-color: cyan;
--smoothie-border-radius: 12px;
--smoothie-border-smoothing: 0.6;
background-color: transparent;
border-radius: 0;
background-image: paint(smoothie-background);
}
}
```
The `border-radius: 0` above can also be omitted, since smooth rounded corners are completely inside the tangent rounded corners.
#### Supported custom properties
- `--smoothie-background-color`: Alternative to `background-color`. Available in background mode.
- `--smoothie-border-color`: Alternative to `border-color`. Available in background mode.
- `--smoothie-border-radius`: Alternative to `border-radius`. Available in **BOTH** modes.
- `--smoothie-border-radius-smoothing`: A decimal between 0 and 1, aka `ξ` in [Figma smoothing parameterized](https://www.figma.com/blog/desperately-seeking-squircles/#breakthrough-smoothing-parameterized). The larger the value, the smoother the corners. Available in **BOTH** modes.
- It is consistent with the iOS specification when specified as `0.6`.
- `--smoothie-border-width`: Alternative to `border-width`. Available in background modes.
### JS API
```js
import { createMaskImage } from 'corner-smoothie'
const mask = createMaskImage(
{ width: 72, height: 72 },
{ borderRadius: 12, borderRadiusSmoothing: 0.6 },
)
element.style.maskImage = mask
```
```js
import { createBackgroundImage } from 'corner-smoothie'
const background = createBackgroundImage(
{ width: 72, height: 72 },
{ borderRadius: 12, borderRadiusSmoothing: 0.6, backgroundColor: 'cyan' },
)
element.style.backgroundImage = background
```
JS API is especially useful for browsers that do not support the CSS Painting API such as Firefox. You can use `ResizeObserver` to have a similar experience to the CSS Painting API:
```js
import { createMaskImage } from 'corner-smoothie'
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
if (entry.borderBoxSize.length) {
entry.target.style.maskImage = createMaskImage({
width: entry.borderBoxSize[0].inlineSize,
height: entry.borderBoxSize[0].blockSize,
}, {
// Normally you can't use the CSS Typed OM API
// because you only need to use the CSS Painting API in these browsers
borderRadius: parseFloat(getComputedStyle(entry.target).getPropertyValue('--smoothie-border-radius')),
borderRadiusSmoothing: 0.6,
})
}
}
})
observer.observe(element)
```
> Some older browsers may not support [`borderBoxSize`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/borderBoxSize), you may need to use [`contentRect`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentRect) instead.
## Differences between mask and background
| Feature | Mask | Background |
| --- | --- | --- |
| Corner radius | ✅ | ✅ |
| Background image | ✅ | ❌ |
| Border | ❌ | ✅ |
| Overflow content | ❌ | ✅ |