Download src/useFlyLayout.ts from gpue/flyyt: direct link, hf CLI and curl.
- Browser
- Download file 3.47 kB
-
https://huggingface.co/spaces/gpue/flyyt/resolve/main/src/useFlyLayout.ts
- Command line
-
hf download hf://spaces/gpue/flyyt/src/useFlyLayout.ts
-
curl -L -o useFlyLayout.ts https://huggingface.co/spaces/gpue/flyyt/resolve/main/src/useFlyLayout.ts
3.47 kB
| import { useEffect, useState } from "react"; | |
| import { apiPath, FLY_AREA_CONFIG } from "./env"; | |
| import { EXTENT_MM, GROUND_OFFSET_MM } from "./rigMetadata"; | |
| import { FREE_FLOOR_RECTS, type AabbMm } from "./roomLayout"; | |
| export interface FlyInstanceData { | |
| id: string; | |
| index: number; | |
| position: [number, number, number]; | |
| /** atan2(x, z) convention, matching the frontend's heading math. */ | |
| heading: number; | |
| } | |
| export const FLY_GROUND_OFFSET_MM = GROUND_OFFSET_MM; | |
| export const FLY_EXTENT_MM = EXTENT_MM; | |
| // Uniform over the union of FREE_FLOOR_RECTS (area-weighted so a big | |
| // rectangle isn't under-sampled relative to a small one), never inside a | |
| // furniture footprint -- rather than the old full-area uniform sample, | |
| // which could spawn a fly inside the couch. | |
| function pickFreeFloorPoint(): { x: number; z: number } { | |
| const areas = FREE_FLOOR_RECTS.map((r) => (r.maxX - r.minX) * (r.maxZ - r.minZ)); | |
| const total = areas.reduce((a, b) => a + b, 0); | |
| let pick = Math.random() * total; | |
| let rect: AabbMm = FREE_FLOOR_RECTS[0]; | |
| for (let i = 0; i < FREE_FLOOR_RECTS.length; i++) { | |
| pick -= areas[i]; | |
| if (pick <= 0) { | |
| rect = FREE_FLOOR_RECTS[i]; | |
| break; | |
| } | |
| } | |
| return { | |
| x: rect.minX + Math.random() * (rect.maxX - rect.minX), | |
| z: rect.minZ + Math.random() * (rect.maxZ - rect.minZ), | |
| }; | |
| } | |
| function generateLocalLayout(config: typeof FLY_AREA_CONFIG, groundOffsetMm: number): FlyInstanceData[] { | |
| return Array.from({ length: config.count }, (_, index) => { | |
| const { x, z } = pickFreeFloorPoint(); | |
| return { | |
| id: `fly-${index}`, | |
| index, | |
| position: [x, groundOffsetMm + Math.random() * config.heightMm, z], | |
| heading: Math.random() * Math.PI * 2, | |
| }; | |
| }); | |
| } | |
| interface RosterEntry { | |
| id: string; | |
| x: number; | |
| y: number; | |
| theta: number; | |
| } | |
| /** | |
| * flyyt-backend (if reachable) owns the fleet roster -- stable serialNumbers | |
| * and spawn positions, so VDA5050 identity means something across page | |
| * reloads (see useVda5050Nats.ts). No backend running is a completely | |
| * normal, fully-supported case ("local practice mode") -- this app has | |
| * always worked standalone and keeps working exactly the same way if the | |
| * fetch fails or times out. | |
| */ | |
| async function fetchRoster(groundOffsetMm: number): Promise<FlyInstanceData[] | null> { | |
| try { | |
| const res = await fetch(apiPath("roster"), { signal: AbortSignal.timeout(1500) }); | |
| if (!res.ok) return null; | |
| const roster: RosterEntry[] = await res.json(); | |
| if (roster.length === 0) return null; | |
| return roster.map((entry, index) => ({ | |
| id: entry.id, | |
| index, | |
| // Same (x,y)->(x,z) conversion as useVda5050Nats.ts's applyPosition. | |
| position: [entry.x, groundOffsetMm, -entry.y], | |
| heading: entry.theta + Math.PI / 2, | |
| })); | |
| } catch { | |
| return null; | |
| } | |
| } | |
| export function useFlyLayout(): FlyInstanceData[] { | |
| const [flies, setFlies] = useState<FlyInstanceData[]>(() => | |
| generateLocalLayout(FLY_AREA_CONFIG, FLY_GROUND_OFFSET_MM), | |
| ); | |
| useEffect(() => { | |
| let cancelled = false; | |
| fetchRoster(FLY_GROUND_OFFSET_MM).then((roster) => { | |
| // Swaps the locally-generated layout for the backend's once it | |
| // arrives, rather than blocking first paint on the fetch -- normally | |
| // near-instant (local dev) or a fast, harmless no-op (unreachable). | |
| if (!cancelled && roster) setFlies(roster); | |
| }); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, []); | |
| return flies; | |
| } | |