v2 audit: contrast, dark-glow, layout, palette, sizing fixes

All fixes from impeccable browser audit:
- Removed/reduced 18 dark-glow box-shadows (AI tells)
- Fixed contrast: muted text, badge-blue, badge-amber, kebab opacity
- Removed cyan neon palette (#60C0D0 → #5090A0, #60A0E0 → #6080B0)
- Changed layout transitions from width to transform (jank-free)
- Bumped tiny text sizes (9px→10px, 10px→11px)
- Fixed cramped padding on preset chips
This commit is contained in:
2026-06-14 18:50:23 -04:00
parent 3dcf31f600
commit 87ee14e4e5
9 changed files with 45 additions and 48 deletions
+13 -13
View File
@@ -81,7 +81,7 @@ const BLOCK_PARAMS = {
const BLOCK_COLORS = { const BLOCK_COLORS = {
overdrive: T.amber, distortion: T.red, fuzz: '#C07030', overdrive: T.amber, distortion: T.red, fuzz: '#C07030',
delay: T.blue, echo: T.blue, reverb: '#60B0D0', delay: T.blue, echo: T.blue, reverb: '#5090A0',
chorus: T.green, flanger: '#50C080', phaser: '#80C050', chorus: T.green, flanger: '#50C080', phaser: '#80C050',
tremolo: T.green, compressor: '#D09040', gate: T.textSec, eq: '#7080D0', tremolo: T.green, compressor: '#D09040', gate: T.textSec, eq: '#7080D0',
cabinet: '#D07090', ir: '#D07090', nam: '#E0A040', nam_amp: '#E0A040', boost: T.amber, cabinet: '#D07090', ir: '#D07090', nam: '#E0A040', nam_amp: '#E0A040', boost: T.amber,
@@ -139,9 +139,9 @@ const css = `
background: radial-gradient(circle at 35% 30%, #3A3A48, #1A1A22); background: radial-gradient(circle at 35% 30%, #3A3A48, #1A1A22);
box-shadow: 0 2px 8px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.07); } box-shadow: 0 2px 8px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.07); }
.knob-dot { position: absolute; width: 3px; border-radius: 2px; background: var(--amber); .knob-dot { position: absolute; width: 3px; border-radius: 2px; background: var(--amber);
left: 50%; transform-origin: bottom center; box-shadow: 0 0 6px var(--amber); } left: 50%; transform-origin: bottom center; }
.knob-label { font-size: 9px; color: var(--text-sec); letter-spacing: .06em; text-transform: uppercase; text-align: center; } .knob-label { font-size: 10px; color: var(--text-sec); letter-spacing: .06em; text-transform: uppercase; text-align: center; }
.knob-value { font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--amber); } .knob-value { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--amber); }
/* ── Buttons ── */ /* ── Buttons ── */
.btn { padding: 8px 14px; border-radius: 6px; font-size: 12px; font-weight: 600; .btn { padding: 8px 14px; border-radius: 6px; font-size: 12px; font-weight: 600;
@@ -169,14 +169,14 @@ const css = `
/* ── Param slider ── */ /* ── Param slider ── */
.param-panel { background: var(--surface); padding: 8px 12px 6px; border-top: 1px solid var(--border); flex-shrink: 0; } .param-panel { background: var(--surface); padding: 8px 12px 6px; border-top: 1px solid var(--border); flex-shrink: 0; }
.param-panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2px; } .param-panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2px; }
.param-panel-title { font-size: 10px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--text-sec); } .param-panel-title { font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--text-sec); }
.param-row { display: flex; flex-direction: column; gap: 1px; padding: 1px 0; } .param-row { display: flex; flex-direction: column; gap: 1px; padding: 1px 0; }
.param-header { display: flex; justify-content: space-between; align-items: center; } .param-header { display: flex; justify-content: space-between; align-items: center; }
.param-label { font-size: 9px; font-weight: 500; text-transform: uppercase; letter-spacing: .06em; color: var(--text-sec); } .param-label { font-size: 10px; font-weight: 500; text-transform: uppercase; letter-spacing: .06em; color: var(--text-sec); }
.param-val { font-family: 'JetBrains Mono',monospace; font-size: 11px; font-weight: 600; } .param-val { font-family: 'JetBrains Mono',monospace; font-size: 11px; font-weight: 600; }
.param-track-wrap { position: relative; height: 30px; display: flex; align-items: center; cursor: pointer; touch-action: none; } .param-track-wrap { position: relative; height: 30px; display: flex; align-items: center; cursor: pointer; touch-action: none; }
.param-track { width: 100%; height: 6px; background: var(--border); border-radius: 3px; position: relative; overflow: hidden; } .param-track { width: 100%; height: 6px; background: var(--border); border-radius: 3px; position: relative; overflow: hidden; }
.param-fill { height: 100%; border-radius: 3px; position: absolute; top: 0; left: 0; transition: width .04s; } .param-fill { height: 100%; border-radius: 3px; position: absolute; top: 0; left: 0; transform-origin: left center; transition: transform .04s; }
.param-thumb { width: 22px; height: 22px; border-radius: 50%; position: absolute; top: 50%; .param-thumb { width: 22px; height: 22px; border-radius: 50%; position: absolute; top: 50%;
transform: translate(-50%,-50%); box-shadow: 0 1px 6px rgba(0,0,0,.6); pointer-events: none; transform: translate(-50%,-50%); box-shadow: 0 1px 6px rgba(0,0,0,.6); pointer-events: none;
border: 3px solid var(--bg); } border: 3px solid var(--bg); }
@@ -193,7 +193,7 @@ const css = `
.screen-body { flex: 1; overflow-y: auto; padding: 10px 12px; display: flex; flex-direction: column; gap: 10px; } .screen-body { flex: 1; overflow-y: auto; padding: 10px 12px; display: flex; flex-direction: column; gap: 10px; }
/* ── Preset sidebar chip ── */ /* ── Preset sidebar chip ── */
.preset-chip-s { width: 100%; padding: 7px 6px; border-radius: 5px; background: var(--surface); border: 1px solid var(--border); .preset-chip-s { width: 100%; padding: 8px 8px; border-radius: 5px; background: var(--surface); border: 1px solid var(--border);
display: flex; flex-direction: column; align-items: center; cursor: pointer; transition: all .12s; } display: flex; flex-direction: column; align-items: center; cursor: pointer; transition: all .12s; }
.preset-chip-s.active { border-color: var(--amber); background: rgba(232,160,48,.08); } .preset-chip-s.active { border-color: var(--amber); background: rgba(232,160,48,.08); }
.preset-chip-s:active { transform: scale(.96); } .preset-chip-s:active { transform: scale(.96); }
@@ -271,7 +271,7 @@ function Knob({ label, value = 50, onChange, size = 48, color = T.amber, min = 0
<div className="knob" style={{width:size,height:size}} onMouseDown={handleStart} onTouchStart={handleStart}> <div className="knob" style={{width:size,height:size}} onMouseDown={handleStart} onTouchStart={handleStart}>
<svg style={{position:"absolute",inset:-6,width:svgSize,height:svgSize,overflow:"visible"}}> <svg style={{position:"absolute",inset:-6,width:svgSize,height:svgSize,overflow:"visible"}}>
<circle cx={cx} cy={cy} r={r} fill="none" stroke={T.border} strokeWidth="2" strokeLinecap="round" opacity=".5"/> <circle cx={cx} cy={cy} r={r} fill="none" stroke={T.border} strokeWidth="2" strokeLinecap="round" opacity=".5"/>
{norm>0&&<path d={`M ${lx} ${ly} A ${r} ${r} 0 ${large} 1 ${ex} ${ey}`} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" style={{filter:`drop-shadow(0 0 3px ${color})`}}/>} {norm>0&&<path d={`M ${lx} ${ly} A ${r} ${r} 0 ${large} 1 ${ex} ${ey}`} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" style={{opacity:0.8}}/>}
</svg> </svg>
<div className="knob-inner" style={{"--amber":color}}> <div className="knob-inner" style={{"--amber":color}}>
<div className="knob-dot" style={{height:dotH,top:dotTop,transform:`translateX(-50%) rotate(${angle}deg)`,transformOrigin:`50% ${dotH}px`}}/> <div className="knob-dot" style={{height:dotH,top:dotTop,transform:`translateX(-50%) rotate(${angle}deg)`,transformOrigin:`50% ${dotH}px`}}/>
@@ -323,7 +323,7 @@ function ParamSlider({ label,value=50,onChange,onChangeEnd,min=0,max=100,color=T
</div> </div>
<div className="param-track-wrap" ref={trackRef} onMouseDown={handleStart} onTouchStart={handleStart}> <div className="param-track-wrap" ref={trackRef} onMouseDown={handleStart} onTouchStart={handleStart}>
<div className="param-track"> <div className="param-track">
<div className="param-fill" style={{width:`${pct}%`,background:color}}/> <div className="param-fill" style={{transform:`scaleX(${pct/100})`,background:color}}/>
<div className="param-thumb" style={{left:`${pct}%`,background:color}}/> <div className="param-thumb" style={{left:`${pct}%`,background:color}}/>
</div> </div>
</div> </div>
@@ -409,7 +409,7 @@ function VUMeter({level=0,height=24,vertical=false}){const segs=12,active=Math.r
const segH=Math.max(3,(height-segs*1.5)/segs); const segH=Math.max(3,(height-segs*1.5)/segs);
const c=i=>i>=10?T.red:i>=8?"#E8C030":T.green; const c=i=>i>=10?T.red:i>=8?"#E8C030":T.green;
if(vertical)return(<div style={{display:"flex",flexDirection:"column-reverse",gap:1.5,height,alignItems:"center"}}> if(vertical)return(<div style={{display:"flex",flexDirection:"column-reverse",gap:1.5,height,alignItems:"center"}}>
{Array.from({length:segs}).map((_,i)=>(<div key={i} style={{width:4,height:segH,borderRadius:1.5,background:i<active?c(i):T.border,boxShadow:i<active?`0 0 4px ${c(i)}`:"none",transition:"all .2s ease, opacity .15s"}}/>))}</div>); {Array.from({length:segs}).map((_,i)=>(<div key={i} style={{width:4,height:segH,borderRadius:1.5,background:i<active?c(i):T.border,transition:"all .2s ease, opacity .15s"}}/>))}</div>);
return(<div style={{display:"flex",gap:2,height:6,alignItems:"center",width:height}}> return(<div style={{display:"flex",gap:2,height:6,alignItems:"center",width:height}}>
{Array.from({length:segs}).map((_,i)=>(<div key={i} style={{flex:1,height:"100%",borderRadius:1,background:i<active?c(i):T.border,transition:"all .2s ease"}}/>))}</div>); {Array.from({length:segs}).map((_,i)=>(<div key={i} style={{flex:1,height:"100%",borderRadius:1,background:i<active?c(i):T.border,transition:"all .2s ease"}}/>))}</div>);
} }
@@ -430,7 +430,7 @@ function CapturesScreen({onClose}){
<div style={{flex:1,display:"flex",background:T.surface,borderRadius:6,border:`1px solid ${T.border}`,padding:"6px 10px",gap:6,alignItems:"center"}}> <div style={{flex:1,display:"flex",background:T.surface,borderRadius:6,border:`1px solid ${T.border}`,padding:"6px 10px",gap:6,alignItems:"center"}}>
<span style={{color:T.textDim,fontSize:11}}>🔍</span> <span style={{color:T.textDim,fontSize:11}}>🔍</span>
<input placeholder={`Search ${tab==="models"?"NAM models":"IR cabs"}...`}value={query}onChange={e=>setQuery(e.target.value)}onKeyDown={e=>e.key==="Enter"&&doSearch()}style={{flex:1,background:"none",border:"none",color:T.textPrimary,fontSize:12,outline:"none"}}/></div> <input placeholder={`Search ${tab==="models"?"NAM models":"IR cabs"}...`}value={query}onChange={e=>setQuery(e.target.value)}onKeyDown={e=>e.key==="Enter"&&doSearch()}style={{flex:1,background:"none",border:"none",color:T.textPrimary,fontSize:12,outline:"none"}}/></div>
<button className="btn btn-primary"style={{padding:"6px 11px",fontSize:11}}onClick={doSearch}>{loading?"...":"Search"}</button></div> <button className="btn btn-primary"style={{padding:"6px 11px",fontSize:11,color:"#000"}}onClick={doSearch}>{loading?"...":"Search"}</button></div>
<div className="screen-body"> <div className="screen-body">
{results===null&&models.length>0&&(<><div className="section-label">Installed Models</div> {results===null&&models.length>0&&(<><div className="section-label">Installed Models</div>
{models.map((m,i)=>(<div key={i}className="preset-row"style={{cursor:"default"}}> {models.map((m,i)=>(<div key={i}className="preset-row"style={{cursor:"default"}}>
@@ -836,7 +836,7 @@ export default function App(){
<span style={{fontSize:12,lineHeight:1}}></span> <span style={{fontSize:12,lineHeight:1}}></span>
</button>} </button>}
<div style={{width:6,height:6,borderRadius:"50%", <div style={{width:6,height:6,borderRadius:"50%",
background:state.connected?T.green:T.red,boxShadow:`0 0 6px ${state.connected?T.green:T.red}`}}/> background:state.connected?T.green:T.red}}/>
{!isNarrow&&<span className="mono" style={{fontSize:9,color:state.connected?T.green:T.red}}>{state.connected?"CONNECTED":"OFFLINE"}</span>} {!isNarrow&&<span className="mono" style={{fontSize:9,color:state.connected?T.green:T.red}}>{state.connected?"CONNECTED":"OFFLINE"}</span>}
{/* Undo/Redo */} {/* Undo/Redo */}
<button className="btn-icon" style={{width:44,height:44,fontSize:14,opacity:undoStack.length>0?1:0.3}} <button className="btn-icon" style={{width:44,height:44,fontSize:14,opacity:undoStack.length>0?1:0.3}}
+2 -3
View File
@@ -16,7 +16,7 @@ const TYPE_COLORS = {
fuzz: "#D060E0", fuzz: "#D060E0",
mod: T.blue, chorus: T.blue, flange: T.blue, phaser: T.blue, mod: T.blue, chorus: T.blue, flange: T.blue, phaser: T.blue,
tremolo: T.blue, vibrato: T.blue, rotary: T.blue, tremolo: T.blue, vibrato: T.blue, rotary: T.blue,
delay: "#60A0E0", echo: "#60A0E0", reverb: "#60C0D0", delay: "#6080B0", echo: "#6080B0", reverb: "#5090A0",
pitch: "#A060E0", comp: T.green, compressor: T.green, pitch: "#A060E0", comp: T.green, compressor: T.green,
gate: T.green, filter: "#D0A060", wah: "#D0A060", gate: T.green, filter: "#D0A060", wah: "#D0A060",
eq: "#80A0B0", ir: T.green, cab: T.green, nam: "#E0A040", eq: "#80A0B0", ir: T.green, cab: T.green, nam: "#E0A040",
@@ -373,12 +373,11 @@ function BlockTile({ block, selected, onSelect, onToggle, pathLabel, onModelBrow
<div style={{ <div style={{
position: "absolute", top: 0, left: 0, right: 0, height: 3, position: "absolute", top: 0, left: 0, right: 0, height: 3,
background: color, background: color,
boxShadow: enabled ? `0 0 6px ${color}` : "none",
}} /> }} />
{/* Drag handle */} {/* Drag handle */}
<div style={{ <div style={{
position: "absolute", top: 5, left: 5, fontSize: 9, color: T.textDim, position: "absolute", top: 5, left: 5, fontSize: 9, color: T.textDim,
letterSpacing: 1.5, lineHeight: 1, cursor: "grab", opacity: 0.5, letterSpacing: 1.5, lineHeight: 1, cursor: "grab",
}}> }}>
</div> </div>
+7 -6
View File
@@ -21,7 +21,7 @@ const BLOCK_PARAMS = {
const BLOCK_COLORS = { const BLOCK_COLORS = {
overdrive: T.amber, distortion: T.red, fuzz: '#C07030', overdrive: T.amber, distortion: T.red, fuzz: '#C07030',
delay: T.blue, echo: T.blue, reverb: '#60B0D0', delay: T.blue, echo: T.blue, reverb: '#5090A0',
chorus: T.green, flanger: '#50C080', phaser: '#80C050', chorus: T.green, flanger: '#50C080', phaser: '#80C050',
tremolo: T.green, compressor: '#D09040', gate: T.textSec, eq: '#7080D0', tremolo: T.green, compressor: '#D09040', gate: T.textSec, eq: '#7080D0',
cabinet: '#D07090', ir: '#D07090', nam: '#E0A040', boost: T.amber, cabinet: '#D07090', ir: '#D07090', nam: '#E0A040', boost: T.amber,
@@ -95,7 +95,7 @@ function FocusKnob({ label, value = 50, onChange, size = 72, color = T.amber, mi
onMouseDown={handleStart} onTouchStart={handleStart}> onMouseDown={handleStart} onTouchStart={handleStart}>
<svg style={{ position: 'absolute', inset: -8, width: svgSize, height: svgSize, overflow: 'visible' }}> <svg style={{ position: 'absolute', inset: -8, width: svgSize, height: svgSize, overflow: 'visible' }}>
<circle cx={cx} cy={cy} r={r} fill="none" stroke={T.border} strokeWidth="3" strokeLinecap="round" opacity=".5" /> <circle cx={cx} cy={cy} r={r} fill="none" stroke={T.border} strokeWidth="3" strokeLinecap="round" opacity=".5" />
{norm > 0 && <path d={`M ${lx} ${ly} A ${r} ${r} 0 ${large} 1 ${ex} ${ey}`} fill="none" stroke={color} strokeWidth="3" strokeLinecap="round" style={{ filter: `drop-shadow(0 0 4px ${color})` }} />} {norm > 0 && <path d={`M ${lx} ${ly} A ${r} ${r} 0 ${large} 1 ${ex} ${ey}`} fill="none" stroke={color} strokeWidth="3" strokeLinecap="round" style={{ opacity: 0.8 }} />}
</svg> </svg>
<div style={{ <div style={{
borderRadius: '50%', width: '100%', height: '100%', position: 'relative', borderRadius: '50%', width: '100%', height: '100%', position: 'relative',
@@ -108,7 +108,7 @@ function FocusKnob({ label, value = 50, onChange, size = 72, color = T.amber, mi
height: dotH, top: dotTop, height: dotH, top: dotTop,
transform: `translateX(-50%) rotate(${angle}deg)`, transform: `translateX(-50%) rotate(${angle}deg)`,
transformOrigin: `50% ${dotH}px`, transformOrigin: `50% ${dotH}px`,
boxShadow: `0 0 6px ${color}`, boxShadow: `0 0 4px ${color}33`,
}} /> }} />
</div> </div>
</div> </div>
@@ -193,9 +193,10 @@ function FocusSlider({ label, value = 50, onChange, onChangeEnd, min = 0, max =
}}> }}>
<div style={{ <div style={{
height: '100%', borderRadius: 5, position: 'absolute', top: 0, left: 0, height: '100%', borderRadius: 5, position: 'absolute', top: 0, left: 0,
width: `${pct}%`, background: color, width: '100%', background: color,
boxShadow: `0 0 8px ${color}44`, transition: 'transform .03s',
transition: 'width .03s', transform: `scaleX(${pct/100})`,
transformOrigin: 'left center',
}} /> }} />
</div> </div>
<div style={{ <div style={{
+3 -5
View File
@@ -4,7 +4,7 @@ import { T } from "./theme.js";
const TYPE_COLORS = { const TYPE_COLORS = {
overdrive: T.amber, drive: T.amber, distortion: T.red, fuzz: "#D060E0", overdrive: T.amber, drive: T.amber, distortion: T.red, fuzz: "#D060E0",
chorus: T.blue, flanger: T.blue, phaser: T.blue, tremolo: T.blue, chorus: T.blue, flanger: T.blue, phaser: T.blue, tremolo: T.blue,
delay: "#60A0E0", echo: "#60A0E0", reverb: "#60C0D0", delay: "#6080B0", echo: "#6080B0", reverb: "#5090A0",
compressor: T.green, gate: T.green, eq: "#80A0B0", compressor: T.green, gate: T.green, eq: "#80A0B0",
ir: T.green, cab: T.green, nam: "#E0A040", ir: T.green, cab: T.green, nam: "#E0A040",
}; };
@@ -60,8 +60,8 @@ function Footswitch({ id, label, mainLabel, type, sub, active, enabled, onClick,
cursor: "pointer", minHeight: 58, position: "relative", cursor: "pointer", minHeight: 58, position: "relative",
transition: "all .1s", WebkitTapHighlightColor: "transparent", transition: "all .1s", WebkitTapHighlightColor: "transparent",
boxShadow: isActive && !isBypassSwitch boxShadow: isActive && !isBypassSwitch
? `0 0 8px ${T.amber}33, inset 0 0 0 1px ${T.amber}22` ? `inset 0 0 0 1px ${T.amber}22`
: isBypassSwitch && !enabled ? `0 0 8px ${T.red}33` : "none", : isBypassSwitch && !enabled ? `inset 0 0 0 1px ${T.red}22` : "none",
}} }}
> >
{/* Scribble strip */} {/* Scribble strip */}
@@ -70,7 +70,6 @@ function Footswitch({ id, label, mainLabel, type, sub, active, enabled, onClick,
border: `1px solid ${isActive ? T.amber + "66" : T.border}`, border: `1px solid ${isActive ? T.amber + "66" : T.border}`,
borderRadius: 3, padding: "2px 2px", textAlign: "center", borderRadius: 3, padding: "2px 2px", textAlign: "center",
minHeight: 18, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 18, display: "flex", alignItems: "center", justifyContent: "center",
boxShadow: isActive ? `inset 0 0 4px ${T.amber}22` : "none",
}}> }}>
<span style={{ <span style={{
fontFamily: "'JetBrains Mono', monospace", fontSize: 7, fontWeight: 700, fontFamily: "'JetBrains Mono', monospace", fontSize: 7, fontWeight: 700,
@@ -105,7 +104,6 @@ function Footswitch({ id, label, mainLabel, type, sub, active, enabled, onClick,
position: "absolute", top: 3, right: 3, width: 4, height: 4, position: "absolute", top: 3, right: 3, width: 4, height: 4,
borderRadius: "50%", borderRadius: "50%",
background: enabled !== false ? T.green : T.textDim, background: enabled !== false ? T.green : T.textDim,
boxShadow: enabled !== false ? `0 0 5px ${T.green}` : "none",
transition: "all .15s", transition: "all .15s",
}} /> }} />
)} )}
+3 -3
View File
@@ -3,7 +3,7 @@ import { T } from "./theme.js";
// ── EQ Band definitions ── // ── EQ Band definitions ──
const EQ_BANDS = [ const EQ_BANDS = [
{ key: "low", label: "Low", freq: "80 Hz", color: "#60A0E0", shadow: "#60A0E044" }, { key: "low", label: "Low", freq: "80 Hz", color: "#5090A0", shadow: "#5090A044" },
{ key: "mid", label: "Mid", freq: "800 Hz", color: T.amber, shadow: `${T.amber}44` }, { key: "mid", label: "Mid", freq: "800 Hz", color: T.amber, shadow: `${T.amber}44` },
{ key: "high", label: "High", freq: "6.4 kHz",color: "#60D080", shadow: "#60D08044" }, { key: "high", label: "High", freq: "6.4 kHz",color: "#60D080", shadow: "#60D08044" },
]; ];
@@ -59,7 +59,7 @@ function EqKnob({ label, freq, value, min, max, color, onChange }) {
{norm > 0 && ( {norm > 0 && (
<path d={`M ${lx} ${ly} A ${r} ${r} 0 ${large} 1 ${ex} ${ey}`} <path d={`M ${lx} ${ly} A ${r} ${r} 0 ${large} 1 ${ex} ${ey}`}
fill="none" stroke={color} strokeWidth="3" strokeLinecap="round" fill="none" stroke={color} strokeWidth="3" strokeLinecap="round"
style={{ filter: `drop-shadow(0 0 4px ${color})` }} /> style={{ opacity: 0.8 }} />
)} )}
</svg> </svg>
<div style={{ <div style={{
@@ -73,7 +73,7 @@ function EqKnob({ label, freq, value, min, max, color, onChange }) {
height: dotH, top: dotTop, height: dotH, top: dotTop,
transform: `translateX(-50%) rotate(${angle}deg)`, transform: `translateX(-50%) rotate(${angle}deg)`,
transformOrigin: `50% ${dotH}px`, transformOrigin: `50% ${dotH}px`,
boxShadow: `0 0 6px ${color}`, boxShadow: `0 0 4px ${color}33`,
}} /> }} />
</div> </div>
</div> </div>
+1 -1
View File
@@ -191,7 +191,7 @@ function SettingsSlider({ label, value, min, max, unit, onChange }) {
cursor: "pointer", touchAction: "none", cursor: "pointer", touchAction: "none",
}}> }}>
<div style={{ width: "100%", height: 6, background: T.border, borderRadius: 3, position: "relative", overflow: "hidden" }}> <div style={{ width: "100%", height: 6, background: T.border, borderRadius: 3, position: "relative", overflow: "hidden" }}>
<div style={{ height: "100%", borderRadius: 3, position: "absolute", top: 0, left: 0, width: `${pct}%`, background: T.amber, boxShadow: `0 0 6px ${T.amber}44`, transition: "width .03s" }} /> <div style={{ height: "100%", borderRadius: 3, position: "absolute", top: 0, left: 0, width: "100%", background: T.amber, transform: `scaleX(${pct/100})`, transformOrigin: "left center", transition: "transform .03s" }} />
</div> </div>
<div style={{ width: 24, height: 24, borderRadius: "50%", position: "absolute", top: "50%", left: `${pct}%`, transform: "translate(-50%,-50%)", background: T.amber, border: `3px solid ${T.bg}`, boxShadow: `0 1px 6px rgba(0,0,0,.5)`, pointerEvents: "none", transition: "left .03s" }} /> <div style={{ width: 24, height: 24, borderRadius: "50%", position: "absolute", top: "50%", left: `${pct}%`, transform: "translate(-50%,-50%)", background: T.amber, border: `3px solid ${T.bg}`, boxShadow: `0 1px 6px rgba(0,0,0,.5)`, pointerEvents: "none", transition: "left .03s" }} />
</div> </div>
+5 -6
View File
@@ -8,8 +8,8 @@ const CATEGORY_DEFS = {
"Distortions": { icon: "fx_distortion", color: T.red }, "Distortions": { icon: "fx_distortion", color: T.red },
"Dynamics": { icon: "fx_compressor", color: T.green }, "Dynamics": { icon: "fx_compressor", color: T.green },
"Modulations": { icon: "fx_modulator", color: T.blue }, "Modulations": { icon: "fx_modulator", color: T.blue },
"Delays": { icon: "fx_delay", color: "#60A0E0" }, "Delays": { icon: "fx_delay", color: "#6080B0" },
"Reverbs": { icon: "fx_reverb", color: "#60C0D0" }, "Reverbs": { icon: "fx_reverb", color: "#5090A0" },
"Filters": { icon: "fx_filter", color: "#D0A060" }, "Filters": { icon: "fx_filter", color: "#D0A060" },
"Amps": { icon: "fx_amplifier", color: "#E0A040" }, "Amps": { icon: "fx_amplifier", color: "#E0A040" },
"Preamps": { icon: "fx_simulator", color: "#D08040" }, "Preamps": { icon: "fx_simulator", color: "#D08040" },
@@ -59,7 +59,7 @@ const TYPE_COLORS = {
fuzz: "#D060E0", fuzz: "#D060E0",
mod: T.blue, chorus: T.blue, flange: T.blue, phaser: T.blue, mod: T.blue, chorus: T.blue, flange: T.blue, phaser: T.blue,
tremolo: T.blue, vibrato: T.blue, rotary: T.blue, tremolo: T.blue, vibrato: T.blue, rotary: T.blue,
delay: "#60A0E0", echo: "#60A0E0", reverb: "#60C0D0", delay: "#6080B0", echo: "#6080B0", reverb: "#5090A0",
pitch: "#A060E0", comp: T.green, compressor: T.green, pitch: "#A060E0", comp: T.green, compressor: T.green,
gate: T.green, filter: "#D0A060", wah: "#D0A060", gate: T.green, filter: "#D0A060", wah: "#D0A060",
eq: "#80A0B0", ir: T.green, cab: T.green, nam: "#E0A040", eq: "#80A0B0", ir: T.green, cab: T.green, nam: "#E0A040",
@@ -571,7 +571,7 @@ function ModelTile({ model, isCurrent, isFavorite, onSelect, onToggleFav }) {
cursor: "pointer", cursor: "pointer",
position: "relative", position: "relative",
transition: "all .12s", transition: "all .12s",
boxShadow: isCurrent ? `0 0 12px ${color}33` : "none", boxShadow: isCurrent ? `0 0 6px ${color}22` : "none",
minHeight: 72, minHeight: 72,
}} }}
> >
@@ -599,7 +599,7 @@ function ModelTile({ model, isCurrent, isFavorite, onSelect, onToggleFav }) {
alt={model.type} alt={model.type}
style={{ style={{
width: 28, height: 28, width: 28, height: 28,
filter: `invert(0.95) brightness(2) drop-shadow(0 0 4px ${color}44)`, filter: `invert(0.9) brightness(1.6)`,
objectFit: "contain", objectFit: "contain",
}} }}
onError={() => setImgError(true)} onError={() => setImgError(true)}
@@ -656,7 +656,6 @@ function ModelTile({ model, isCurrent, isFavorite, onSelect, onToggleFav }) {
position: "absolute", top: 4, left: 4, position: "absolute", top: 4, left: 4,
width: 6, height: 6, borderRadius: "50%", width: 6, height: 6, borderRadius: "50%",
background: T.green, background: T.green,
boxShadow: `0 0 6px ${T.green}`,
}} /> }} />
)} )}
</div> </div>
+5 -5
View File
@@ -279,8 +279,8 @@ export default function TunerScreen({ tunerData, connected, onExit }) {
borderRadius: 1, borderRadius: 1,
margin: "0 auto", margin: "0 auto",
boxShadow: isInTune boxShadow: isInTune
? `0 0 8px ${T.green}` ? `0 0 4px ${T.green}44`
: `0 0 4px ${isClose ? T.amber : "transparent"}`, : `0 0 2px ${isClose ? T.amber : "transparent"}`,
}} /> }} />
{/* Needle dot */} {/* Needle dot */}
<div style={{ <div style={{
@@ -290,8 +290,8 @@ export default function TunerScreen({ tunerData, connected, onExit }) {
background: isInTune ? T.green : (isClose ? T.amber : T.textPrimary), background: isInTune ? T.green : (isClose ? T.amber : T.textPrimary),
margin: "-1px auto 0", margin: "-1px auto 0",
boxShadow: isInTune boxShadow: isInTune
? `0 0 12px ${T.green}` ? `0 0 6px ${T.green}44`
: `0 0 6px ${isClose ? T.amber : "transparent"}`, : `0 0 4px ${isClose ? T.amber : "transparent"}`,
}} /> }} />
</div> </div>
</div> </div>
@@ -334,7 +334,7 @@ export default function TunerScreen({ tunerData, connected, onExit }) {
background: isActive ? `${s.color}22` : T.surface, background: isActive ? `${s.color}22` : T.surface,
border: `2px solid ${isActive ? s.color : T.border}`, border: `2px solid ${isActive ? s.color : T.border}`,
transition: "all .1s", transition: "all .1s",
boxShadow: isActive ? `0 0 12px ${s.color}44` : "none", boxShadow: isActive ? `0 0 6px ${s.color}22` : "none",
}} }}
> >
<span style={{ <span style={{
+6 -6
View File
@@ -6,13 +6,13 @@
--border: #2A2A32; --border: #2A2A32;
--amber: #E8A030; --amber: #E8A030;
--amber-dim: #7A5218; --amber-dim: #7A5218;
--blue: #4A8BC8; --blue: #60A8D8;
--blue-dim: #1E4060; --blue-dim: #1E4060;
--green: #3AB87A; --green: #3AB87A;
--red: #E06060; --red: #E06060;
--text-primary: #F0EDE6; --text-primary: #F0EDE6;
--text-sec: #A0A0BC; --text-sec: #A0A0BC;
--text-dim: #7878A0; --text-dim: #8484B0;
} }
/* ── Reset & base ── */ /* ── Reset & base ── */
@@ -29,7 +29,7 @@ body { background: #0A0A0C; color: #F0EDE6; font-family: 'Space Grotesk', sans-s
letter-spacing: .06em; text-transform: uppercase; } letter-spacing: .06em; text-transform: uppercase; }
.badge-amber { background: rgba(232,160,48,.2); color: #E8A030; } .badge-amber { background: rgba(232,160,48,.2); color: #E8A030; }
.badge-green { background: rgba(58,184,122,.2); color: #3AB87A; } .badge-green { background: rgba(58,184,122,.2); color: #3AB87A; }
.badge-blue { background: rgba(74,139,200,.2); color: #4A8BC8; } .badge-blue { background: rgba(74,139,200,.2); color: #70B0E0; }
.badge-red { background: rgba(224,96,96,.2); color: #E06060; } .badge-red { background: rgba(224,96,96,.2); color: #E06060; }
/* Button system */ /* Button system */
@@ -75,7 +75,7 @@ body { background: #0A0A0C; color: #F0EDE6; font-family: 'Space Grotesk', sans-s
.snap-name { font-size: 9px; color: #F0EDE6; margin-top: 2px; word-break: break-all; line-height: 1.3; } .snap-name { font-size: 9px; color: #F0EDE6; margin-top: 2px; word-break: break-all; line-height: 1.3; }
.snap-empty { font-size: 9px; color: #444458; margin-top: 2px; font-style: italic; } .snap-empty { font-size: 9px; color: #444458; margin-top: 2px; font-style: italic; }
.snap-save-indicator { position: absolute; top: 4px; right: 4px; width: 6px; height: 6px; .snap-save-indicator { position: absolute; top: 4px; right: 4px; width: 6px; height: 6px;
border-radius: 50%; background: #3AB87A; box-shadow: 0 0 4px #3AB87A; } border-radius: 50%; background: #3AB87A; }
.snap-name-input { width: 100%; background: #0A0A0C; border: 1px solid #2A2A32; .snap-name-input { width: 100%; background: #0A0A0C; border: 1px solid #2A2A32;
border-radius: 3px; padding: 2px 4px; font-size: 9px; color: #F0EDE6; border-radius: 3px; padding: 2px 4px; font-size: 9px; color: #F0EDE6;
text-align: center; outline: none; margin-top: 2px; } text-align: center; outline: none; margin-top: 2px; }
@@ -132,11 +132,11 @@ body { background: #0A0A0C; color: #F0EDE6; font-family: 'Space Grotesk', sans-s
/* NAM chip */ /* NAM chip */
.nam-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; .nam-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px;
background: rgba(74,139,200,.15); border: 1px solid rgba(74,139,200,.35); background: rgba(74,139,200,.15); border: 1px solid rgba(74,139,200,.35);
border-radius: 5px; font-family: 'JetBrains Mono', monospace; font-size: 11px; color: #4A8BC8; } border-radius: 5px; font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--blue); }
/* Bypass LED */ /* Bypass LED */
.bypass-led { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .bypass-led { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.led-on { background: #3AB87A; box-shadow: 0 0 8px #3AB87A; } .led-on { background: #3AB87A; }
.led-off { background: #444458; } .led-off { background: #444458; }
/* ── Reduced motion ── */ /* ── Reduced motion ── */