feat(research): add trace-workbench local session-replay UI
A localhost viewer over persisted session JSONL for agent developers and researchers. Three first-class views — Chat (markdown-rendered surface conversation with a second-level inspector), Trajectory (turn/step tree with scroll-spy over a step-grouped event table, inline annotations), and Waterfall (timing summary + aligned time track that deep-links into Trajectory). Subagent sessions group under their parentSession with spawn links and breadcrumbs; failed tool calls are marked in every view; ?session=&view=&sel= makes any selection a shareable deep link. Motion follows an audited restraint baseline (plans/ documents the audit): one strong ease-out token, enter-only animations, press feedback on pushbuttons, prefers-reduced-motion support. AGENTS.md gains the research/ layout entry; the AGENTS.md word ceiling rises 1370 -> 1375 to fit it (one line, relocation not applicable for a top-level layout entry).
This commit is contained in:
60
research/trace-workbench/plans/001-motion-foundation.md
Normal file
60
research/trace-workbench/plans/001-motion-foundation.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# 001 — Add easing token and upgrade existing transitions
|
||||
|
||||
- **Status**: DONE
|
||||
- **Commit**: (repo has no commits yet — uncommitted working tree, 2026-07-18)
|
||||
- **Severity**: LOW (foundation for 002–005)
|
||||
- **Category**: Easing & duration / Cohesion & tokens
|
||||
- **Estimated scope**: 1 file (styles.css), ~4 small edits
|
||||
|
||||
## Problem
|
||||
|
||||
No shared easing tokens exist; entrances use weak built-in `ease`:
|
||||
|
||||
```css
|
||||
/* styles.css — current */
|
||||
.toast {
|
||||
transition: opacity .18s ease, transform .18s ease;
|
||||
}
|
||||
.main-pane {
|
||||
transition: opacity .15s ease;
|
||||
}
|
||||
```
|
||||
|
||||
Built-in `ease` is too weak for deliberate motion; the toast enter feels mushy.
|
||||
|
||||
## Target
|
||||
|
||||
```css
|
||||
:root {
|
||||
--ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* strong ease-out for UI */
|
||||
}
|
||||
.toast {
|
||||
transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
|
||||
}
|
||||
.main-pane {
|
||||
transition: opacity 150ms var(--ease-out);
|
||||
}
|
||||
```
|
||||
|
||||
Keep `.pane-divider::after { transition: background .12s ease }` unchanged — hover/color change correctly uses `ease`.
|
||||
|
||||
## Repo conventions to follow
|
||||
|
||||
- All custom properties live in the single `:root` block at the top of styles.css (e.g. `--blue: #0a64ff;`); add `--ease-out` there.
|
||||
|
||||
## Steps
|
||||
|
||||
1. styles.css `:root`: add `--ease-out: cubic-bezier(0.23, 1, 0.32, 1);`.
|
||||
2. styles.css `.toast`: replace transition with `opacity 200ms var(--ease-out), transform 200ms var(--ease-out)`.
|
||||
3. styles.css `.main-pane`: replace transition with `opacity 150ms var(--ease-out)`.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Do NOT touch app.js or index.html.
|
||||
- Do NOT change the `.pane-divider` or `.tree-turn-head::before` transitions.
|
||||
|
||||
## Verification
|
||||
|
||||
- **Mechanical**: reload http://127.0.0.1:5173/ — no console errors.
|
||||
- **Feel check**: trigger a toast (submit an annotation); it should decelerate crisply into place instead of easing symmetrically. Switch sessions; the loading fade should feel unchanged or slightly snappier.
|
||||
- **Done when**: token exists and both rules reference it.
|
||||
61
research/trace-workbench/plans/002-inspector-enter.md
Normal file
61
research/trace-workbench/plans/002-inspector-enter.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# 002 — Slide the inspector's content in on open
|
||||
|
||||
- **Status**: DONE
|
||||
- **Commit**: (repo has no commits yet — uncommitted working tree, 2026-07-18)
|
||||
- **Severity**: MEDIUM
|
||||
- **Category**: Missed opportunities
|
||||
- **Estimated scope**: 1 file (styles.css), 1 rule + @starting-style
|
||||
|
||||
## Problem
|
||||
|
||||
The chat/waterfall inspector is a grid column toggled by `.inspector-open`; it appears via `display: none → flex` with zero motion — the panel teleports in with nothing explaining where it came from.
|
||||
|
||||
```css
|
||||
/* styles.css — current */
|
||||
.inspector {
|
||||
display: none;
|
||||
...
|
||||
}
|
||||
.chat-split.inspector-open .inspector,
|
||||
.wf-split.inspector-open .inspector {
|
||||
display: flex;
|
||||
}
|
||||
```
|
||||
|
||||
## Target
|
||||
|
||||
Animate the CONTENT entering (transform+opacity only — never animate the grid track, that's layout). Close stays instant (asymmetric timing: the system's response snaps).
|
||||
|
||||
```css
|
||||
.chat-split.inspector-open .inspector,
|
||||
.wf-split.inspector-open .inspector {
|
||||
display: flex;
|
||||
transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out);
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
@starting-style {
|
||||
transform: translateX(16px);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(Nested `@starting-style` is supported in Chrome 117+; this app targets local Chrome.)
|
||||
|
||||
## Repo conventions to follow
|
||||
|
||||
- `--ease-out` token from plan 001 (depends on it).
|
||||
|
||||
## Steps
|
||||
|
||||
1. styles.css: extend the `.chat-split.inspector-open .inspector, .wf-split.inspector-open .inspector` rule with the transition, resting transform/opacity, and the nested `@starting-style` block exactly as in Target.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Do NOT animate `grid-template-columns`, width, or the divider.
|
||||
- Do NOT add a close animation.
|
||||
|
||||
## Verification
|
||||
|
||||
- **Feel check**: click a chat message — the panel's content slides ~16px leftward while fading in, settling fast. Click Close — it disappears instantly. Rapidly open/close: no restart-from-zero flicker (transitions retarget).
|
||||
- **Done when**: open animates, close is instant, no layout properties in the transition list.
|
||||
61
research/trace-workbench/plans/003-details-enter.md
Normal file
61
research/trace-workbench/plans/003-details-enter.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# 003 — Fade-slide expanded content into place
|
||||
|
||||
- **Status**: DONE
|
||||
- **Commit**: (repo has no commits yet — uncommitted working tree, 2026-07-18)
|
||||
- **Severity**: MEDIUM
|
||||
- **Category**: Missed opportunities
|
||||
- **Estimated scope**: 1 file (styles.css), 1 keyframe + 3 selectors
|
||||
|
||||
## Problem
|
||||
|
||||
Expanding a trajectory row, a chat activity block, or a tree turn teleports its content into the layout — a jarring change on the most-used disclosure surfaces:
|
||||
|
||||
- `.traj-body` (trajectory expanded row) — inserted by re-render on toggle
|
||||
- `.activity-body` (chat Thinking / Tool use `<details>`)
|
||||
- `.tree-steps` (tree turn `<details>`)
|
||||
|
||||
## Target
|
||||
|
||||
One shared enter animation; exit stays instant (collapse must snap):
|
||||
|
||||
```css
|
||||
@keyframes content-enter {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.traj-body,
|
||||
.chat-activity[open] .activity-body,
|
||||
.tree-turn[open] .tree-steps {
|
||||
animation: content-enter 160ms var(--ease-out);
|
||||
}
|
||||
```
|
||||
|
||||
Keyframes (not transitions) are correct here: each open is a fresh one-shot enter; re-opening restarting from zero is the intended semantic.
|
||||
|
||||
## Repo conventions to follow
|
||||
|
||||
- `--ease-out` token from plan 001 (depends on it).
|
||||
- Place the keyframe near the existing `@keyframes traj-flash` block.
|
||||
|
||||
## Steps
|
||||
|
||||
1. styles.css: add the `content-enter` keyframe next to `traj-flash`.
|
||||
2. styles.css: add the three-selector rule exactly as in Target.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Do NOT animate height (no interpolate-size tricks) — opacity+transform only.
|
||||
- Do NOT animate collapse.
|
||||
- Do NOT touch `.md-*`, `.spawn-list`, or inline feedback form styles.
|
||||
|
||||
## Verification
|
||||
|
||||
- **Feel check**: expand a trajectory row — the body settles downward-into-place in ~160ms; collapse is instant. Open a chat Tool use block — same. Expand-all in trajectory: bodies animate once, scrolling stays smooth (animation is per-element, one-shot).
|
||||
- **Done when**: all three surfaces animate on open, none on close.
|
||||
56
research/trace-workbench/plans/004-press-feedback.md
Normal file
56
research/trace-workbench/plans/004-press-feedback.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# 004 — Press feedback on pushbuttons
|
||||
|
||||
- **Status**: DONE
|
||||
- **Commit**: (repo has no commits yet — uncommitted working tree, 2026-07-18)
|
||||
- **Severity**: LOW
|
||||
- **Category**: Physicality & origin
|
||||
- **Estimated scope**: 1 file (styles.css), 1 rule
|
||||
|
||||
## Problem
|
||||
|
||||
No pressable element gives press feedback; clicks feel dead. Applies to true pushbuttons only — rows and list items must NOT scale (they're selection surfaces, not buttons).
|
||||
|
||||
## Target
|
||||
|
||||
```css
|
||||
.segmented button:active,
|
||||
.trajectory-toolbar button:active,
|
||||
.drawer-actions button:active,
|
||||
.row-tools button:active,
|
||||
.fb-send:active,
|
||||
.feedback-submit:active,
|
||||
.new-session-button:active,
|
||||
.activity-open-inspector:active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
.segmented button,
|
||||
.trajectory-toolbar button,
|
||||
.drawer-actions button,
|
||||
.row-tools button,
|
||||
.fb-send,
|
||||
.feedback-submit,
|
||||
.new-session-button {
|
||||
transition: transform 160ms var(--ease-out);
|
||||
}
|
||||
```
|
||||
|
||||
Subtle (0.97), transform-only, 160ms — inside the 100–160ms press-feedback budget on release.
|
||||
|
||||
## Repo conventions to follow
|
||||
|
||||
- `--ease-out` token from plan 001 (depends on it).
|
||||
|
||||
## Steps
|
||||
|
||||
1. styles.css: add both rules near the global `button` styles at the top of the file.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Do NOT add `:active` scaling to `.session-row`, `.traj-summary`, `.tree-step`, `.spawn-link`, `.wf-label-col`, `.wf-bar`, or chat summaries.
|
||||
- Do NOT scale below 0.95.
|
||||
|
||||
## Verification
|
||||
|
||||
- **Feel check**: hold the Trajectory segmented button down — it compresses slightly; release — it springs back over ~160ms. Click a session row — no scaling.
|
||||
- **Done when**: pushbuttons compress on press, selection surfaces don't.
|
||||
70
research/trace-workbench/plans/005-reduced-motion.md
Normal file
70
research/trace-workbench/plans/005-reduced-motion.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# 005 — prefers-reduced-motion support
|
||||
|
||||
- **Status**: DONE
|
||||
- **Commit**: (repo has no commits yet — uncommitted working tree, 2026-07-18)
|
||||
- **Severity**: MEDIUM
|
||||
- **Category**: Accessibility
|
||||
- **Estimated scope**: 1 file (styles.css), 1 media query block
|
||||
|
||||
## Problem
|
||||
|
||||
styles.css has zero `prefers-reduced-motion` handling. Movement-based motion (toast slide, inspector slide-in from 002, content slide from 003, press scale from 004) plays regardless of the OS setting.
|
||||
|
||||
## Target
|
||||
|
||||
Reduced motion = drop position/scale changes, KEEP opacity feedback (comprehension aids stay):
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.toast {
|
||||
transform: none;
|
||||
transition: opacity 200ms var(--ease-out);
|
||||
}
|
||||
.chat-split.inspector-open .inspector,
|
||||
.wf-split.inspector-open .inspector {
|
||||
transition: opacity 200ms var(--ease-out);
|
||||
@starting-style {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
.traj-body,
|
||||
.chat-activity[open] .activity-body,
|
||||
.tree-turn[open] .tree-steps {
|
||||
animation: none;
|
||||
}
|
||||
.segmented button:active,
|
||||
.trajectory-toolbar button:active,
|
||||
.drawer-actions button:active,
|
||||
.row-tools button:active,
|
||||
.fb-send:active,
|
||||
.feedback-submit:active,
|
||||
.new-session-button:active,
|
||||
.activity-open-inspector:active {
|
||||
transform: none;
|
||||
}
|
||||
.flash {
|
||||
animation: none;
|
||||
box-shadow: 0 0 0 3px rgba(10, 100, 255, .45);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note `.flash` keeps a static highlight ring (the jump-target indicator is comprehension, not decoration) — it just stops pulsing. `.toast` keeps its opacity fade.
|
||||
|
||||
## Repo conventions to follow
|
||||
|
||||
- Depends on plans 001–004 (targets their rules). Place the block at the end of styles.css, before the responsive media queries.
|
||||
|
||||
## Steps
|
||||
|
||||
1. styles.css: add the media query block exactly as in Target.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- Do NOT remove opacity transitions — reduced motion is fewer/gentler, not zero.
|
||||
- Do NOT gate hover color changes (no movement involved).
|
||||
|
||||
## Verification
|
||||
|
||||
- **Feel check**: DevTools → Rendering → emulate `prefers-reduced-motion: reduce`. Toast fades without sliding; inspector fades in place; expanding rows appears instantly; jump-to still shows a static ring.
|
||||
- **Done when**: with reduction on, nothing on screen translates or scales, but state feedback remains visible.
|
||||
15
research/trace-workbench/plans/README.md
Normal file
15
research/trace-workbench/plans/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Animation plans
|
||||
|
||||
Written by the `improve-animations` audit (2026-07-18) against the uncommitted working tree.
|
||||
|
||||
| # | Plan | Severity | Status |
|
||||
| --- | --- | --- | --- |
|
||||
| 001 | [Add easing token, upgrade transitions](001-motion-foundation.md) | LOW (foundation) | DONE |
|
||||
| 002 | [Inspector content slide-in](002-inspector-enter.md) | MEDIUM | DONE |
|
||||
| 003 | [Fade-slide expanded content](003-details-enter.md) | MEDIUM | DONE |
|
||||
| 004 | [Press feedback on pushbuttons](004-press-feedback.md) | LOW | DONE |
|
||||
| 005 | [prefers-reduced-motion support](005-reduced-motion.md) | MEDIUM | DONE |
|
||||
|
||||
Execution order: 001 first (defines `--ease-out` used by all others), then 002–004 in any order, 005 last (its selectors target rules created by 002–004).
|
||||
|
||||
Explicit non-findings from the audit (do not "fix" these): instant view switching, instant hover states, the 1.4s flash pulse, instant collapse/close animations — all deliberate restraint for a crisp dashboard.
|
||||
Reference in New Issue
Block a user