controlsKit.layout — where the on-screen controls go.
Pure geometry: given a scheme's `touch` spec, the logical screen size and
the safe area, it answers where every stick and button sits and how big it
is. Nothing here touches the engine, so the tests run it directly at phone
sizes in both orientations.
Sizing is in logical points and comes from the screen's SHORT side, so a
phone gets thumb-sized controls in portrait and landscape alike:
stick radius clamp(short * 0.15, 56, 110)
button radius clamp(short * 0.075, 26, 52) (52pt+ across)
small button at least 24pt radius (48pt across, above the 44pt
touch-target minimum)
Everything stays inside the safe area plus a 16pt margin and is pushed out
of any cutout (notch, camera hole). When the two thumb clusters would
collide (narrow portrait), they shrink together, never below the minimum.
clamp(v: number, a: number, b: number) → number
| arg | type | description |
|---|
| v | number | |
| a | number | |
| b | number | |
units(w: number, h: number, scale: number?) → any
The control sizes for a screen: stick, button and small-button radii,
margin and gap, all in logical points.
| arg | type | description |
|---|
| w | number | Logical screen width. |
| h | number | Logical screen height. |
| scale | number? | Optional size preference (1 = default). |
clusterButtons(layout: string, actions: { string }, u: any, outer: number) → void
Offsets of a button cluster's buttons around its centre, before mirroring.
`outer` is +1 on the right-hand side (thumb rests to the right) and -1 on
the left. Returns the button circles and which actions overflowed.
| arg | type | description |
|---|
| layout | string | |
| actions | { string } | |
| u | any | |
| outer | number | |
clusterExtent(el: any, u: any, outer: number) → void
Half extents of a cluster around its centre.
| arg | type | description |
|---|
| el | any | |
| u | any | |
| outer | number | |
circleRect(c: any) → Rect
rectsHit(a: Rect, b: Rect) → boolean
| arg | type | description |
|---|
| a | Rect | |
| b | Rect | |
cutoutRects(safe: Safe) → void
| arg | type | description |
|---|
| safe | Safe | |
avoidCutouts(c: any, cuts: { Rect }, gap: number, w: number, h: number) → void
Push a circle out of every cutout along the shortest way back into the
interior of the screen.
| arg | type | description |
|---|
| c | any | |
| cuts | { Rect } | |
| gap | number | |
| w | number | |
| h | number | |
normSafe(safe: any?) → Safe
| arg | type | description |
|---|
| safe | any? | |
compute(touch: any, w: number, h: number, safe: any?, opts: any?) → any
Place a scheme's touch controls on a screen.
| arg | type | description |
|---|
| touch | any | The scheme's `touch` spec (left, right, extras, corner, backdrop). |
| w | number | Logical screen width. |
| h | number | Logical screen height. |
| safe | any? | Safe-area insets { left, top, right, bottom, cutouts }. |
| opts | any? | { scale?: number } — a size preference, 1 by default. |
_computeAt(touch: any, w: number, h: number, sf: Safe, scale: number) → any
| arg | type | description |
|---|
| touch | any | |
| w | number | |
| h | number | |
| sf | Safe | |
| scale | number | |
cluster(side: string, el: any) → void
| arg | type | description |
|---|
| side | string | |
| el | any | |
report(placed: any) → any
Check a computed layout: circles that overlap, leave the screen, leave
the safe area, touch a cutout, or are smaller than a thumb.
| arg | type | description |
|---|
| placed | any | The table `compute` returned. |
hitsCutout(c: any, safe: any) → boolean
Whether a circle touches any cutout in a safe-area spec.
| arg | type | description |
|---|
| c | any | |
| safe | any | |
⌬ Types
Rect = { x0: number, y0: number, x1: number, y1: number }Safe = { left: number, top: number, right: number, bottom: number, cutouts: { any }? }Circle = { id: string, action: string?, x: number, y: number, r: number, role: string }