feat:themes, tactilea codec

This commit is contained in:
lenn
2026-04-03 16:40:48 +08:00
parent 7688986ad7
commit 1c5ac13da8
42 changed files with 881 additions and 551 deletions

View File

@@ -42,7 +42,7 @@
const copyByLocale: Record<LocaleCode, HudCopy> = {
"zh-CN": {
appName: "JOYSON HUD",
appName: "JE-Skin",
suiteName: "v0.1.0",
stageTitle: "WebGL2 主渲染区",
stageHint: "底图与三维操作将在此区域加载",
@@ -98,7 +98,7 @@
disconnectedLabel: "未连接"
},
"en-US": {
appName: "JOYSON HUD",
appName: "JE-Skin",
suiteName: "v0.1.0",
stageTitle: "WebGL2 Main Surface",
stageHint: "Map texture and 3D interactions will render here",
@@ -197,7 +197,7 @@
let connectionNotice = "";
let connectionNoticeTone: HudNoticeTone = "info";
let isExporting = false;
let deviceValue = "JY-Sense Unit";
let deviceValue = "JE-Skin-F";
let sampleRateValue = "100Hz";
let channelsValue = "84";
let webglStatusTone: StageStatusTone = "warn";
@@ -211,7 +211,7 @@
let matrixRows = 12;
let matrixCols = 7;
let rangeMin = 0;
let rangeMax = 5000;
let rangeMax = 16000;
let colorMapPreset: PressureColorMapPreset = "emerald";
let replayFrames: ReplayFrame[] = [];
let replayCurrentIndex = 0;
@@ -308,8 +308,49 @@
const palette = pressureColorPalettes[preset] ?? pressureColorPalettes.emerald;
const [range0, range1, range2, range3, range4, range5] = palette.rangeStops;
const [glow0, glow1, glow2] = palette.rangeGlow;
const {
bg00,
bg10,
bg20,
bg30,
textMainRgb,
textDimRgb,
borderRgb,
borderStrongRgb,
surfaceRgb,
surfaceAltRgb,
surfaceDeepRgb,
glowRgb,
glowAltRgb,
cyanRgb,
limeRgb,
orangeRgb,
infoRgb
} = palette.uiTheme;
return [
`--hud-bg-00: ${bg00}`,
`--hud-bg-10: ${bg10}`,
`--hud-bg-20: ${bg20}`,
`--hud-bg-30: ${bg30}`,
`--hud-text-main-rgb: ${textMainRgb}`,
`--hud-text-dim-rgb: ${textDimRgb}`,
`--hud-text-main: rgb(${textMainRgb})`,
`--hud-text-dim: rgb(${textDimRgb})`,
`--hud-border-rgb: ${borderRgb}`,
`--hud-border-strong-rgb: ${borderStrongRgb}`,
`--hud-surface-rgb: ${surfaceRgb}`,
`--hud-surface-alt-rgb: ${surfaceAltRgb}`,
`--hud-surface-deep-rgb: ${surfaceDeepRgb}`,
`--hud-glow-rgb: ${glowRgb}`,
`--hud-glow-alt-rgb: ${glowAltRgb}`,
`--hud-cyan-rgb: ${cyanRgb}`,
`--hud-lime-rgb: ${limeRgb}`,
`--hud-orange-rgb: ${orangeRgb}`,
`--hud-info-rgb: ${infoRgb}`,
`--hud-cyan: rgb(${cyanRgb})`,
`--hud-lime: rgb(${limeRgb})`,
`--hud-orange: rgb(${orangeRgb})`,
`--hud-range-0: ${range0}`,
`--hud-range-1: ${range1}`,
`--hud-range-2: ${range2}`,
@@ -615,11 +656,10 @@
function frameValuesToMatrix(values: number[]): number[] {
const totalCells = Math.max(matrixRows * matrixCols, 1);
const matrix = new Array<number>(totalCells).fill(0);
const maxRawValue = Math.max(rangeMax, 5000);
for (let index = 0; index < totalCells; index += 1) {
const value = Number(values[index] ?? 0);
matrix[index] = clamp(Number.isFinite(value) ? value : 0, 0, maxRawValue);
matrix[index] = Number.isFinite(value) ? value : 0;
}
return matrix;
@@ -1468,7 +1508,7 @@
});
</script>
<main class="hud-screen">
<main class="hud-screen" style={rangeScaleStyle}>
<div class="hud-background" aria-hidden="true">
<div class="hud-gradient"></div>
<div class="hud-vignette"></div>
@@ -1567,7 +1607,7 @@
on:replayclose={handleReplayClose}
on:configclose={() => (isConfigPanelOpen = false)}
>
<section class="range-scale" aria-label="Signal Range" style={rangeScaleStyle}>
<section class="range-scale" aria-label="Signal Range">
<p class="range-label">Range</p>
<div class="range-track">
{#each rangeTicks as tick}
@@ -1627,8 +1667,8 @@
position: absolute;
inset: 0;
background:
radial-gradient(circle at 14% 6%, rgb(62 232 255 / 0.07), transparent 36%),
radial-gradient(circle at 86% 14%, rgb(133 255 68 / 0.05), transparent 32%),
radial-gradient(circle at 14% 6%, rgb(var(--hud-glow-rgb) / 0.07), transparent 36%),
radial-gradient(circle at 86% 14%, rgb(var(--hud-glow-alt-rgb) / 0.05), transparent 32%),
linear-gradient(170deg, var(--hud-bg-20) 0%, var(--hud-bg-10) 56%, var(--hud-bg-30) 100%);
}
@@ -1655,14 +1695,19 @@
grid-template-rows: auto minmax(0, 1fr);
gap: clamp(0.5rem, 1.2vw, 0.95rem);
padding: clamp(0.65rem, 1.75vw, 1.3rem);
border: 1px solid rgb(111 150 173 / 0.2);
border: 1px solid rgb(var(--hud-border-rgb) / 0.2);
border-radius: 0.9rem;
background:
linear-gradient(176deg, rgb(8 10 12 / 0.9) 0%, rgb(0 0 0 / 0.94) 56%, rgb(6 8 10 / 0.9) 100%),
radial-gradient(circle at 18% 0%, rgb(62 232 255 / 0.05), transparent 40%),
radial-gradient(circle at 84% 8%, rgb(133 255 68 / 0.04), transparent 36%);
linear-gradient(
176deg,
rgb(var(--hud-surface-alt-rgb) / 0.9) 0%,
rgb(var(--hud-surface-deep-rgb) / 0.94) 56%,
rgb(var(--hud-surface-rgb) / 0.9) 100%
),
radial-gradient(circle at 18% 0%, rgb(var(--hud-glow-rgb) / 0.05), transparent 40%),
radial-gradient(circle at 84% 8%, rgb(var(--hud-glow-alt-rgb) / 0.04), transparent 36%);
box-shadow:
inset 0 1px 0 rgb(197 228 245 / 0.08),
inset 0 1px 0 rgb(var(--hud-border-strong-rgb) / 0.08),
inset 0 -28px 60px rgb(0 0 0 / 0.34);
overflow: hidden;
}
@@ -1672,21 +1717,21 @@
grid-template-columns: auto 1fr;
align-items: center;
gap: 0.75rem;
border: 1px solid rgb(103 135 154 / 0.24);
border: 1px solid rgb(var(--hud-border-rgb) / 0.24);
border-radius: 0.48rem;
padding: 0.34rem 0.52rem;
background:
linear-gradient(180deg, rgb(4 10 14 / 0.72), rgb(2 6 10 / 0.56)),
radial-gradient(circle at 50% 0, rgb(62 232 255 / 0.06), transparent 52%);
linear-gradient(180deg, rgb(var(--hud-surface-rgb) / 0.72), rgb(var(--hud-surface-deep-rgb) / 0.56)),
radial-gradient(circle at 50% 0, rgb(var(--hud-glow-rgb) / 0.06), transparent 52%);
box-shadow:
inset 0 1px 0 rgb(176 218 240 / 0.06),
0 0 12px rgb(62 232 255 / 0.08);
inset 0 1px 0 rgb(var(--hud-border-strong-rgb) / 0.06),
0 0 12px rgb(var(--hud-glow-rgb) / 0.08);
pointer-events: none;
}
.range-label {
margin: 0;
color: rgb(146 170 187 / 0.82);
color: rgb(var(--hud-text-dim-rgb) / 0.82);
font-size: 0.56rem;
letter-spacing: 0.1em;
text-transform: uppercase;
@@ -1699,9 +1744,9 @@
grid-template-columns: repeat(11, minmax(0, 1fr));
gap: 0.26rem;
padding: 0.28rem 0.36rem 0.16rem;
border: 1px solid rgb(131 181 200 / 0.14);
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.14);
border-radius: 999px;
background: rgb(6 13 16 / 0.34);
background: rgb(var(--hud-surface-rgb) / 0.34);
overflow: hidden;
}
@@ -1721,9 +1766,9 @@
color-mix(in srgb, var(--hud-range-4) 96%, black) 84%,
color-mix(in srgb, var(--hud-range-5) 94%, black) 100%
),
linear-gradient(180deg, rgb(255 255 255 / 0.06), transparent 42%);
linear-gradient(180deg, rgb(var(--hud-text-main-rgb) / 0.06), transparent 42%);
box-shadow:
inset 0 1px 0 rgb(255 255 255 / 0.1),
inset 0 1px 0 rgb(var(--hud-text-main-rgb) / 0.1),
inset 0 -10px 18px rgb(0 0 0 / 0.18);
opacity: 0.94;
}
@@ -1749,12 +1794,12 @@
position: relative;
z-index: 1;
padding-block-start: 0.36rem;
color: rgb(230 243 252 / 0.96);
color: rgb(var(--hud-text-main-rgb) / 0.96);
font-size: 0.56rem;
text-align: center;
text-shadow:
0 1px 0 rgb(0 0 0 / 0.46),
0 0 12px rgb(10 18 24 / 0.4);
0 0 12px rgb(var(--hud-surface-alt-rgb) / 0.4);
}
.range-tick::before {
@@ -1765,8 +1810,8 @@
inline-size: 1px;
block-size: 0.24rem;
transform: translateX(-50%);
background: rgb(234 247 255 / 0.74);
box-shadow: 0 0 8px rgb(62 232 255 / 0.22);
background: rgb(var(--hud-text-main-rgb) / 0.74);
box-shadow: 0 0 8px rgb(var(--hud-glow-rgb) / 0.22);
}
@media (max-width: 760px) {