Skip to content

Add squircle wiki page - #154

Open
raphlinus wants to merge 9 commits into
mainfrom
squircle
Open

raphlinus wants to merge 9 commits into
mainfrom
squircle

Conversation

@raphlinus

Copy link
Copy Markdown
Contributor

A whole bunch of information about squircles, including an interactive tester that makes it easy to compare the main variants. There's some historical info and some math, tying together the original superellipse version, the Apple iOS 7 icon design, and the popular Figma variant, as well as the newer corner-shape property and its Chromium implementation.

AI disclosure: the initial version of the xilem_web interactive tester, including implementation of the math, was done arduously by hand. To push this over the edge, I used Claude Code to refine the UI and integrate it into the Wiki (among other things, it helpfully did dark mode by itself). All text was written by hand, but I used Claude to find typos and other such problems (there were a bunch).

Note: we'll need to either delete "discussion question" or fill it in.

raphlinus and others added 9 commits September 18, 2026 02:57
Adds a wiki page comparing four squircle constructions, with an embedded
xilem_web demo for exploring them, following the approach prototyped in #131.

Demos live in a crates/ workspace, matching the layout already used on the
log-aesthetic branch.
Each is a cdylib exporting start(id), which wasm-bindgen packages into
static/rust/ for the page to import and mount.
Each also has a bin target so `trunk serve` still works for local iteration
against that same entry point; site builds pass --lib, so it is never compiled
in CI.

crates/build.sh is what both the deploy workflow and local use beside
`zola serve` run, so the two cannot drift.
It builds only the crates that declare a cdylib, so native tools that share
this workspace are never compiled for wasm.

The tester is ported from a standalone prototype, with the formatting reworked
for embedding: the radios and the zoom toggle are labelled, the curvature
profile moved out of the shape's coordinate space into its own panel, the SVGs
carry a viewBox instead of fixed pixel sizes so they reflow, and stroke colors
come from CSS custom properties so the demo follows the site's light and dark
themes.

Two fixes to the ported math:

Superellipse::curvature_profile swept only a half quadrant, while the other
constructions sweep a full one, so selecting it silently halved the plot's arc
length axis.

render_profile now drops non-finite samples and breaks the polyline across the
gap.
At the bottom of the gauge range the Figma corner collapses to a cubic whose
first three control points coincide, making its curvature 0/0, and a single NaN
makes a browser reject the whole SVG path.
Adds the rounded rectangle Apple introduced in iOS 7 as a fifth construction,
labelled "Apple".

The control points are Apple's own, recovered by PaintCode by walking the live
CGPath with CGPathApply, and published at
https://www.paintcodeapp.com/blogpost/code-for-ios-7-rounded-rectangles

This renders the square aspect ratio at the largest corner radius the
construction allows, which is where the flat sides vanish and one corner spans
a full quadrant, so it sits on the same footing as the other four.
The flat side length is the parameter this shape really has; that is not wired
up yet, so render ignores the gauge.

The quadrant is neither symmetric about its diagonal nor curvature continuous.
A short straight run sits on one side of the diagonal, and curvature steps from
1.638 to 1.095 at the join between the last two cubics.
Both are properties of Apple's shape rather than of the transcription, so the
module says to reproduce the path as published and not tidy it; the temptation
is real, since mirroring the corner's other half makes it symmetric.
Figma and Lisse both report the same asymmetry, and Figma's curvature figure
plots a corner they had already repaired that way.
A shape is a corner profile scaled into the square left by a straight run
along each half edge. Corner::resolve maps the two sliders onto that;
quadrant and quadrant_profile assemble the shape and its curvature.

The gauge always holds, so the radio buttons compare constructions at one
gauge. The flat picks the corner within what the gauge allows; where a
construction's family has no such corner it makes the nearest one and the
flat takes up the difference. The clothoid tops out near 0.79 and Apple
has a single corner, so for those the flat is largely determined.

The superellipse and the Chromium approximation take the gauge directly.
The clothoid and Figma take a smoothness instead, so those are solved for
with solve_itp against the measured diagonal crossing.

Show the superellipse exponent where it applies, greyed elsewhere.

Fix Superellipse::curvature_profile, which did not pin its endpoint the
way render does: the last theta overshoots FRAC_PI_2, and powf of the
negative cosine put a NaN into the arc length.

The curvature plot's arc length axis is now absolute rather than fitted,
with a tick where the curve ends.
Drop the superellipse reference and its legend, which were a development
aid rather than something to ship.

Add a fill checkbox. A zoomed quadrant is an open path, so filling that
closes it through the centre.

Label the curvature axis at each gridline, and drop the caption under the
plot in favour of explaining it in prose.
The radio buttons read as a choice without a heading; the name survives
as an aria-label.

Also corrects two stale doc comments on AppState: the gauge is no longer
derived where the corner is fixed, and the superellipse reference is gone.
This an edited version of the draft I had posted to Zulip.
A superellipse with exponent 3 and a flat side chosen to match the gauge is a very close match to the Apple shape.

Figure was generated by Claude.
@DJMcNab

DJMcNab commented Sep 21, 2026

Copy link
Copy Markdown
Member

(Just as a note, I'd like to avoid merging PRs with a recorded Co-Authored-By: Claude if at all possible - although admittedly, I haven't driven that through the process, I also haven't seen any pushback in favour of it either)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants