Add the Extrudex Design System v3 bundle

Tokens (light + dark, neumorphism, 54/54 WCAG AA contrast pairs), the
self-hosted JetBrains Mono fonts, and interactive mockups of every screen
across three iterations. Iteration 3 is final: phone, tablet and desktop
tiers, device preview, and "empty spool weight" terminology. The build
scripts regenerate the screens byte-identically from source.

Implementation is tracked in Maestro feature UI Refresh - V3.0
(224b72a1-8d84-4970-97ea-5dafa4d8ea3b).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joshua King
2026-09-19 11:31:50 -04:00
co-authored by Claude Opus 5
parent 9ba0d409c8
commit d9ed1898b9
67 changed files with 33632 additions and 1 deletions
+10
View File
@@ -0,0 +1,10 @@
def lum(h):
h=h.lstrip('#'); r,g,b=[int(h[i:i+2],16)/255 for i in (0,2,4)]
f=lambda c: c/12.92 if c<=0.03928 else ((c+0.055)/1.055)**2.4
return 0.2126*f(r)+0.7152*f(g)+0.0722*f(b)
def cr(a,b):
la,lb=sorted([lum(a),lum(b)],reverse=True); return (la+0.05)/(lb+0.05)
import sys
pairs=[l.split() for l in sys.stdin if l.strip()]
for p in pairs:
print(f"{p[0]:>9} on {p[1]:>9} {cr(p[0],p[1]):5.2f} {' '.join(p[2:])}")
+22
View File
@@ -0,0 +1,22 @@
import pathlib; exec(open(pathlib.Path(__file__).with_name('contrast.py')).read().split('import sys')[0])
def blend(fg,bg,a):
f=[int(fg[i:i+2],16) for i in (1,3,5)]; b=[int(bg[i:i+2],16) for i in (1,3,5)]
return '#'+''.join(f'{round(x*a+y*(1-a)):02x}' for x,y in zip(f,b))
D=dict(page='#2c2c30',inset='#232327',high='#36363a',text='#f4f4f6',muted='#b2b2ba',acc='#a99af0',accbg='#a99af0',onacc='#2a2431',ctl='#85858f',ok='#a9d88b',err='#f08b93',warn='#e8c170',info='#8fc3f0')
L=dict(page='#e4e2ea',inset='#d9d6e1',high='#f1f0f5',text='#2a2431',muted='#55505f',acc='#5b43b8',accbg='#5b43b8',onacc='#ffffff',ctl='#736e86',ok='#2c6619',err='#a8202f',warn='#7c5100',info='#1d5e94')
rows=[]
for name,T in (('Dark',D),('Light',L)):
chk=[('Body text','text','page',4.5),('Body text on inset (inputs)','text','inset',4.5),('Body text on high surface (dialog)','text','high',4.5),
('Secondary text','muted','page',4.5),('Secondary text on inset','muted','inset',4.5),('Secondary text on high','muted','high',4.5),
('Accent text / links','acc','page',4.5),('Accent text on high','acc','high',4.5),('Text on primary button','onacc','accbg',4.5),
('Success text','ok','page',4.5),('Error text','err','page',4.5),('Error text on high','err','high',4.5),('Warning text','warn','page',4.5),('Info text','info','page',4.5),
('Control border vs page (1.4.11)','ctl','page',3),('Control border vs inset','ctl','inset',3),('Control border vs high','ctl','high',3),('Focus ring vs page','acc','page',3),('Focus ring vs high','acc','high',3),
('Primary button fill vs page','accbg','page',3),('Error border vs inset','err','inset',3),('Warning border vs page','warn','page',3)]
for label,a,b,need in chk:
r=cr(T[a],T[b]); rows.append((name,label,T[a],T[b],r,need))
# tinted chips: 10% wash of status over page
for s in ('ok','err','warn','info','acc'):
bg=blend(T[s],T['page'],0.10); r=cr(T[s],bg); rows.append((name,f'{s} chip text on 10% wash',T[s],bg,r,4.5))
print('| Theme | Pair | Foreground | Background | Ratio | Needs | Result |\n|---|---|---|---|---|---|---|')
for n,l,a,b,r,need in rows:
print(f"| {n} | {l} | `{a}` | `{b}` | {r:.2f}:1 | {need}:1 | {'Pass' if r>=need else '**FAIL**'} |")