update frontend components and cargo config
This commit is contained in:
@@ -29,6 +29,7 @@
|
|||||||
export let summary: HudSummary;
|
export let summary: HudSummary;
|
||||||
export let pressureMatrix: number[] | null = null;
|
export let pressureMatrix: number[] | null = null;
|
||||||
export let spatialForce: HudSpatialForce | null = null;
|
export let spatialForce: HudSpatialForce | null = null;
|
||||||
|
export let devkitSpatialForce: HudSpatialForce | null = null;
|
||||||
export let showConfigPanel = false;
|
export let showConfigPanel = false;
|
||||||
export let configPanelTitle = "";
|
export let configPanelTitle = "";
|
||||||
export let configPanelHint = "";
|
export let configPanelHint = "";
|
||||||
@@ -327,6 +328,29 @@
|
|||||||
{locale}
|
{locale}
|
||||||
side="right"
|
side="right"
|
||||||
panelIndex={rightPanels.length}
|
panelIndex={rightPanels.length}
|
||||||
|
panelCode="ALG"
|
||||||
|
panelTitle={locale === "zh-CN" ? "本地切向力" : "Local Tangential"}
|
||||||
|
badgeLabel={locale === "zh-CN" ? "算法" : "ALGO"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="panel-motion-shell"
|
||||||
|
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||||
|
out:fly={{ x: 180, duration: 280, opacity: 0.06, easing: cubicIn }}
|
||||||
|
>
|
||||||
|
<SpatialForcePanel
|
||||||
|
spatialForce={devkitSpatialForce}
|
||||||
|
{locale}
|
||||||
|
side="right"
|
||||||
|
panelIndex={rightPanels.length + 1}
|
||||||
|
panelCode="DKT"
|
||||||
|
panelTitle={locale === "zh-CN" ? "DevKit 切向力" : "DevKit Tangential"}
|
||||||
|
badgeLabel="DEVKIT"
|
||||||
|
badgeTone="lime"
|
||||||
|
showMetrics={false}
|
||||||
|
requireMagnitude={false}
|
||||||
|
compactMetaText={locale === "zh-CN" ? "等待 DevKit 角度流" : "Waiting for DevKit angle"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,13 @@
|
|||||||
export let side: "left" | "right" = "right";
|
export let side: "left" | "right" = "right";
|
||||||
export let panelIndex = 0;
|
export let panelIndex = 0;
|
||||||
export let locale: "zh-CN" | "en-US" = "zh-CN";
|
export let locale: "zh-CN" | "en-US" = "zh-CN";
|
||||||
|
export let panelCode = "TAN";
|
||||||
|
export let panelTitle = "";
|
||||||
|
export let badgeLabel = "";
|
||||||
|
export let badgeTone: "cyan" | "lime" | "orange" = "cyan";
|
||||||
|
export let showMetrics = true;
|
||||||
|
export let requireMagnitude = true;
|
||||||
|
export let compactMetaText = "";
|
||||||
|
|
||||||
function formatValue(value: number | null, digits = 1): string {
|
function formatValue(value: number | null, digits = 1): string {
|
||||||
if (value === null || !Number.isFinite(value)) {
|
if (value === null || !Number.isFinite(value)) {
|
||||||
@@ -91,11 +98,15 @@
|
|||||||
strength: "Strength",
|
strength: "Strength",
|
||||||
confidence: "Confidence"
|
confidence: "Confidence"
|
||||||
};
|
};
|
||||||
|
$: resolvedTitle = panelTitle || i18n.title;
|
||||||
|
$: resolvedBadgeLabel = badgeLabel || i18n.angle;
|
||||||
|
$: resolvedCompactMetaText =
|
||||||
|
compactMetaText || (locale === "zh-CN" ? "仅使用角度流" : "Angle stream only");
|
||||||
|
|
||||||
$: hasData =
|
$: hasData =
|
||||||
spatialForce !== null &&
|
spatialForce !== null &&
|
||||||
Number.isFinite(spatialForce.angleDeg) &&
|
Number.isFinite(spatialForce.angleDeg) &&
|
||||||
Number.isFinite(spatialForce.magnitude);
|
(!requireMagnitude || Number.isFinite(spatialForce.magnitude));
|
||||||
$: angleDeg = hasData ? normalizeAngle(spatialForce?.angleDeg ?? 0) : 0;
|
$: angleDeg = hasData ? normalizeAngle(spatialForce?.angleDeg ?? 0) : 0;
|
||||||
$: updateVisualAngle(angleDeg, hasData);
|
$: updateVisualAngle(angleDeg, hasData);
|
||||||
$: magnitude = hasData ? spatialForce?.magnitude ?? 0 : null;
|
$: magnitude = hasData ? spatialForce?.magnitude ?? 0 : null;
|
||||||
@@ -110,12 +121,12 @@
|
|||||||
>
|
>
|
||||||
<header class="panel-head">
|
<header class="panel-head">
|
||||||
<div class="head-text">
|
<div class="head-text">
|
||||||
<p class="panel-code">TAN</p>
|
<p class="panel-code">{panelCode}</p>
|
||||||
<p class="panel-title">{i18n.title}</p>
|
<p class="panel-title">{resolvedTitle}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="icon-layer" aria-hidden="true">
|
<div class="icon-layer" aria-hidden="true">
|
||||||
<span class="icon-chip tone-cyan">{i18n.angle}</span>
|
<span class={`icon-chip tone-${badgeTone}`}>{resolvedBadgeLabel}</span>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@@ -152,8 +163,13 @@
|
|||||||
|
|
||||||
<div class="angle-stage">
|
<div class="angle-stage">
|
||||||
<p class="angle-label">{i18n.heading}</p>
|
<p class="angle-label">{i18n.heading}</p>
|
||||||
<p class="angle-meta">{i18n.strength}: {formatValue(magnitude, 2)}</p>
|
{#if showMetrics}
|
||||||
<p class="angle-meta">{i18n.confidence}: {hasData ? `${formatValue(confidence, 0)}%` : "--"}</p>
|
<p class="angle-meta">{i18n.strength}: {formatValue(magnitude, 2)}</p>
|
||||||
|
<p class="angle-meta">{i18n.confidence}: {hasData ? `${formatValue(confidence, 0)}%` : "--"}</p>
|
||||||
|
{:else}
|
||||||
|
<p class="angle-meta">{resolvedCompactMetaText}</p>
|
||||||
|
<p class="angle-meta">{hasData ? (locale === "zh-CN" ? "实时对比中" : "Live comparison") : "--"}</p>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -251,6 +267,14 @@
|
|||||||
border-color: rgb(var(--hud-cyan-rgb) / 0.54);
|
border-color: rgb(var(--hud-cyan-rgb) / 0.54);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-chip.tone-lime {
|
||||||
|
border-color: rgb(var(--hud-lime-rgb) / 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-chip.tone-orange {
|
||||||
|
border-color: rgb(var(--hud-orange-rgb) / 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
.panel-body {
|
.panel-body {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1.1fr) minmax(10rem, 0.9fr);
|
grid-template-columns: minmax(0, 1.1fr) minmax(10rem, 0.9fr);
|
||||||
|
|||||||
@@ -46,6 +46,13 @@
|
|||||||
dtsMs: number;
|
dtsMs: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DevKitPztAngleEvent {
|
||||||
|
seq: number;
|
||||||
|
timestampMs: number;
|
||||||
|
dtsMs: number;
|
||||||
|
angle: number;
|
||||||
|
}
|
||||||
|
|
||||||
const copyByLocale: Record<LocaleCode, HudCopy> = {
|
const copyByLocale: Record<LocaleCode, HudCopy> = {
|
||||||
"zh-CN": {
|
"zh-CN": {
|
||||||
appName: "JE-Skin",
|
appName: "JE-Skin",
|
||||||
@@ -230,6 +237,7 @@
|
|||||||
let summary: HudSummary = buildEmptySummary();
|
let summary: HudSummary = buildEmptySummary();
|
||||||
let pressureMatrix: number[] | null = null;
|
let pressureMatrix: number[] | null = null;
|
||||||
let spatialForce: HudSpatialForce | null = null;
|
let spatialForce: HudSpatialForce | null = null;
|
||||||
|
let devkitSpatialForce: HudSpatialForce | null = null;
|
||||||
let matrixRows = 12;
|
let matrixRows = 12;
|
||||||
let matrixCols = 7;
|
let matrixCols = 7;
|
||||||
let rangeMin = DEFAULT_PRESSURE_RANGE_MIN;
|
let rangeMin = DEFAULT_PRESSURE_RANGE_MIN;
|
||||||
@@ -270,6 +278,7 @@
|
|||||||
rowsKept: number;
|
rowsKept: number;
|
||||||
} | null = null;
|
} | null = null;
|
||||||
let devkitStatusTimer: number | null = null;
|
let devkitStatusTimer: number | null = null;
|
||||||
|
let devkitSpatialForceClearTimer: number | null = null;
|
||||||
let sessionStartedAt: number = Date.now();
|
let sessionStartedAt: number = Date.now();
|
||||||
|
|
||||||
$: uiCopy = copyByLocale[locale];
|
$: uiCopy = copyByLocale[locale];
|
||||||
@@ -297,6 +306,31 @@
|
|||||||
return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearDevkitSpatialForce(): void {
|
||||||
|
devkitSpatialForce = null;
|
||||||
|
if (devkitSpatialForceClearTimer != null && typeof window !== "undefined") {
|
||||||
|
window.clearTimeout(devkitSpatialForceClearTimer);
|
||||||
|
devkitSpatialForceClearTimer = null;
|
||||||
|
}
|
||||||
|
hasSignalData = signalPanels.length > 0 || summary.points.length > 0 || spatialForce !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleDevkitSpatialForceClear(): void {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devkitSpatialForceClearTimer != null) {
|
||||||
|
window.clearTimeout(devkitSpatialForceClearTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
devkitSpatialForceClearTimer = window.setTimeout(() => {
|
||||||
|
devkitSpatialForce = null;
|
||||||
|
devkitSpatialForceClearTimer = null;
|
||||||
|
hasSignalData = signalPanels.length > 0 || summary.points.length > 0 || spatialForce !== null;
|
||||||
|
}, 420);
|
||||||
|
}
|
||||||
|
|
||||||
function clamp(value: number, min: number, max: number): number {
|
function clamp(value: number, min: number, max: number): number {
|
||||||
return Math.min(max, Math.max(min, value));
|
return Math.min(max, Math.max(min, value));
|
||||||
}
|
}
|
||||||
@@ -720,6 +754,7 @@
|
|||||||
function resetReplayVisualState(): void {
|
function resetReplayVisualState(): void {
|
||||||
pressureMatrix = buildZeroMatrix();
|
pressureMatrix = buildZeroMatrix();
|
||||||
spatialForce = null;
|
spatialForce = null;
|
||||||
|
clearDevkitSpatialForce();
|
||||||
signalPanels = buildInactivePanels();
|
signalPanels = buildInactivePanels();
|
||||||
summary = buildEmptySummary();
|
summary = buildEmptySummary();
|
||||||
hasSignalData = false;
|
hasSignalData = false;
|
||||||
@@ -756,6 +791,7 @@
|
|||||||
replayProgress = replayFrames.length > 1 ? safeIndex / (replayFrames.length - 1) : 1;
|
replayProgress = replayFrames.length > 1 ? safeIndex / (replayFrames.length - 1) : 1;
|
||||||
pressureMatrix = frameValuesToMatrix(replayFrames[safeIndex].values);
|
pressureMatrix = frameValuesToMatrix(replayFrames[safeIndex].values);
|
||||||
spatialForce = null;
|
spatialForce = null;
|
||||||
|
clearDevkitSpatialForce();
|
||||||
signalPanels = buildInactivePanels();
|
signalPanels = buildInactivePanels();
|
||||||
summary = buildReplaySummaryAt(safeIndex);
|
summary = buildReplaySummaryAt(safeIndex);
|
||||||
hasSignalData = true;
|
hasSignalData = true;
|
||||||
@@ -1011,7 +1047,11 @@
|
|||||||
}
|
}
|
||||||
pressureMatrix = packet.pressureMatrix;
|
pressureMatrix = packet.pressureMatrix;
|
||||||
spatialForce = packet.spatialForce ?? null;
|
spatialForce = packet.spatialForce ?? null;
|
||||||
hasSignalData = signalPanels.length > 0 || packet.summary.points.length > 0 || spatialForce !== null;
|
hasSignalData =
|
||||||
|
signalPanels.length > 0 ||
|
||||||
|
packet.summary.points.length > 0 ||
|
||||||
|
spatialForce !== null ||
|
||||||
|
devkitSpatialForce !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearHudPanels(): void {
|
function clearHudPanels(): void {
|
||||||
@@ -1020,6 +1060,7 @@
|
|||||||
summary = buildEmptySummary();
|
summary = buildEmptySummary();
|
||||||
pressureMatrix = null;
|
pressureMatrix = null;
|
||||||
spatialForce = null;
|
spatialForce = null;
|
||||||
|
clearDevkitSpatialForce();
|
||||||
}
|
}
|
||||||
|
|
||||||
function startMockFeed(push: (packet: HudPacket) => void): () => void {
|
function startMockFeed(push: (packet: HudPacket) => void): () => void {
|
||||||
@@ -1794,12 +1835,25 @@
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Failed to listen for hud_stream:", error);
|
console.error("Failed to listen for hud_stream:", error);
|
||||||
});
|
});
|
||||||
void listen<{ seq: number; timestampMs: number; dtsMs: number; angle: number }>(
|
void listen<DevKitPztAngleEvent>("devkit_pzt_angle", (event) => {
|
||||||
"devkit_pzt_angle",
|
const angleDeg = Number(event.payload.angle);
|
||||||
(event) => {
|
if (!Number.isFinite(angleDeg)) {
|
||||||
console.log("[devkit_pzt_angle]", event.payload);
|
clearDevkitSpatialForce();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
devkitSpatialForce = {
|
||||||
|
angleDeg,
|
||||||
|
magnitude: 0,
|
||||||
|
confidence: 0
|
||||||
|
};
|
||||||
|
scheduleDevkitSpatialForceClear();
|
||||||
|
hasSignalData =
|
||||||
|
signalPanels.length > 0 ||
|
||||||
|
summary.points.length > 0 ||
|
||||||
|
spatialForce !== null ||
|
||||||
|
devkitSpatialForce !== null;
|
||||||
|
})
|
||||||
.then((unlisten) => {
|
.then((unlisten) => {
|
||||||
if (disposed) {
|
if (disposed) {
|
||||||
unlisten();
|
unlisten();
|
||||||
@@ -1818,6 +1872,7 @@
|
|||||||
return () => {
|
return () => {
|
||||||
disposed = true;
|
disposed = true;
|
||||||
pauseReplayPlayback();
|
pauseReplayPlayback();
|
||||||
|
clearDevkitSpatialForce();
|
||||||
stopMockFeed?.();
|
stopMockFeed?.();
|
||||||
unlistenHudStream?.();
|
unlistenHudStream?.();
|
||||||
unlistenDevkitPztAngle?.();
|
unlistenDevkitPztAngle?.();
|
||||||
@@ -1937,6 +1992,7 @@
|
|||||||
rightPanels={rightSignalPanels}
|
rightPanels={rightSignalPanels}
|
||||||
{pressureMatrix}
|
{pressureMatrix}
|
||||||
{spatialForce}
|
{spatialForce}
|
||||||
|
{devkitSpatialForce}
|
||||||
showConfigPanel={isConfigPanelOpen}
|
showConfigPanel={isConfigPanelOpen}
|
||||||
showPrecisionTestPanel={isPrecisionTestOpen}
|
showPrecisionTestPanel={isPrecisionTestOpen}
|
||||||
{summary}
|
{summary}
|
||||||
|
|||||||
Reference in New Issue
Block a user