> **Shape is not a rounding number an element _has_; it is a perceptual quality
> — continuity, family, tension — that the system _composes_ and that, in its
> moment, _happens_.**
Everybody reduces shape to ONE number: `border-radius`. But the corner has more
axes than its magnitude: **how continuous** it is (circular arc vs
superellipse), which **family** it belongs to (rounded / continuous / cut /
pill), how it **relates** to nested shapes, and **what happens to it** when the
element is pressed or commits. Eidos treats shape as a **first-class channel**:
unified (magnitude + continuity + family + harmony), and **eventful** (shape can
tense/relax), under the **open cage**.
## 1. The survey — how the references do it and where they stop
| Framework | Model | Structural limit |
|---|---|---|
| **Tailwind / Bootstrap** | `rounded-sm…full` scale, circular arc | no continuity, no nested harmony, no family, static; the corner is an arc, period |
| **Material 3** | shape scale + per-component mapping + (M3 Expressive) *morph* + `cut` family | arc/cut; the morph is recent and narrow; a **closed** system (you pick from the scale) |
| **Apple / SwiftUI** | **continuous** corners (superellipse) `.continuous` | platform-bound, not a portable token; not eventful; manual nesting |
| **CSS today** | `border-radius` = elliptical arcs | no universal native superellipse (`corner-shape` emerging); squircles via SVG/clip-path hacks |
**Common limit**: shape = **one arc-radius number**, a **static** property you
assign, **detached** from neighboring/nested elements, without real
**continuity**, and **disconnected from what happens**. SwiftUI is the only one
with continuity — but closed and per-platform. Material is the only one with
family + morph — but arc-based and closed. Nobody **unifies** them or makes
them **open**.
## 2. Where Eidos stands today (coherent, but not novel)
- **Radius scale** in `--radius-{none·sm·md·lg·xl·xxl·full}` (4/6/10/16/20px + pill). ✓
- Assigned **per component** via the size primitive (`radius: 'md'`). ✓
- **BUT** the model is exactly "one **circular arc** number": no continuity
(squircle), no **harmony** between nested radii, no perceptual **family**, and
**static** (it never happens). You are ~on par with Tailwind; below SwiftUI
(continuity) and M3 (family + morph).
## 3. The novel model — 4 pieces
1.**Continuity (superellipse)** — a new axis `--shape-smoothing` (0 = circular
**perceptual** axis, not one of magnitude. Eidos canon (like roles/variants):
themeable values, canonical set.
4.**_Eventful_ shape (the genuinely new part)** — shape **tenses/relaxes** when
something happens: `contact`→squeezes corners, `commit`→rounds them, via the
**same signature** that already drives motion/depth. Shape-as-happening,
coordinated from **one single sema event**.
## 3.bis The two moments of shape
Shape respects the framework's **two-moments model** (motion F1) — it does not
reinvent it:
| Moment | Attribute (axis) | For shape | Phase |
|---|---|---|---|
| **state** | `data-state` (persistent) | the **resting shape** — magnitude (`--radius-*`) + family + continuity: how the element *is* | 1 |
| **event** | `data-event-*` (transient, during the `hold`) | the **morph** — squeeze/round on `contact`/`commit`: what *happens*. Ordered by `sequence`, next to the motion/depth signatures | 3 |
A control **has** a shape (state) **and tenses it** when pressed (event) — the
two moments, never collapsed. The book's same rigor (event ≠ state) carried to
shape.
## 4. Doctrine — _strong default, open cage_
| Piece | Strong default | Open door |
|---|---|---|
| **scale** | canonical `--radius-*` | config-driven (`EidosConfig` size/radius); raw `border-radius` always one step away |
| **continuity** | `--shape-smoothing` on by default (subtle) | global/per-component/per-element override; `0` returns to the pure arc |
| **family** | canonical set (rounded/continuous/cut/pill/sharp) | the set is **canon** but themeable; a wrapper composes its own without inventing a family |
| **nesting** | `--shape-nest` convention (concentric) | opt-in; the computation is transparent (`calc()`), overridable |
| **eventful** | `contact`↓squeeze / `commit`↑round | **opt-in/opt-out** (like sound/haptic/depth); sema's open registry; **degrades with `prefers-reduced-motion`**; static shape works without the channel |