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:
+13
-13
@@ -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
@@ -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
@@ -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={{
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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 ── */
|
||||||
|
|||||||
Reference in New Issue
Block a user