Download src/components/autonomy/AutonomyStack.tsx from whassan/attention: direct link, hf CLI and curl.
- Browser
- Download file 12 kB
-
https://huggingface.co/spaces/whassan/attention/resolve/main/src/components/autonomy/AutonomyStack.tsx
- Command line
-
hf download hf://spaces/whassan/attention/src/components/autonomy/AutonomyStack.tsx
-
curl -L -o AutonomyStack.tsx https://huggingface.co/spaces/whassan/attention/resolve/main/src/components/autonomy/AutonomyStack.tsx
12 kB
| import { useEffect, useMemo, useState } from "react"; | |
| import { Pause, Play, RotateCcw, SkipForward } from "lucide-react"; | |
| import { | |
| FLOW_ORDER, | |
| FRAMES, | |
| LEARNING_ORDER, | |
| PLANES, | |
| RUNTIME_ORDER, | |
| SAFETY_ORDER, | |
| STAGES, | |
| type StageId, | |
| } from "../../data/autonomy"; | |
| import { FlowArrow, StageCard } from "./StageCard"; | |
| import { StageDetail } from "./StageDetail"; | |
| type Props = { | |
| openStage: StageId | null; | |
| onOpenStage: (id: StageId | null) => void; | |
| }; | |
| const PHASES: { key: string; label: string; stages: StageId[] }[] = [ | |
| { key: "sense", label: "Sense", stages: ["sensors", "fusion"] }, | |
| { key: "understand", label: "Understand", stages: ["perception"] }, | |
| { key: "predict", label: "Predict", stages: ["prediction"] }, | |
| { key: "decide", label: "Decide", stages: ["behavior", "motion"] }, | |
| { key: "act", label: "Act", stages: ["control", "actuators"] }, | |
| { key: "verify", label: "Verify", stages: ["supervisor"] }, | |
| { key: "learn", label: "Learn", stages: ["capture"] }, | |
| ]; | |
| const TICK_MS = 1500; | |
| const CYCLE: StageId[] = [...RUNTIME_ORDER, "world"]; | |
| export function AutonomyStack({ openStage, onOpenStage }: Props) { | |
| const [playing, setPlaying] = useState(true); | |
| const [tick, setTick] = useState(0); | |
| useEffect(() => { | |
| if (!playing) return; | |
| const id = window.setInterval(() => setTick((t) => t + 1), TICK_MS); | |
| return () => window.clearInterval(id); | |
| }, [playing]); | |
| const cycle = Math.floor(tick / CYCLE.length); | |
| const activeRuntime = CYCLE[tick % CYCLE.length]!; | |
| const frame = FRAMES[cycle % FRAMES.length]!; | |
| const activeLearning = LEARNING_ORDER[Math.floor(tick / 3) % LEARNING_ORDER.length]!; | |
| const overriding = frame.safety === "override"; | |
| const gating = activeRuntime === "control" || activeRuntime === "actuators"; | |
| const phase = useMemo( | |
| () => PHASES.find((item) => item.stages.includes(activeRuntime))?.key ?? "sense", | |
| [activeRuntime], | |
| ); | |
| const activeIds = useMemo(() => { | |
| const set = new Set<StageId>([activeRuntime, activeLearning]); | |
| if (gating || overriding) set.add("supervisor"); | |
| if (overriding) set.add("fallback"); | |
| return set; | |
| }, [activeLearning, activeRuntime, gating, overriding]); | |
| const step = () => { | |
| setPlaying(false); | |
| setTick((t) => t + 1); | |
| }; | |
| const detail = openStage ? STAGES[openStage] : null; | |
| const detailIndex = openStage ? FLOW_ORDER.indexOf(openStage) : -1; | |
| return ( | |
| <section aria-label="Autonomy stack emulator" className="space-y-5"> | |
| <div className="rounded-xl border border-white/10 bg-[#0e1624] p-4"> | |
| <h2 className="font-mono text-[10px] tracking-[0.22em] text-cyan-200/80 uppercase"> | |
| Closed loop | |
| </h2> | |
| <ol className="mt-3 flex flex-wrap items-center gap-x-2 gap-y-2"> | |
| {PHASES.map((item, index) => ( | |
| <li key={item.key} className="flex items-center gap-2"> | |
| <span | |
| className={`rounded-md border px-2.5 py-1 text-xs transition-colors ${ | |
| phase === item.key | |
| ? "border-cyan-300/70 bg-cyan-400/15 text-white" | |
| : "border-white/10 text-slate-400" | |
| }`} | |
| > | |
| {item.label} | |
| </span> | |
| {index < PHASES.length - 1 ? ( | |
| <span aria-hidden className="text-slate-600"> | |
| → | |
| </span> | |
| ) : null} | |
| </li> | |
| ))} | |
| </ol> | |
| <p className="mt-3 text-sm leading-relaxed text-slate-400"> | |
| An autonomy stack is not a pipeline that ends. Every action changes | |
| the world, the sensors measure the change, and the loop runs again — | |
| typically ten to twenty times a second. | |
| </p> | |
| </div> | |
| <div className="sticky top-0 z-20 rounded-xl border border-white/10 bg-[#0b1220]/95 p-3 backdrop-blur-md sm:p-4"> | |
| <div className="flex flex-wrap items-center justify-between gap-3"> | |
| <div className="min-w-0"> | |
| <p className="font-mono text-[10px] tracking-[0.22em] text-cyan-200/80 uppercase"> | |
| Scenario · {frame.label} · cycle {cycle + 1} | |
| </p> | |
| <p className="text-sm font-medium text-white">{frame.headline}</p> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <span | |
| className={`rounded-md border px-2.5 py-1 font-mono text-[10px] tracking-wide uppercase ${ | |
| overriding | |
| ? "border-rose-400/60 bg-rose-500/15 text-rose-100" | |
| : "border-emerald-400/40 bg-emerald-500/10 text-emerald-100" | |
| }`} | |
| > | |
| {overriding ? "Safety override" : "Nominal"} | |
| </span> | |
| <button | |
| type="button" | |
| onClick={() => setPlaying((value) => !value)} | |
| aria-label={playing ? "Pause emulator" : "Play emulator"} | |
| className="inline-flex min-h-11 items-center gap-1.5 rounded-md border border-white/15 bg-white/5 px-3 py-2 text-xs text-slate-100 hover:bg-white/10" | |
| > | |
| {playing ? <Pause className="h-3.5 w-3.5" /> : <Play className="h-3.5 w-3.5" />} | |
| {playing ? "Pause" : "Play"} | |
| </button> | |
| <button | |
| type="button" | |
| onClick={step} | |
| aria-label="Step one stage" | |
| className="inline-flex min-h-11 items-center gap-1.5 rounded-md border border-white/15 bg-white/5 px-3 py-2 text-xs text-slate-100 hover:bg-white/10" | |
| > | |
| <SkipForward className="h-3.5 w-3.5" /> | |
| Step | |
| </button> | |
| <button | |
| type="button" | |
| onClick={() => { | |
| setTick(0); | |
| setPlaying(true); | |
| }} | |
| aria-label="Restart emulator" | |
| className="inline-flex min-h-11 items-center gap-1.5 rounded-md border border-white/15 bg-white/5 px-3 py-2 text-xs text-slate-100 hover:bg-white/10" | |
| > | |
| <RotateCcw className="h-3.5 w-3.5" /> | |
| Restart | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="grid gap-5 lg:grid-cols-[minmax(0,1.25fr)_minmax(15rem,0.85fr)]"> | |
| <div className="min-w-0"> | |
| <h3 className="mb-3 font-mono text-[10px] tracking-[0.22em] text-slate-500 uppercase"> | |
| Autonomy runtime | |
| </h3> | |
| <StageCard | |
| stage={STAGES.mission} | |
| active={false} | |
| readout={frame.readouts.mission} | |
| alwaysShowReadout | |
| onOpen={() => onOpenStage("mission")} | |
| /> | |
| <FlowArrow label="route + constraints" /> | |
| {RUNTIME_ORDER.map((id, index) => ( | |
| <div key={id}> | |
| <StageCard | |
| stage={STAGES[id]} | |
| active={activeIds.has(id)} | |
| alert={overriding && (id === "control" || id === "actuators")} | |
| readout={frame.readouts[id]} | |
| onOpen={() => onOpenStage(id)} | |
| /> | |
| {index === RUNTIME_ORDER.length - 1 ? null : ( | |
| <FlowArrow | |
| label={ | |
| id === "motion" ? "proposed trajectory → safety check" : undefined | |
| } | |
| /> | |
| )} | |
| </div> | |
| ))} | |
| <FlowArrow label="force applied to the world" /> | |
| <StageCard | |
| stage={STAGES.world} | |
| active={activeIds.has("world")} | |
| readout={frame.readouts.world} | |
| onOpen={() => onOpenStage("world")} | |
| /> | |
| <p className="mt-3 rounded-lg border border-dashed border-cyan-300/30 bg-cyan-400/5 px-3 py-2.5 text-xs leading-relaxed text-cyan-100/90"> | |
| ↺ The world feeds the sensor layer again. This edge is what turns a | |
| perception model into a control system. | |
| </p> | |
| </div> | |
| <div className="space-y-6"> | |
| <div> | |
| <h3 className="mb-1 font-mono text-[10px] tracking-[0.22em] text-slate-500 uppercase"> | |
| Safety & supervision | |
| </h3> | |
| <p className="mb-3 text-xs leading-relaxed text-slate-500"> | |
| Sits between the planner and the actuators with independent | |
| authority to say no. | |
| </p> | |
| <div className="space-y-2"> | |
| {SAFETY_ORDER.map((id) => ( | |
| <StageCard | |
| key={id} | |
| stage={STAGES[id]} | |
| compact | |
| active={activeIds.has(id)} | |
| alert={overriding} | |
| readout={frame.readouts[id]} | |
| alwaysShowReadout={id === "health"} | |
| onOpen={() => onOpenStage(id)} | |
| /> | |
| ))} | |
| </div> | |
| </div> | |
| <div> | |
| <h3 className="mb-1 font-mono text-[10px] tracking-[0.22em] text-slate-500 uppercase"> | |
| Data & learning plane | |
| </h3> | |
| <p className="mb-3 text-xs leading-relaxed text-slate-500"> | |
| Runs offline, on fleet time rather than frame time. This is the | |
| autonomy development stack. | |
| </p> | |
| {frame.capture ? ( | |
| <p className="mb-3 rounded-md border border-emerald-400/40 bg-emerald-500/10 px-3 py-2 font-mono text-[11px] text-emerald-100"> | |
| event captured · {frame.capture} | |
| </p> | |
| ) : null} | |
| <div className="space-y-2"> | |
| {LEARNING_ORDER.map((id) => ( | |
| <StageCard | |
| key={id} | |
| stage={STAGES[id]} | |
| compact | |
| active={activeIds.has(id)} | |
| readout={frame.readouts[id]} | |
| onOpen={() => onOpenStage(id)} | |
| /> | |
| ))} | |
| </div> | |
| <p className="mt-3 rounded-lg border border-dashed border-emerald-300/30 bg-emerald-400/5 px-3 py-2.5 text-xs leading-relaxed text-emerald-100/90"> | |
| ↺ Release feeds the runtime. The autonomy stack drives the car; | |
| this loop is what makes next month's car better. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="rounded-xl border border-white/10 bg-[#0e1624] p-4"> | |
| <h3 className="font-mono text-[10px] tracking-[0.22em] text-slate-500 uppercase"> | |
| Six interacting planes | |
| </h3> | |
| <div className="mt-3 grid gap-2 sm:grid-cols-2"> | |
| {(Object.keys(PLANES) as (keyof typeof PLANES)[]).map((key) => ( | |
| <div | |
| key={key} | |
| className="rounded-lg border border-white/10 px-3 py-2" | |
| style={{ boxShadow: `inset 3px 0 0 ${PLANES[key].accent}` }} | |
| > | |
| <p | |
| className="font-mono text-[10px] tracking-[0.18em] uppercase" | |
| style={{ color: PLANES[key].accent }} | |
| > | |
| {PLANES[key].label} | |
| </p> | |
| <p className="mt-1 text-xs leading-relaxed text-slate-400"> | |
| {PLANES[key].blurb} | |
| </p> | |
| </div> | |
| ))} | |
| </div> | |
| <p className="mt-4 text-sm leading-relaxed text-slate-400"> | |
| There is no single "AI" box. Learning shows up in perception, fusion, | |
| the world model, prediction, behavior, motion costs, simulation, and | |
| scenario mining — while safety stays deliberately deterministic around | |
| all of it. | |
| </p> | |
| </div> | |
| {detail ? ( | |
| <StageDetail | |
| stage={detail} | |
| live={frame.readouts[detail.id]} | |
| neighbors={{ | |
| prev: FLOW_ORDER[(detailIndex - 1 + FLOW_ORDER.length) % FLOW_ORDER.length]!, | |
| next: FLOW_ORDER[(detailIndex + 1) % FLOW_ORDER.length]!, | |
| }} | |
| onOpen={onOpenStage} | |
| onClose={() => onOpenStage(null)} | |
| /> | |
| ) : null} | |
| </section> | |
| ); | |
| } | |