mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
tweak
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -11,8 +11,8 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
||||||
<title>Multi Roomba Rover</title>
|
<title>Multi Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-MrbP_QVu.js"></script>
|
<script type="module" crossorigin src="/assets/index-BMPbggP8.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CJGsz9ZO.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-COtFQYoW.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -1,106 +1,129 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useDockIr } from '../hooks/useDockIr.js';
|
import { useDockIr } from '../hooks/useDockIr.js';
|
||||||
|
|
||||||
const SVG_SIZE = 120;
|
const SVG_W = 120;
|
||||||
const SVG_HEIGHT = 120;
|
const SVG_H = 110;
|
||||||
const CENTER_X = SVG_SIZE / 2;
|
const CX = SVG_W / 2;
|
||||||
const DOCK_Y = 18;
|
const DOCK_Y = 16;
|
||||||
const ROVER_Y = 90;
|
const ROVER_Y = 86;
|
||||||
|
|
||||||
function lobePath(side = 'left') {
|
function lobePath(side = 'left') {
|
||||||
if (side === 'left') {
|
if (side === 'left') {
|
||||||
return `M ${CENTER_X} ${DOCK_Y} C ${CENTER_X - 22} ${DOCK_Y + 18} ${CENTER_X - 28} ${ROVER_Y - 16} ${CENTER_X - 8} ${ROVER_Y} L ${CENTER_X} ${ROVER_Y} Z`;
|
return `M ${CX} ${DOCK_Y} C ${CX - 16} ${DOCK_Y + 12} ${CX - 18} ${ROVER_Y - 20} ${CX - 4} ${ROVER_Y - 6} L ${CX} ${ROVER_Y - 10} Z`;
|
||||||
}
|
}
|
||||||
return `M ${CENTER_X} ${DOCK_Y} C ${CENTER_X + 22} ${DOCK_Y + 18} ${CENTER_X + 28} ${ROVER_Y - 16} ${CENTER_X + 8} ${ROVER_Y} L ${CENTER_X} ${ROVER_Y} Z`;
|
return `M ${CX} ${DOCK_Y} C ${CX + 16} ${DOCK_Y + 12} ${CX + 18} ${ROVER_Y - 20} ${CX + 4} ${ROVER_Y - 6} L ${CX} ${ROVER_Y - 10} Z`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DockAssistHUD({ sensors }) {
|
export default function DockAssistHUD({ sensors }) {
|
||||||
const state = useDockIr(sensors);
|
const state = useDockIr(sensors);
|
||||||
const lobe = useMemo(
|
const palette = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
left: {
|
green: ['rgba(16,185,129,0.6)', 'rgba(16,185,129,0.45)', 'rgba(16,185,129,0)'],
|
||||||
base: 'rgba(16, 185, 129, 0.15)',
|
red: ['rgba(239,68,68,0.6)', 'rgba(239,68,68,0.45)', 'rgba(239,68,68,0)'],
|
||||||
active: 'rgba(16, 185, 129, 0.55)',
|
forceOutline: 'rgba(191,219,254,0.85)',
|
||||||
outline: 'rgba(52, 211, 153, 0.9)',
|
roverBody: '#0f172a',
|
||||||
},
|
roverFill: '#e5e7eb',
|
||||||
right: {
|
|
||||||
base: 'rgba(239, 68, 68, 0.15)',
|
|
||||||
active: 'rgba(239, 68, 68, 0.55)',
|
|
||||||
outline: 'rgba(248, 113, 113, 0.9)',
|
|
||||||
},
|
|
||||||
force: {
|
|
||||||
halo: 'rgba(59, 130, 246, 0.15)',
|
|
||||||
haloStrong: 'rgba(59, 130, 246, 0.35)',
|
|
||||||
outline: 'rgba(191, 219, 254, 0.8)',
|
|
||||||
},
|
|
||||||
rover: {
|
|
||||||
body: '#111827',
|
|
||||||
fill: '#e5e7eb',
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!state.visible) {
|
if (!state.visible) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nudge = state.balance * 6; // pixels to offset rover cue
|
const nudge = state.balance * 6;
|
||||||
const leftGlow = state.left.red || state.left.green || state.left.force;
|
const leftActive = state.left.red || state.left.green || state.left.force;
|
||||||
const rightGlow = state.right.red || state.right.green || state.right.force;
|
const rightActive = state.right.red || state.right.green || state.right.force;
|
||||||
const aligned = state.left.red && state.left.green && state.right.red && state.right.green && state.forceDetected;
|
const allAligned = state.left.red && state.left.green && state.right.red && state.right.green && state.forceDetected;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pointer-events-none absolute inset-x-0 top-0 flex justify-center p-0.25">
|
<div className="pointer-events-none absolute inset-x-0 top-0 flex justify-center p-0.25">
|
||||||
<div className="rounded bg-black/70 px-0.5 py-0.25 shadow-md shadow-black/40 ring-1 ring-white/5">
|
<svg width={SVG_W} height={SVG_H} viewBox={`0 0 ${SVG_W} ${SVG_H}`} role="img" aria-label="Docking assist">
|
||||||
<svg width={SVG_SIZE} height={SVG_HEIGHT} viewBox={`0 0 ${SVG_SIZE} ${SVG_HEIGHT}`} role="img" aria-label="Docking assist">
|
<defs>
|
||||||
{/* Force field halo */}
|
<linearGradient id="gradGreen" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||||
<circle
|
<stop offset="0%" stopColor={palette.green[0]} />
|
||||||
cx={CENTER_X}
|
<stop offset="60%" stopColor={palette.green[1]} />
|
||||||
cy={DOCK_Y + 6}
|
<stop offset="100%" stopColor={palette.green[2]} />
|
||||||
r={20}
|
</linearGradient>
|
||||||
fill={state.forceDetected ? lobe.force.haloStrong : lobe.force.halo}
|
<linearGradient id="gradRed" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||||
stroke={state.forceDetected ? lobe.force.outline : 'none'}
|
<stop offset="0%" stopColor={palette.red[0]} />
|
||||||
strokeWidth={state.forceDetected ? 2 : 0}
|
<stop offset="60%" stopColor={palette.red[1]} />
|
||||||
|
<stop offset="100%" stopColor={palette.red[2]} />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="halo" cx="50%" cy="20%" r="60%">
|
||||||
|
<stop offset="0%" stopColor="rgba(59,130,246,0.45)" />
|
||||||
|
<stop offset="100%" stopColor="rgba(59,130,246,0)" />
|
||||||
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
{/* Force field halo */}
|
||||||
|
<circle
|
||||||
|
cx={CX}
|
||||||
|
cy={DOCK_Y + 4}
|
||||||
|
r={18}
|
||||||
|
fill={state.forceDetected ? 'url(#halo)' : 'rgba(59,130,246,0.1)'}
|
||||||
|
stroke={state.forceDetected ? palette.forceOutline : 'none'}
|
||||||
|
strokeWidth={state.forceDetected ? 1.2 : 0}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Lobes */}
|
||||||
|
<path d={lobePath('left')} fill={leftActive ? 'url(#gradGreen)' : 'rgba(16,185,129,0.12)'} />
|
||||||
|
<path d={lobePath('right')} fill={rightActive ? 'url(#gradRed)' : 'rgba(239,68,68,0.12)'} />
|
||||||
|
{leftActive && rightActive ? (
|
||||||
|
<path
|
||||||
|
d={`M ${CX - 6} ${ROVER_Y - 12} Q ${CX} ${ROVER_Y - 4} ${CX + 6} ${ROVER_Y - 12}`}
|
||||||
|
fill="rgba(255,255,255,0.08)"
|
||||||
/>
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{/* Left lobe */}
|
{/* Dock icon: sideways D with rounded top corners */}
|
||||||
<path d={lobePath('left')} fill={leftGlow ? lobe.left.active : lobe.left.base} />
|
<path
|
||||||
{aligned && <path d={lobePath('left')} fill="none" stroke={lobe.left.outline} strokeWidth={1.5} />}
|
d={`
|
||||||
|
M ${CX - 15} ${DOCK_Y - 6}
|
||||||
|
Q ${CX - 13} ${DOCK_Y - 8} ${CX - 11} ${DOCK_Y - 8}
|
||||||
|
H ${CX + 9}
|
||||||
|
Q ${CX + 19} ${DOCK_Y - 6} ${CX + 19} ${DOCK_Y + 6}
|
||||||
|
Q ${CX + 19} ${DOCK_Y + 18} ${CX + 9} ${DOCK_Y + 20}
|
||||||
|
H ${CX - 15}
|
||||||
|
Z
|
||||||
|
`}
|
||||||
|
fill="#0b1220"
|
||||||
|
stroke="#94a3b8"
|
||||||
|
strokeWidth="0.8"
|
||||||
|
/>
|
||||||
|
{/* Force field emitter dot */}
|
||||||
|
<circle cx={CX - 4} cy={DOCK_Y - 2} r="1.7" fill="#60a5fa" />
|
||||||
|
{/* Contacts */}
|
||||||
|
<rect x={CX + 1} y={DOCK_Y + 6} width="2.8" height="7" rx="0.8" fill="#e2e8f0" />
|
||||||
|
<rect x={CX + 5.5} y={DOCK_Y + 6} width="2.8" height="7" rx="0.8" fill="#e2e8f0" />
|
||||||
|
|
||||||
{/* Right lobe */}
|
{/* Rover cue */}
|
||||||
<path d={lobePath('right')} fill={rightGlow ? lobe.right.active : lobe.right.base} />
|
<g transform={`translate(${CX + nudge}, ${ROVER_Y})`}>
|
||||||
{aligned && <path d={lobePath('right')} fill="none" stroke={lobe.right.outline} strokeWidth={1.5} />}
|
<circle r="6" fill={palette.roverBody} stroke="#6b7280" strokeWidth="1" />
|
||||||
|
<path d="M 0 -5 L 4 4 L -4 4 Z" fill={palette.roverFill} />
|
||||||
|
</g>
|
||||||
|
|
||||||
{/* Dock icon */}
|
{/* Nudge arrow */}
|
||||||
<rect x={CENTER_X - 12} y={DOCK_Y - 8} width="24" height="10" rx="2" fill="#1f2937" stroke="#6b7280" strokeWidth="0.8" />
|
{state.bias !== 'center' && (
|
||||||
<circle cx={CENTER_X - 5} cy={DOCK_Y - 3.5} r="1.5" fill="#9ca3af" />
|
<path
|
||||||
<circle cx={CENTER_X + 5} cy={DOCK_Y - 3.5} r="1.5" fill="#9ca3af" />
|
d={
|
||||||
|
state.bias === 'left'
|
||||||
|
? `M ${CX - 12} ${ROVER_Y - 5} L ${CX - 18} ${ROVER_Y} L ${CX - 12} ${ROVER_Y + 5}`
|
||||||
|
: `M ${CX + 12} ${ROVER_Y - 5} L ${CX + 18} ${ROVER_Y} L ${CX + 12} ${ROVER_Y + 5}`
|
||||||
|
}
|
||||||
|
fill="none"
|
||||||
|
stroke="#e5e7eb"
|
||||||
|
strokeWidth="1.3"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Rover cue */}
|
{/* Thumbs up when fully aligned */}
|
||||||
<g transform={`translate(${CENTER_X + nudge}, ${ROVER_Y})`}>
|
{allAligned ? (
|
||||||
<circle r="7" fill={lobe.rover.body} stroke="#6b7280" strokeWidth="1.2" />
|
<text x={CX + 30} y={DOCK_Y + 8} fontSize="12" fill="#fbbf24" fontFamily="sans-serif">
|
||||||
<path d="M 0 -5 L 4 4 L -4 4 Z" fill={lobe.rover.fill} />
|
👍
|
||||||
</g>
|
</text>
|
||||||
|
) : null}
|
||||||
{/* Nudge arrow */}
|
</svg>
|
||||||
{state.bias !== 'center' && (
|
|
||||||
<path
|
|
||||||
d={
|
|
||||||
state.bias === 'left'
|
|
||||||
? `M ${CENTER_X - 14} ${ROVER_Y - 6} L ${CENTER_X - 22} ${ROVER_Y} L ${CENTER_X - 14} ${ROVER_Y + 6}`
|
|
||||||
: `M ${CENTER_X + 14} ${ROVER_Y - 6} L ${CENTER_X + 22} ${ROVER_Y} L ${CENTER_X + 14} ${ROVER_Y + 6}`
|
|
||||||
}
|
|
||||||
fill="none"
|
|
||||||
stroke="#e5e7eb"
|
|
||||||
strokeWidth="1.6"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user