transitions-refine 0.3.23 → 0.3.25
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.
- package/demo.html +909 -87
- package/package.json +2 -2
- package/server/motion-tokens.mjs +34 -0
- package/server/relay.mjs +2 -2
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "transitions-refine",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.25",
|
|
4
4
|
"description": "Live, agent-driven Refine panel for CSS/Motion transitions — injects a timeline + Refine UI and runs transitions.dev suggestions via your coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"refine": "
|
|
7
|
+
"refine": "bin/cli.mjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
package/server/motion-tokens.mjs
CHANGED
|
@@ -133,6 +133,7 @@ export function refineTimings(timings, ctx) {
|
|
|
133
133
|
const suggestions = [];
|
|
134
134
|
if (!Array.isArray(timings)) return suggestions;
|
|
135
135
|
const c = ctx || {};
|
|
136
|
+
const blurByMember = new Map(); // memberKey -> {member,hint,sawBlur,varName}
|
|
136
137
|
|
|
137
138
|
for (const t of timings) {
|
|
138
139
|
const prop = t.property || "all";
|
|
@@ -140,6 +141,13 @@ export function refineTimings(timings, ctx) {
|
|
|
140
141
|
// with this lane's own property/member so component words (dropdown, modal,
|
|
141
142
|
// page slide…) are visible to the usage matcher.
|
|
142
143
|
const hint = [c.label, c.selector, c.phase, t.hint, t.property, t.member].filter(Boolean).join(" ");
|
|
144
|
+
const memberKey = t.member || "__all__";
|
|
145
|
+
if (!blurByMember.has(memberKey)) {
|
|
146
|
+
blurByMember.set(memberKey, { member: t.member || null, hint, sawBlur: false, varName: null });
|
|
147
|
+
}
|
|
148
|
+
const bm = blurByMember.get(memberKey);
|
|
149
|
+
bm.hint = [bm.hint, hint].filter(Boolean).join(" ");
|
|
150
|
+
if (t.varName && (!bm.varName || prop === "filter")) bm.varName = t.varName;
|
|
143
151
|
|
|
144
152
|
// Duration → nearest token (skip if already on-grid or within 10ms).
|
|
145
153
|
if (Number.isFinite(t.durationMs)) {
|
|
@@ -199,6 +207,7 @@ export function refineTimings(timings, ctx) {
|
|
|
199
207
|
// Blur → a transitions.dev blur token (usage-first, nearest fallback). The
|
|
200
208
|
// captured value is the non-resting "pre" blur (settles to 0); skip 0/none.
|
|
201
209
|
if (Number.isFinite(t.blur) && t.blur > 1e-4) {
|
|
210
|
+
bm.sawBlur = true;
|
|
202
211
|
const usage = pickBlurByUsage(hint);
|
|
203
212
|
const { token: near, delta } = nearestBlur(t.blur);
|
|
204
213
|
const token = usage || near;
|
|
@@ -218,5 +227,30 @@ export function refineTimings(timings, ctx) {
|
|
|
218
227
|
}
|
|
219
228
|
}
|
|
220
229
|
|
|
230
|
+
// Missing-blur detection: when usage clearly maps to a blur token but no blur
|
|
231
|
+
// lane is present, suggest adding one so the motion isn't opacity-only.
|
|
232
|
+
for (const [memberKey, info] of blurByMember) {
|
|
233
|
+
if (info.sawBlur) continue;
|
|
234
|
+
const token = pickBlurByUsage(info.hint);
|
|
235
|
+
if (!token) continue;
|
|
236
|
+
const member = info.member;
|
|
237
|
+
suggestions.push({
|
|
238
|
+
id: `${memberKey}-blur-add`,
|
|
239
|
+
kind: "blur",
|
|
240
|
+
property: "filter",
|
|
241
|
+
member,
|
|
242
|
+
title: `Blur → ${token.name}`,
|
|
243
|
+
from: "0px",
|
|
244
|
+
to: `${token.px}px`,
|
|
245
|
+
patch: {
|
|
246
|
+
property: "filter",
|
|
247
|
+
blur: token.px,
|
|
248
|
+
...(info.varName ? { varName: info.varName } : {}),
|
|
249
|
+
...(member ? { member } : {}),
|
|
250
|
+
},
|
|
251
|
+
reason: `${token.name} (${token.px}px) is the transitions.dev blur token for ${token.usage}. This transition currently has no blur.`,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
221
255
|
return suggestions;
|
|
222
256
|
}
|
package/server/relay.mjs
CHANGED
|
@@ -300,7 +300,7 @@ function buildPrompt(job) {
|
|
|
300
300
|
);
|
|
301
301
|
if (multiPhase) {
|
|
302
302
|
lines.push(
|
|
303
|
-
"RELATED PHASES: `phases` lists this transition's related states (e.g. open AND close). They are ONE motion — a recipe swap must update them TOGETHER. For the replace suggestion emit a `patches` array with ONE entry per phase in `phases`,
|
|
303
|
+
"RELATED PHASES: `phases` lists this transition's related states (e.g. open AND close). They are ONE motion — a recipe swap must update them TOGETHER. For the replace suggestion emit a `patches` array with ONE timing entry per phase in `phases`, shaped `{\"phase\":<phase>,\"property\":\"all\",\"durationMs\":...,\"easing\":...}`. If the recipe also uses transform pre-scale or filter pre-blur, add EXTRA per-lane value patches for those lanes (not property:\"all\") and include that lane's `member` + `varName` from input timings, e.g. `{\"phase\":\"open\",\"property\":\"transform\",\"member\":\"Panel\",\"varName\":\"--dropdown-pre-scale\",\"scale\":0.97}` and `{\"phase\":\"open\",\"property\":\"filter\",\"member\":\"Panel\",\"varName\":\"--panel-blur\",\"blur\":2}`. Take each phase duration from MOTION TOKENS (open usually slower than close, e.g. 250ms/150ms). Also include a single `patch` for live preview (first timing patch is fine). Apply will write every phase from `patches`.",
|
|
304
304
|
"",
|
|
305
305
|
);
|
|
306
306
|
}
|
|
@@ -335,7 +335,7 @@ function buildPrompt(job) {
|
|
|
335
335
|
'A scale tweak looks like {"id":"transform-scale","kind":"scale","property":"transform","member":"Menu","title":"Scale → Medium","from":"0.8","to":"0.97","patch":{"property":"transform","member":"Menu","scale":0.97},"reason":"…"}; a blur tweak like {"id":"filter-blur","kind":"blur","property":"filter","member":"Panel","title":"Blur → Small","from":"8px","to":"2px","patch":{"property":"filter","member":"Panel","blur":2},"reason":"…"}.',
|
|
336
336
|
"CRITICAL — `member`: every suggestion and its `patch` MUST echo the `member` of the input lane it came from, copied VERBATIM from that lane in the data above. This is REQUIRED whenever any input lane carries a `member` — most importantly when several lanes share the same `property` (e.g. a dropdown where a caret does `transform: rotate` AND a panel does `transform: scale`): the `member` is the ONLY way to tell which lane a `transform` tweak targets. Omitting it mislabels the suggestion onto the wrong element. Omit `member` only for lanes that genuinely have none.",
|
|
337
337
|
multiPhase
|
|
338
|
-
? 'A multi-phase replace suggestion ALSO carries a `patches` array
|
|
338
|
+
? 'A multi-phase replace suggestion ALSO carries a `patches` array. Put timing in phase-level entries (`property:"all"`, duration/easing), and put scale/blur in lane-level entries (`property:"transform"`/`"filter"` plus the lane `member` and `varName` from input timings). In each `patch`/`patches` entry include only changed fields (durationMs, delayMs, easing, scale, blur — plus `member` copied from input lane and `varName` when present); `property` must match an input property or "all".'
|
|
339
339
|
: 'In each `patch` include only the changed fields (durationMs, delayMs, easing, scale, blur — plus `member` copied from the input lane, and `varName` if the input lane had one); `property` must match an input property or "all". If nothing should change, return an empty suggestions array.',
|
|
340
340
|
);
|
|
341
341
|
return lines.join("\n");
|