fix(tabletop): align cards to the stacking curve

Fix the tangent angle at the curve's start and rotate cards to follow
the curve direction. Add a stacking curve visualization shown with
surface debug.
This commit is contained in:
2026-08-10 00:40:56 +08:00
parent f12b40e82b
commit 50c6df48b5
6 changed files with 80 additions and 4 deletions
@@ -0,0 +1,40 @@
/**
* `StackingCurve` — a debug visualization of a route's stacking `curve`.
*
* Draws the SVG path (mm, converted to world units) as a line on the surface,
* plus a small marker at the curve's start. The curve is defined relative to
* the route's anchor, so the points are offset by the anchor's `x`/`y`. Used
* by the surface views when `showSurface` is enabled, so the curve's shape and
* direction are visible.
*/
import { Line } from '@react-three/drei';
import type { Route } from '@tts/bgm';
import { parsePath } from '../stacking.js';
import { MM_TO_WORLD } from '../part.js';
export function StackingCurve({ route }: { route: Route }) {
if (!route.stacking?.curve) return null;
const path = parsePath(route.stacking.curve);
if (path.points.length === 0) return null;
// Curve coords are in mm relative to the route anchor (x, y); map to world
// (x, z) and offset by the anchor, matching how parts are placed.
const points: [number, number, number][] = path.points.map((p) => [
(route.x + p.x) * MM_TO_WORLD,
0,
(route.y + p.y) * MM_TO_WORLD,
]);
const start = points[0]!;
return (
<group>
<Line points={points} color="#f59e0b" lineWidth={2} />
{/* Marker at the curve's start, showing its direction. */}
<mesh position={[start[0], 0.01, start[2]]}>
<sphereGeometry args={[0.01, 8, 8]} />
<meshBasicMaterial color="#f59e0b" />
</mesh>
</group>
);
}