transitions-refine 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: refine-live
3
- description: Become the live "Refine" agent for the Timeline Inspector. Use when the user runs `/refine live`, asks to "refine live", "go live", "answer refine jobs", or wants the timeline panel's Refine button (LLM mode) or Accept button to be backed by a real agent. Long-polls the local refine relay, reasons about each CSS transition with the transitions-dev skill, posts suggestions back to the browser panel, and for "apply" jobs writes the accepted timing changes into the user's source code.
3
+ description: Become the live "Refine" agent for the Timeline Inspector. Use when the user runs `/refine live`, asks to "refine live", "go live", "answer refine jobs", or wants the timeline panel's Refine button (LLM mode), Accept button, or grouped scan to be backed by a real agent. Long-polls the local refine relay, reasons about each CSS transition with the transitions-dev skill, posts suggestions back to the browser panel, for "scan" jobs groups the page's transitions into components with open/close phases by reading the source, and for "apply" jobs writes the accepted timing changes into the user's source code.
4
4
  ---
5
5
 
6
6
  # Refine Live
@@ -54,6 +54,10 @@ never has to re-run `/refine live`.
54
54
  }
55
55
  ```
56
56
 
57
+ - **If `request.kind === "scan"`** this is not a suggestion job — the panel is
58
+ asking you to group the page's transitions by reading the source. Jump to
59
+ [`## Scan jobs`](#scan-jobs-group-from-source) and return `groups` instead of
60
+ suggestions.
57
61
  - **If `request.kind === "apply"`** this is not a suggestion job — the user
58
62
  pressed **Accept** to write changes to their code. Jump to
