|
54 | 54 | replay: document.getElementById("replaySlider"), |
55 | 55 | replayValue: document.getElementById("replayValue"), |
56 | 56 | comparePanel: document.getElementById("comparePanel"), |
| 57 | + timeline: document.getElementById("timeline"), |
57 | 58 | scene: document.getElementById("scene"), |
58 | 59 | traceRows: document.getElementById("traceRows"), |
59 | 60 | stepCounter: document.getElementById("stepCounter"), |
|
575 | 576 |
|
576 | 577 | renderReplay(replayIndex); |
577 | 578 | renderCompare(); |
| 579 | + renderTimeline(replayIndex); |
578 | 580 | renderScene(current); |
579 | 581 | renderTrace(replayIndex); |
580 | 582 | } |
|
632 | 634 | elements.replayValue.textContent = replayLabel(replayIndex); |
633 | 635 | } |
634 | 636 |
|
| 637 | + function renderTimeline(replayIndex) { |
| 638 | + elements.timeline.textContent = ""; |
| 639 | + state.trace.forEach((event, index) => { |
| 640 | + const step = index + 1; |
| 641 | + const button = document.createElement("button"); |
| 642 | + button.className = "timeline-step " + timelineClass(event); |
| 643 | + button.type = "button"; |
| 644 | + button.textContent = String(step); |
| 645 | + button.setAttribute("aria-label", timelineLabel(event, step)); |
| 646 | + if (step === replayIndex) { |
| 647 | + button.classList.add("timeline-active"); |
| 648 | + button.setAttribute("aria-current", "step"); |
| 649 | + } |
| 650 | + button.addEventListener("click", () => setReplayIndex(step)); |
| 651 | + elements.timeline.appendChild(button); |
| 652 | + }); |
| 653 | + } |
| 654 | + |
| 655 | + function timelineClass(event) { |
| 656 | + if (event.failure === "ambiguous_goal") return "timeline-ambiguous"; |
| 657 | + if (event.failure === "unsafe_nominal_step") return "timeline-unsafe"; |
| 658 | + if (event.failure === "grasp_miss") return "timeline-grasp"; |
| 659 | + if (event.failure === "human_correction") return "timeline-human"; |
| 660 | + if (event.agentState === "done") return "timeline-success"; |
| 661 | + return "timeline-neutral"; |
| 662 | + } |
| 663 | + |
| 664 | + function timelineLabel(event, step) { |
| 665 | + return ( |
| 666 | + "Step " + |
| 667 | + step + |
| 668 | + ": " + |
| 669 | + (event.failure || (event.agentState === "done" ? "success" : event.agentState)) |
| 670 | + ); |
| 671 | + } |
| 672 | + |
635 | 673 | function currentReplayIndex() { |
636 | 674 | if (state.replayIndex === null) { |
637 | 675 | return state.trace.length; |
|
0 commit comments