fix(rotor): a disc on the panel, not a black tile in it

The dial painted its background as a full-bleed square, so inside the
rotor widget — which is already a card — it read as a hole punched in the
panel rather than an instrument sitting on it. It is a circle now, at the
radius the map already used, and the corners are left to whatever it is
drawn on. The wrapper loses its own border and background for the same
reason: one card, not two.

And the continents were barely there. At #202832 on a #0B1015 ground the
land was some eight per cent brighter than the sea — technically a map,
practically a dark square with a suggestion in it. The new shades read as
coastlines while staying well under the beams, which are what the dial is
actually for.

The palette stays deliberately unthemed. That was never the problem: a
map that repaints itself in four colour schemes stops being readable, and
the beams' green, orange and yellow have to mean the same thing in every
one of them.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
2026-09-08 22:00:39 +02:00
co-authored by Claude Opus 5
parent dbeabc1bae
commit a89be4b86e
2 changed files with 17 additions and 7 deletions
+13 -5
View File
@@ -81,8 +81,12 @@ type BeamKind = 'antenna' | 'hover';
const TARGET_YELLOW = '#FBBF24';
const MAP_BG_TOP = '#0B1015';
const MAP_BG_BOTTOM = '#080C11';
const MAP_LAND = '#202832';
const MAP_LAND_SECONDARY = '#25303A';
// The continents, and they have to be VISIBLE. At #202832 on a #0B1015 ground
// the land was some eight per cent brighter than the sea — technically a map,
// practically a dark square with a suggestion in it. These read as coastlines
// while staying well under the beams, which are what the dial is for.
const MAP_LAND = '#33414F';
const MAP_LAND_SECONDARY = '#41525F';
// What each rotor was last seen at, and what it was last told to do, kept
// OUTSIDE the component and keyed by rotor index.
@@ -289,7 +293,11 @@ function RotorCompassDial({
};
return (
<div className="w-full h-full min-w-0 aspect-square rounded-md border border-border bg-background flex items-center justify-center overflow-hidden">
// No card of its own, and no square: the dial is drawn as a disc and the
// corners are left to whatever it is sitting on. A black tile inside the
// rotor panel read as a hole punched in it — the widget is already a card,
// and this is an instrument on that card, not a second one.
<div className="w-full h-full min-w-0 aspect-square flex items-center justify-center overflow-hidden">
<svg
viewBox={`0 0 ${SIZE} ${SIZE}`}
className={cn('block w-full h-full select-none', onGoto ? 'cursor-crosshair' : 'cursor-default')}
@@ -338,10 +346,10 @@ function RotorCompassDial({
))}
</defs>
<rect x="0" y="0" width={SIZE} height={SIZE} fill={`url(#${bgGradientId})`} />
<circle cx={CENTER} cy={CENTER} r={MAP_RADIUS} fill={`url(#${bgGradientId})`} />
{landPath && (
<g mask={`url(#${mapFadeMaskId})`} opacity="0.78" pointerEvents="none">
<g mask={`url(#${mapFadeMaskId})`} opacity="0.92" pointerEvents="none">
<path d={landPath} fill={MAP_LAND} />
<path d={landPath} fill={MAP_LAND_SECONDARY} opacity="0.22" transform="translate(0.35 0.35)" />
</g>