59
63
  [`## Apply jobs`](#apply-jobs-write-to-source) and edit the source instead of
@@ -176,6 +180,78 @@ never has to re-run `/refine live`.
176
180
  stop, tell them the LLM tab will go unavailable and how to restart
177
181
  (`/refine live`).
178
182
 
183
+ ## Scan jobs (group from source)
184
+
185
+ When a claimed job has `request.kind === "scan"`, the panel wants you to turn a
186
+ flat list of DOM-detected transitions into **components with phases**. A naive
187
+ DOM scan only sees each element's *current* computed transition — it can't tell
188
+ open from close, and lists related elements (panel, backdrop, staggered items)
189
+ separately. You fix that by reading the source. The request looks like:
190
+
191
+ ```json
192
+ {
193
+ "id": "uuid",
194
+ "request": {
195
+ "kind": "scan",
196
+ "url": "http://localhost:5173/",
197
+ "raw": [
198
+ { "label": "div.dropdown-panel", "selector": ".dropdown-panel",
199
+ "properties": ["opacity","transform"],
200
+ "timings": [{ "property": "opacity", "durationMs": 200, "delayMs": 0, "easing": "ease-out" }] }
201
+ ]
202
+ }
203
+ }
204
+ ```
205
+
206
+ Do this:
207
+
208
+ 1. **Identify each animated component** the raw entries belong to (dropdown,
209
+ modal, tooltip, accordion, drawer, toast…). Use the selectors/labels as hints,
210
+ then read the source — plain CSS / CSS Modules, styled-components/emotion,
211
+ Tailwind, inline styles, or Motion/Framer variants.
212
+ 2. **Split each component into phases** — usually `open` and `close` (a hover-only
213
+ component can be a single phase). Open and close often live on different
214
+ selectors (`.is-open` vs `.is-closing`) with different timings; report **both**
215
+ even though only one is in the DOM right now.
216
+ 3. **List each phase's members** — the elements that animate in that phase. Give
217
+ each a stable `id`, a human `label`, a live-resolvable CSS `selector`, an
218
+ optional `toState` hint (the class/attribute that drives the phase, e.g.
219
+ `.is-open`), and its real `propertyTimings`. **Quote the real timings from the
220
+ source — never invent.**
221
+ 4. **Post the groups** (this completes the job):
222
+
223
+ ```bash
224
+ curl -s -X POST http://localhost:7331/jobs/<id>/result \
225
+ -H 'Content-Type: application/json' \
226
+ -d '{
227
+ "summary": "Grouped Dropdown into Open/Close.",
228
+ "groups": [
229
+ { "id": "dropdown", "label": "Dropdown", "component": "src/Dropdown.tsx",
230
+ "phases": [
231
+ { "id": "dropdown:open", "phase": "open", "label": "Open", "members": [
232
+ { "id": "panel", "label": "Panel", "selector": ".dropdown-panel", "toState": ".is-open",
233
+ "propertyTimings": [
234
+ { "property": "opacity", "durationMs": 200, "delayMs": 0, "easing": "ease-out" },
235
+ { "property": "transform", "durationMs": 200, "delayMs": 0, "easing": "cubic-bezier(0.22, 1, 0.36, 1)" }
236
+ ] }
237
+ ] },
238
+ { "id": "dropdown:close", "phase": "close", "label": "Close", "members": [
239
+ { "id": "panel", "label": "Panel", "selector": ".dropdown-panel", "toState": ".is-closing",
240
+ "propertyTimings": [
241
+ { "property": "opacity", "durationMs": 150, "delayMs": 0, "easing": "ease-in" }
242
+ ] }
243
+ ] }
244
+ ] }
245
+ ]
246
+ }'
247
+ ```
248
+
249
+ If you can't confidently group anything, post `{"groups":[],"summary":"…"}` —
250
+ the panel keeps its flat DOM scan. Reserve `/jobs/<id>/error` for unexpected
251
+ failures.
252
+
253
+ Then go back to step 1 of the loop.
254
+
179
255
  ## Apply jobs (write to source)
180
256
 
181
257
  When a claimed job has `request.kind === "apply"`, the user accepted their current
@@ -186,10 +262,14 @@ timeline values and wants them written to the codebase. The request looks like:
186
262
  "id": "uuid",
187
263
  "request": {
188
264
  "kind": "apply",
189
- "label": "div.modal.t-modal",
190
- "selector": "div.modal > button.close",
265
+ "label": "Dropdown · Close",
266
+ "selector": ".dropdown-panel",
267
+ "component": "src/Dropdown.tsx",
268
+ "group": "Dropdown",
269
+ "phase": "close",
191
270
  "changes": [
192
- { "property": "opacity", "from": { "durationMs": 300, "delayMs": 0, "easing": "ease" },
271
+ { "property": "opacity", "member": "Panel", "selector": ".dropdown-panel",
272
+ "from": { "durationMs": 300, "delayMs": 0, "easing": "ease" },
193
273
  "to": { "durationMs": 150, "delayMs": 0, "easing": "cubic-bezier(0.4, 0, 1, 1)" } }
194
274
  ]
195
275
  }
@@ -199,15 +279,19 @@ timeline values and wants them written to the codebase. The request looks like:
199
279
  Do this:
200
280
 
201
281
  1. **Locate the real declaration in the source.** The `selector` is a DOM-path
202
- *hint*, not necessarily the source selector. Search by the label/class names and
203
- handle whatever the project uses: plain CSS / CSS Modules, styled-components or
204
- emotion template literals, Tailwind utilities (`duration-300`, arbitrary
205
- `[transition-duration:300ms]`, or the `tailwind.config` theme), and inline
206
- `style={{ transition: … }}` objects. Match by the `from` values to disambiguate.
282
+ *hint*, not necessarily the source selector. Use the `component` hint and search
283
+ by the label/class names; handle whatever the project uses: plain CSS / CSS
284
+ Modules, styled-components or emotion template literals, Tailwind utilities
285
+ (`duration-300`, arbitrary `[transition-duration:300ms]`, or the
286
+ `tailwind.config` theme), inline `style={{ transition: … }}` objects, and
287
+ Motion/Framer variants. Match by the `from` values to disambiguate.
288
+ - **If `phase` is set** (e.g. `"open"`/`"close"`), edit only that state's rule
289
+ (the `.is-open` rule for open, the `.is-closing`/base rule for close) — not
290
+ the other phase. Each change's `member` + `selector` says which element.
207
291
  2. **Edit each change's property** to its `to` values (`durationMs` ms, `easing`,
208
- `delayMs` ms). Keep the file's existing unit/format (`0.25s` vs `250ms`) and
209
- touch only that property's timing. If a CSS variable / design token backs the
210
- value, update it at the single most sensible place.
292
+ `delayMs` ms) on the right member + phase. Keep the file's existing unit/format
293
+ (`0.25s` vs `250ms`) and touch only that property's timing. If a CSS variable /
294
+ design token backs the value, update it at the single most sensible place.
211
295
  3. **Minimal edit** — no reformatting or unrelated changes.
212
296
  4. **Post the outcome** (this completes the job):
213
297
 
