diff --git a/docs/bgm-format.md b/docs/bgm-format.md index fe23ca5..52c8aff 100644 --- a/docs/bgm-format.md +++ b/docs/bgm-format.md @@ -371,7 +371,7 @@ layout: - `align` — `start`, `end`, or `center` of the curve. - `steps` — the maximum number of parts per curve length unit. Defaults to `1`. See the positioning process below. -- `tilt` — rotation in radians per shown part about the card's local Y (long) +- `tilt` — rotation in degrees per shown part about the card's local Y (long) axis. Each part tilts `tilt` more than the previous, fanning the stack so its edges stay visible. It applies even without a `curve`, so a bare `tilt` fans a straight pile. diff --git a/packages/bgm/src/types.ts b/packages/bgm/src/types.ts index f0a0fe4..832b40c 100644 --- a/packages/bgm/src/types.ts +++ b/packages/bgm/src/types.ts @@ -108,7 +108,7 @@ export interface Stacking { /** Maximum parts per curve length unit; defaults to `1`. */ steps?: number; /** - * Rotation in radians per shown part about the card's local Y (long) axis. + * Rotation in degrees per shown part about the card's local Y (long) axis. * Each part tilts `tilt` more than the previous, fanning the stack so its * edges stay visible. Works with or without a `curve`. */ diff --git a/packages/tabletop/src/part.ts b/packages/tabletop/src/part.ts index 8d44b89..70ed452 100644 --- a/packages/tabletop/src/part.ts +++ b/packages/tabletop/src/part.ts @@ -15,6 +15,9 @@ import { /** Scale from mm (the format's `size` unit) to world units. */ export const MM_TO_WORLD = 1 / 30; +/** Degrees → radians. Angles in the bgm format are authored in degrees. */ +export const DEG_TO_RAD = Math.PI / 180; + /** Default part size `[w, h, d]` in mm when a part has no `size`. */ const DEFAULT_SIZE: [number, number, number] = [60, 60, 3]; diff --git a/packages/tabletop/src/placement.tsx b/packages/tabletop/src/placement.tsx index ff6090b..0a5d1d9 100644 --- a/packages/tabletop/src/placement.tsx +++ b/packages/tabletop/src/placement.tsx @@ -9,7 +9,7 @@ import type { Package } from '@tts/bgm'; import { useStacking } from './stacking.js'; import type { Placement } from './state.js'; import { PartView } from './partView.js'; -import { MM_TO_WORLD } from './part.js'; +import { MM_TO_WORLD, DEG_TO_RAD } from './part.js'; export function PartPlacement({ pkg, placement }: { pkg: Package; placement: Placement }) { const { route, candidate, piece, index, stackSize } = placement; @@ -22,15 +22,16 @@ export function PartPlacement({ pkg, placement }: { pkg: Package; placement: Pla // Route anchors and stacking offsets are in mm; convert to world units so // parts land on the (world-scaled) surface. `z` raises the part along the // surface normal (world +Y); `tilt` fans it about its local Y (long) axis. + // Angles are authored in degrees; three.js expects radians. const anchorX = ((candidate?.x ?? route.x ?? 0) + x) * MM_TO_WORLD; const anchorY = ((candidate?.y ?? route.y ?? 0) + y) * MM_TO_WORLD; const anchorZ = z * MM_TO_WORLD; - const anchorRotation = (candidate?.rotation ?? route.rotation ?? 0) + rotation; + const anchorRotation = ((candidate?.rotation ?? route.rotation ?? 0) + rotation) * DEG_TO_RAD; return ( {/* The part mesh extrudes along +Z; lay it flat so its face points up. */} - + diff --git a/packages/tabletop/src/stacking.ts b/packages/tabletop/src/stacking.ts index 3c86292..13b8ce2 100644 --- a/packages/tabletop/src/stacking.ts +++ b/packages/tabletop/src/stacking.ts @@ -14,11 +14,11 @@ export interface StackOffset { x: number; /** y offset from the anchor. */ y: number; - /** Rotation in radians. */ + /** Rotation in degrees. */ rotation: number; /** Vertical (surface-normal) offset from the anchor, in mm. */ z: number; - /** Rotation in radians about the card's local Y (long) axis. */ + /** Rotation in degrees about the card's local Y (long) axis. */ tilt: number; } diff --git a/packages/tabletop/src/surfaces/WorldSurfaceView.tsx b/packages/tabletop/src/surfaces/WorldSurfaceView.tsx index 492b1f1..3add4bb 100644 --- a/packages/tabletop/src/surfaces/WorldSurfaceView.tsx +++ b/packages/tabletop/src/surfaces/WorldSurfaceView.tsx @@ -10,7 +10,7 @@ import type { Package } from '@tts/bgm'; import { useRenderState, placementKey } from '../state.js'; import { PartPlacement } from '../placement.js'; import type { MountNode } from '../mount.js'; -import { MM_TO_WORLD } from '../part.js'; +import { MM_TO_WORLD, DEG_TO_RAD } from '../part.js'; import { SurfaceBounds } from './SurfaceBounds.js'; import { SurfacePlane } from './SurfacePlane.js'; @@ -42,7 +42,7 @@ export function SurfaceNode({ return ( {showSurface && ( <>