SquircleKeycap

A key drawn as a superellipse and extruded, which travels when you press it.

press the key

Paste into Claude Code, Cursor or any agent. Pinned to a tag, so it will not change under you.

Options

plate #efece3

css colour

The surface the key sits on. Slightly darker than the cap, because a key is lighter than the thing it is set into and that difference is most of what says it stands up.

cap #fbfaf6

css colour

The top of the key.

side #d6d1c4

css colour

The sides, which are what makes it a solid rather than a sticker. It wants to be a clear step darker than the cap: this is a facet turned away from the light, not a shadow.

ink #2b2a26

css colour

The legend, and the contact shadow under the key.

legend K

What is printed on the key. One or two characters: it is set at under a third of the key's width, and a word at that size is a label on a key rather than a key.

corner 4.2

2 to 16, good: 3 to 6

The superellipse exponent. 2 is an ellipse, 4 is the shape everybody means by a squircle, and by 12 it is a rectangle with a hint of a corner. The useful range is narrow and the difference inside it is the whole item.

size 0.56

0.15 to 0.9

How much of the shorter side of the element the key takes up.

depth 0.16

0.02 to 0.4, good: 0.1 to 0.24

How tall the key stands, as a share of its width. This is the thing the press has to eat into, so a flat key has nowhere to travel and reads as a flicker.

travel 0.62

0.1 to 1, good: 0.5 to 0.8

How far down it goes when pressed, as a share of its height. At 1 it bottoms out flush with the plate, which reads as broken rather than as pressed.

snap 0.13

0.03 to 0.6, good: 0.08 to 0.2

Seconds the key takes to come back up. The way down is fixed and fast, because that is a key hitting a stop; this is the rubber dome, and it is the only half with any character in it.

What it needs

Category
Surfaces, an effect
Dependencies
None at all
Browser
No WebGL
Frame budget
~0.5 ms · 0 context
Pinned to
v0.14.0
  • The shape is the point. A border-radius is a rectangle with circular arcs stuck on the corners, and the join between the straight edge and the arc is continuous in position and direction but not in curvature: it jumps from zero to one over the radius, instantly. A superellipse has no join at all, because it is one equation the whole way round
  • Walked as a path rather than approximated, so the exponent is a real control: 2 is an ellipse, 4 is the shape everybody means, and by 12 it is a rectangle with a suggestion of a corner. No value of border-radius lands on any of them
  • The exponent is applied to the absolute value of the cosine and the sign put back, because a fractional power of a negative number is not a number and the left half of the shape would simply not be drawn
  • The travel is a closed form of the time since the press, so renderAtTime is pure in t. A key is state between frames by nature, which is the one thing this library will not have: the resolution is to keep the list of presses rather than the position and work the displacement out from the clock. Seeking backwards unpresses the key, which a spring integrated frame by frame can never do
  • An attack and a decay, not a spring. A keycap does not oscillate: it goes down against a stop, fast and ending abruptly, and comes back on a rubber dome, slower and settling without overshoot
  • The side is drawn as its own extrusion rather than as a drop shadow, which is the difference between a key and a sticker. It is also what makes the travel legible: the side gets shorter as the key goes down, and that is the part anyone actually reads
  • The top is dished rather than domed. A keycap is concave so a fingertip sits in it, and what reports that is a soft dark edge at the top of the face, not a highlight in the middle
  • A press anywhere on the element counts rather than only inside the drawn shape. A click two pixels outside the edge is a click the reader believes they made
  • 2D rather than WebGL. A key is something you want several of on a page, and the budget is one WebGL context
  • It is a drawing of a control, not a control. There is no role, no focus and no keyboard handling, because a canvas cannot carry them. Put it behind a real button if it is going to do something
  • Two filled paths of a hundred and twenty points, a clipped gradient and one glyph