package/README.md CHANGED
@@ -4,6 +4,10 @@ A live, agent-driven **Refine** panel for CSS and [Motion](https://motion.dev) t
4
4
 
5
5
  The feedback shows up **in a panel that slides in from the right** — not in your chat — and you pick which suggestions to apply. Applied suggestions are **live overrides** (instant preview, reversible) — the same path as dragging the timeline bars. When you're happy, **Accept** writes those values back into your source via the agent.
6
6
 
7
+ There's **no play button or scrubber** — the running component *is* the preview. Any edit (a dragged bar, an inspector tweak, or an applied suggestion) is written straight onto the live element as an inline `transition`, so you see it the next time you trigger the transition (open the dropdown, hover the card, …). Reset reverts the element to its source.
8
+
9
+ Real components rarely live in one CSS rule. A dropdown has an **Open** and a **Close** phase, each animating several elements (panel, backdrop, staggered items) with different timings — and the close phase usually isn't even in the DOM while the panel is open. So when the panel opens it also asks the agent to **read your source and group** the page's transitions into components → phases → member elements. You then pick a whole phase (e.g. *Dropdown · Open*) and see every sub-transition as a labeled lane on one shared timeline. If no agent is live, the panel falls back to the flat DOM scan with no regression.
10
+
7
11
  Inspired by the [impeccable.style](https://impeccable.style/live-mode/) "live" pattern: the browser drops a job in a tiny local relay, and the relay answers it with **one agent run per click**. No standing loop, nothing to start per click — you just keep the relay running.
8
12
 
9
13
  ```
@@ -54,6 +58,12 @@ REFINE_AGENT_CMD='cursor-agent -p' npm run relay # or: codex exec - | claude
54
58
 
55
59
  The CLI must have the `transitions-dev` skill available (the prompt tells it to read the skill).
56
60
 
61
+ ## Grouped scan — Open / Close phases
62
+
63
+ When the panel opens it posts a **scan job** to the relay; the agent reads your source and returns the page's animated components, each split into phases (`open`, `close`, …) with their **member elements** and the *real* per-state timings — including the close transition the DOM can't show you. The picker then groups by component, you select a phase, and the timeline renders one lane per member-property (each lane labeled with its member) on a single time axis so stagger and delays line up. Editing any lane applies **live** as an inline `transition` on that member element, so triggering the component yourself (open/close it) previews the whole phase with your values; **Accept** writes back to the correct state rule (`.is-open` vs `.is-closing`) per member.
64
+
65
+ Grouping needs the agent (`/refine live`, `--llm`, or `REFINE_AGENT_CMD`); with no agent the panel just shows the flat DOM scan as before.
66
+
57
67
  ## Refine modes
58
68
 
59
69
  - **Small refinements** — keeps the transition, suggests motion-token tweaks (duration/easing), and may add a whole-transition replacement when one clearly fits better.
@@ -63,7 +73,7 @@ The CLI must have the `transitions-dev` skill available (the prompt tells it to
63
73
 
64
74
  The **Accept** button (next to Refine) is enabled whenever the selected transition has unsaved changes — whether you edited the bars/easing by hand or applied a Refine suggestion. Pressing it sends an **apply job** to the relay: the agent finds where that transition is declared in your source (plain CSS, CSS Modules, styled-components/emotion, Tailwind, or inline styles), edits only the changed timings, and reports back. The button shows a spinner while saving and flips to **Done** on success.
65
75
 
66
- Like Replace, Accept needs the agent — run `/refine live` (or `--llm` / `REFINE_AGENT_CMD`). The deterministic answerer can't edit files. Play preview also no longer needs you to trigger the transition first: it recovers the end-state from your stylesheets (hover/focus pseudo-states and toggled classes like `.modal.open`), so opening the panel and pressing Play just works.
76
+ Like Replace, Accept needs the agent — run `/refine live` (or `--llm` / `REFINE_AGENT_CMD`). The deterministic answerer can't edit files.
67
77
 
68
78
  ## Pieces
69
79
 
@@ -86,7 +96,7 @@ Like Replace, Accept needs the agent — run `/refine live` (or `--llm` / `REFIN
86
96
  | `REFINE_AUTO=0` | — | disable auto-answer and wait for an external poller |
87
97
  | `window.REFINE_RELAY_URL` | injected origin | browser override for the relay URL |
88
98
 
89
- Endpoints: `POST /jobs` (refine or `kind: "apply"`), `GET /jobs/:id` (browser). In `REFINE_AUTO=0` mode an external poller also uses `GET /jobs/next` and `POST /jobs/:id/{status,result,error}`.
99
+ Endpoints: `POST /jobs` (refine, `kind: "apply"`, or `kind: "scan"`), `GET /jobs/:id` (browser). In `REFINE_AUTO=0` mode an external poller also uses `GET /jobs/next` and `POST /jobs/:id/{status,result,error}` (the result body accepts `suggestions`, `groups`, or `applied`).
90
100
 
91
101
  Refine suggestions stay as live overrides until you press **Accept**, which is the explicit step that writes them into your source.
92
102