@creator-notes/cnotes 0.35.0 → 0.35.1
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/README.md +8 -0
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +7 -2
- package/dist/commands/skills.js.map +1 -1
- package/dist/lib/install-skill.d.ts +2 -1
- package/dist/lib/install-skill.d.ts.map +1 -1
- package/dist/lib/install-skill.js +13 -0
- package/dist/lib/install-skill.js.map +1 -1
- package/package.json +1 -1
- package/skills/howto-filmstrips/SKILL.md +214 -0
- package/skills/howto-filmstrips/scripts/inject-highlight.js +198 -0
- package/skills/howto-filmstrips/scripts/soft-spotlight.py +75 -0
package/README.md
CHANGED
|
@@ -222,6 +222,14 @@ The simplest path: run `npx @creator-notes/cnotes@latest init` and accept the "I
|
|
|
222
222
|
|
|
223
223
|
After that, Claude will use `cnotes` whenever you ask about notes, canvases, or workspace tasks — no further setup.
|
|
224
224
|
|
|
225
|
+
Optional filmstrip skills (not auto-installed):
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
cnotes skills list
|
|
229
|
+
cnotes skills install fat-marker-flows # Shape Up sketch journeys
|
|
230
|
+
cnotes skills install howto-filmstrips # live UI screenshot how-tos
|
|
231
|
+
```
|
|
232
|
+
|
|
225
233
|
### Claude Desktop (MCP Server)
|
|
226
234
|
|
|
227
235
|
Add CreatorNotes as a tool server so Claude Desktop can read and write your notes directly.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8F7D"}
|
package/dist/commands/skills.js
CHANGED
|
@@ -23,7 +23,7 @@ function resolveTargets(agentOpt) {
|
|
|
23
23
|
export function registerSkillsCommands(program) {
|
|
24
24
|
const skills = program
|
|
25
25
|
.command("skills")
|
|
26
|
-
.description("Install bundled agent skills (e.g. fat-marker flows) into Claude Code or Codex");
|
|
26
|
+
.description("Install bundled agent skills (e.g. fat-marker flows, how-to filmstrips) into Claude Code or Codex");
|
|
27
27
|
skills
|
|
28
28
|
.command("list")
|
|
29
29
|
.description("List the skills this CLI can install")
|
|
@@ -57,6 +57,7 @@ export function registerSkillsCommands(program) {
|
|
|
57
57
|
.addHelpText("after", `
|
|
58
58
|
Examples:
|
|
59
59
|
$ cnotes skills install fat-marker
|
|
60
|
+
$ cnotes skills install howto-filmstrips
|
|
60
61
|
$ cnotes skills install fat-marker --agent codex
|
|
61
62
|
$ cnotes skills install fat-marker --agent all`)
|
|
62
63
|
.action((name, options) => {
|
|
@@ -82,11 +83,15 @@ Examples:
|
|
|
82
83
|
console.log(`✓ Installed ${skill.label} for ${label} → ${r.destPath}`);
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
|
-
//
|
|
86
|
+
// Filmstrip skills also need an authed workspace to place canvases.
|
|
86
87
|
if (skill.name === "fat-marker-flows") {
|
|
87
88
|
console.log("");
|
|
88
89
|
console.log('Next: cnotes auth login then ask your agent to "fat-marker this flow".');
|
|
89
90
|
}
|
|
91
|
+
if (skill.name === "howto-filmstrips") {
|
|
92
|
+
console.log("");
|
|
93
|
+
console.log('Next: cnotes auth login then ask your agent to "capture a how-to filmstrip of …".');
|
|
94
|
+
}
|
|
90
95
|
}
|
|
91
96
|
catch (error) {
|
|
92
97
|
handleError(error, cfg.json);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,aAAa,EAEb,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC;;;;;GAKG;AACH,SAAS,cAAc,CAAC,QAAiB;IACvC,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,KAAK;YAAE,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,OAAO;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,IAAI,eAAe,CACvB,oBAAoB,QAAQ,+BAA+B,CAC5D,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,MAAM,GAAG,OAAO;SACnB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,aAAa,EAEb,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC;;;;;GAKG;AACH,SAAS,cAAc,CAAC,QAAiB;IACvC,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,KAAK;YAAE,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,OAAO;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,IAAI,eAAe,CACvB,oBAAoB,QAAQ,+BAA+B,CAC5D,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,MAAM,GAAG,OAAO;SACnB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CACV,mGAAmG,CACpG,CAAC;IAEJ,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,sCAAsC,CAAC;SACnD,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9C,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YACb,UAAU,CACR,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACxB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,IAAI,EAAE,CAAC,CAAC,IAAI;aACb,CAAC,CAAC,CACJ,CAAC;YACF,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC,CAAC,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;YAC/D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEL,MAAM;SACH,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,sDAAsD,CAAC;SACnE,MAAM,CACL,iBAAiB,EACjB,0EAA0E,CAC3E;SACA,WAAW,CACV,OAAO,EACP;;;;;iDAK2C,CAC5C;SACA,MAAM,CAAC,CAAC,IAAY,EAAE,OAA2B,EAAE,EAAE;QACpD,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1D,MAAM,IAAI,eAAe,CACvB,kBAAkB,IAAI,iBAAiB,KAAK,GAAG,CAChD,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAEtE,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBACb,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBACzC,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;oBACtB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,2BAA2B,KAAK,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;gBAClF,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACzE,CAAC;YACH,CAAC;YAED,oEAAoE;YACpE,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;YAC3F,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChB,OAAO,CAAC,GAAG,CACT,sFAAsF,CACvF,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -35,7 +35,8 @@ export declare function legacySkillInstalled(target: SkillTarget): boolean;
|
|
|
35
35
|
*
|
|
36
36
|
* Unlike the auto-installed `cnotes` skill (a single SKILL.md), catalog skills
|
|
37
37
|
* can be whole folders — e.g. `fat-marker-flows` ships SKILL.md plus an
|
|
38
|
-
* `examples/` set of reference keyframes
|
|
38
|
+
* `examples/` set of reference keyframes, and `howto-filmstrips` ships
|
|
39
|
+
* SKILL.md plus helper `scripts/` the skill tells the agent to run.
|
|
39
40
|
* The source folder lives at `<package>/skills/<name>/`.
|
|
40
41
|
*/
|
|
41
42
|
export interface CatalogSkill {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-skill.d.ts","sourceRoot":"","sources":["../../src/lib/install-skill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7C,eAAO,MAAM,aAAa,EAAE,WAAW,EAAwB,CAAC;AAEhE,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE5D;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAOD,kEAAkE;AAClE,wBAAgB,mBAAmB,IAAI,MAAM,CAG5C;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,WAAsB,GAAG,MAAM,CAEvE;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAE9D;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,WAAsB,GAAG,OAAO,CAE7E;AAOD,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAEjE;AAkDD
|
|
1
|
+
{"version":3,"file":"install-skill.d.ts","sourceRoot":"","sources":["../../src/lib/install-skill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7C,eAAO,MAAM,aAAa,EAAE,WAAW,EAAwB,CAAC;AAEhE,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE5D;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAOD,kEAAkE;AAClE,wBAAgB,mBAAmB,IAAI,MAAM,CAG5C;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAAC,MAAM,GAAE,WAAsB,GAAG,MAAM,CAEvE;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAE9D;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,WAAsB,GAAG,OAAO,CAE7E;AAOD,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAEjE;AAkDD;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,IAAI,EAAE,OAAO,CAAC;CACf;AAED,eAAO,MAAM,aAAa,EAAE,YAAY,EA+BvC,CAAC;AAEF,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAK3E;AAaD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,kBAAkB,CAexF;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,IAAI,kBAAkB,EAAE,CAc7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,GAAE,WAAsB,GAAG,kBAAkB,CAkB/E"}
|
|
@@ -107,6 +107,19 @@ export const SKILL_CATALOG = [
|
|
|
107
107
|
description: "Storyboard a UI flow as rough Shape Up 'broad-strokes' keyframes and lay them on a canvas as a left-to-right filmstrip.",
|
|
108
108
|
auto: false,
|
|
109
109
|
},
|
|
110
|
+
{
|
|
111
|
+
name: "howto-filmstrips",
|
|
112
|
+
aliases: [
|
|
113
|
+
"howto-filmstrip",
|
|
114
|
+
"how-to-filmstrips",
|
|
115
|
+
"how-to-filmstrip",
|
|
116
|
+
"live-howto",
|
|
117
|
+
"live-how-to",
|
|
118
|
+
],
|
|
119
|
+
label: "How-to filmstrips",
|
|
120
|
+
description: "Capture a live product how-to as screenshot filmstrips (CSS highlight + soft spotlight) and place them on a CreatorNotes canvas.",
|
|
121
|
+
auto: false,
|
|
122
|
+
},
|
|
110
123
|
];
|
|
111
124
|
/** Resolve a CLI-provided name/alias to a catalog skill (case-insensitive). */
|
|
112
125
|
export function resolveCatalogSkill(query) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-skill.js","sourceRoot":"","sources":["../../src/lib/install-skill.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"install-skill.js","sourceRoot":"","sources":["../../src/lib/install-skill.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: howto-filmstrips
|
|
3
|
+
description: >-
|
|
4
|
+
Capture a real product UI how-to as a horizontal filmstrip on a CreatorNotes
|
|
5
|
+
canvas: live CSS highlight on the click target, soft radial spotlight, then
|
|
6
|
+
screenshot → upload → place. Use when the user wants a screenshot storyboard,
|
|
7
|
+
click-path how-to, JTBD walkthrough, multi-path UI guide, or "show me how to
|
|
8
|
+
do X in the app" with accurate click markers (not fat-marker sketches).
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# How-to filmstrips (live UI capture on a canvas)
|
|
12
|
+
|
|
13
|
+
Turn a real product flow into a left-to-right filmstrip of screenshots on a CreatorNotes canvas. Each frame shows the full UI with a clear click (or type) target: **crimson highlight on the real element box** + **soft radial spotlight** dimming the rest.
|
|
14
|
+
|
|
15
|
+
This is the **pixel-accurate sibling** of `fat-marker-flows`. Use fat-marker for proposed / Shape Up sketches; use this skill for “how do I do this in the live product?”
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Design lock (do not invent a new look)
|
|
20
|
+
|
|
21
|
+
| Element | Spec |
|
|
22
|
+
|---------|------|
|
|
23
|
+
| Highlight colour | Classy crimson `#C43036` (outline, soft wash, CLICK/TYPE pill) |
|
|
24
|
+
| Spotlight | Soft **radial** fade, max opacity **~40%** (up to **~55%** on dark forms), long fade (`fade_mult ≈ 5.5`) |
|
|
25
|
+
| Done frame | Green `#2F9E6A` outline + `DONE` pill; lighter spotlight (~30%) |
|
|
26
|
+
| Captions | Canvas **richtext** under the image (same node), not Notes |
|
|
27
|
+
| Titles | Middle dot `·` as separator; **no em dashes** |
|
|
28
|
+
| Layout | One path = one horizontal row; multiple paths = stacked sections |
|
|
29
|
+
| Language | Match the product UI; prefer UK English in captions unless the product is US-only |
|
|
30
|
+
|
|
31
|
+
**Do not** use orange bullseyes, yellow highlighters, cyan brackets, or hard rectangular `box-shadow: 0 0 0 9999px` spotlights. The hard box-shadow gets clipped by parent `overflow` and often never appears in the PNG.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## When to use / not use
|
|
36
|
+
|
|
37
|
+
**Use when:** documenting a live click path, comparing entry points (Path A/B/C), workshop how-tos, JTBD storyboards from a real app.
|
|
38
|
+
|
|
39
|
+
**Do not use when:** the UI does not exist yet (use `fat-marker-flows`), or the user wants a polished Figma mock (use a design tool).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Prerequisites
|
|
44
|
+
|
|
45
|
+
1. Browser automation available (Cursor browser MCP / CDP `Runtime.evaluate` + screenshot).
|
|
46
|
+
2. `cnotes` authenticated with a writable workspace (`cnotes auth status`, `cnotes workspace current`).
|
|
47
|
+
3. This skill folder installed (`cnotes skills install howto-filmstrips`) so scripts resolve under the agent skills dir.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Step 0 — Scope the paths
|
|
52
|
+
|
|
53
|
+
1. Name the job (e.g. “Create a new contact”).
|
|
54
|
+
2. List each **entry path** separately (Path A, Path B…). One path = one row.
|
|
55
|
+
3. For each path, list 4–7 frames: each frame is **one action** (click or type) or a final Done state.
|
|
56
|
+
4. Write captions before capture: `N · Click …` / `N · Type …` / `N · Done · …`.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Step 1 — Inject highlight helpers (before any click)
|
|
61
|
+
|
|
62
|
+
Read `scripts/inject-highlight.js` and evaluate its **entire file contents** in the page via CDP `Runtime.evaluate` (or equivalent). That installs:
|
|
63
|
+
|
|
64
|
+
- `window.__cnHowto.highlight(el, { label: 'CLICK'|'TYPE'|'DONE' })`
|
|
65
|
+
- `window.__cnHowto.clear()`
|
|
66
|
+
- `window.__cnHowto.findExact(text, opts)` — visible, sized matches; prefer menu-row / control size
|
|
67
|
+
|
|
68
|
+
The injector uses a **fixed full-viewport radial overlay** (not element `box-shadow`), so the spotlight survives screenshot and parent clipping.
|
|
69
|
+
|
|
70
|
+
**Calibrate visually:** after first inject, highlight one control and screenshot. Check that the crimson outline hugs the element box (not an inner span), the CLICK pill sits just above it and is legible, and the spotlight is a soft radial fade centred on the control — never a hard-edged rectangle. Adjust opacity only if the product chrome is unusually light or dark.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Step 2 — Capture loop (per frame)
|
|
75
|
+
|
|
76
|
+
For each click/type frame:
|
|
77
|
+
|
|
78
|
+
1. **Find** the target with `__cnHowto.findExact` (exact label text) or a tight selector. Prefer the **largest visible** control that matches (menu row over inner text span).
|
|
79
|
+
2. **Highlight** with the right label (`CLICK` / `TYPE`).
|
|
80
|
+
3. **Screenshot** the viewport → save as `A1.png`, `A2.png`, …
|
|
81
|
+
4. **Clear** highlight.
|
|
82
|
+
5. **Perform** the action (click / type), wait for UI settle.
|
|
83
|
+
6. Repeat.
|
|
84
|
+
|
|
85
|
+
For the **Done** frame: land on the success state, highlight the result (e.g. contact name) with `{ label: 'DONE' }`, screenshot, clear.
|
|
86
|
+
|
|
87
|
+
### Accuracy rules
|
|
88
|
+
|
|
89
|
+
- Capture highlights **live** from element `getBoundingClientRect`. Do not guess pixel rings on old PNGs.
|
|
90
|
+
- If a frame teaches picking an option that is already selected, switch to another option first, then highlight the target and shoot — so the frame shows the switch, not a no-op.
|
|
91
|
+
- Retina / DPR: screenshots are often 2× CSS pixels. The injector uses CSS pixels for the overlay; if you fall back to `soft-spotlight.py`, pass `--dpr` (usually `2`).
|
|
92
|
+
|
|
93
|
+
### Fallback if the in-page spotlight is weak
|
|
94
|
+
|
|
95
|
+
On very dark UIs the radial overlay can look faint. After capture, run:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
python3 "<skillDir>/scripts/soft-spotlight.py" \
|
|
99
|
+
--in A3.png --out A3.png \
|
|
100
|
+
--cx 276 --cy 219 --dpr 2 \
|
|
101
|
+
--opacity 0.55
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`--cx/--cy` are **CSS-pixel** centres from `getBoundingClientRect` (the script multiplies by `--dpr`).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Step 3 — Upload and place on the canvas
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
WS=<workspaceId>
|
|
112
|
+
CANVAS=<canvasId>
|
|
113
|
+
OUT=/tmp/howto-filmstrip
|
|
114
|
+
mkdir -p "$OUT"
|
|
115
|
+
|
|
116
|
+
cnotes operations begin -w "$WS" --prompt "How-to filmstrip: <job>" --json >/dev/null
|
|
117
|
+
|
|
118
|
+
# Upload in frame order; collect storageIds
|
|
119
|
+
> "$OUT/ids.txt"
|
|
120
|
+
for f in A1 A2 A3 A4 A5 A6; do
|
|
121
|
+
sid=$(cnotes files upload "$OUT/$f.png" -w "$WS" --json \
|
|
122
|
+
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('storageId') or d.get('id') or '')")
|
|
123
|
+
echo "$sid" >> "$OUT/ids.txt"
|
|
124
|
+
done
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Build a place spec: header + one **section per path**, each with a **grid** of richtext cells (image markdown + caption). Prefer `columns: N` matching frame count (e.g. 6). Use `size: "medium"` for frames.
|
|
128
|
+
|
|
129
|
+
Image URL form inside richtext:
|
|
130
|
+
|
|
131
|
+
```markdown
|
|
132
|
+

|
|
133
|
+
|
|
134
|
+
1 · Click Create new +
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Clear existing storyboard nodes if rebuilding the same canvas:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
cnotes canvas get "$CANVAS" -w "$WS" --json | python3 -c "
|
|
141
|
+
import sys,json
|
|
142
|
+
d=json.load(sys.stdin)
|
|
143
|
+
ids=[n['id'] for n in (d.get('allNodes') or [])]
|
|
144
|
+
for s in d.get('sectionNodes') or []:
|
|
145
|
+
if s['id'] not in ids: ids.append(s['id'])
|
|
146
|
+
open('/tmp/howto-remove.json','w').write(json.dumps(ids))
|
|
147
|
+
"
|
|
148
|
+
cnotes canvas agent-run wrap --canvas "$CANVAS" --prompt "Clear before how-to rebuild" -- \
|
|
149
|
+
cnotes canvas bulk-remove "$CANVAS" --nodes "$(cat /tmp/howto-remove.json)" -w "$WS" --json
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Place:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
cnotes canvas agent-run wrap --canvas "$CANVAS" --prompt "Place how-to filmstrip" -- \
|
|
156
|
+
cnotes canvas place "$CANVAS" --spec "$OUT/unified.json" -w "$WS" --json
|
|
157
|
+
cnotes operations end -w "$WS" --json
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Multi-path layout sketch
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"root": {
|
|
165
|
+
"kind": "stack",
|
|
166
|
+
"axis": "vertical",
|
|
167
|
+
"gap": "spacious",
|
|
168
|
+
"align": "start",
|
|
169
|
+
"items": [
|
|
170
|
+
{ "kind": "item", "type": "richtext", "size": "large",
|
|
171
|
+
"content": "# How to …\n\nSame job, several entry points. Read each row left to right." },
|
|
172
|
+
{
|
|
173
|
+
"kind": "section",
|
|
174
|
+
"name": "Path A · …",
|
|
175
|
+
"child": {
|
|
176
|
+
"kind": "stack",
|
|
177
|
+
"axis": "vertical",
|
|
178
|
+
"gap": "tight",
|
|
179
|
+
"align": "start",
|
|
180
|
+
"items": [
|
|
181
|
+
{ "kind": "item", "type": "richtext", "size": "small",
|
|
182
|
+
"content": "**Path A** · …" },
|
|
183
|
+
{ "kind": "grid", "columns": 6, "gap": "medium", "items": [/* frames */] }
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Gotchas (learned the hard way)
|
|
195
|
+
|
|
196
|
+
- **`box-shadow: 9999px` spotlights get clipped** and vanish from screenshots. Always use the fixed radial overlay from `inject-highlight.js`.
|
|
197
|
+
- **Wrong element:** loose regexes match sibling labels (`/save/i` also matches “Save and close”). Prefer exact text + min width/height + prefer larger hit targets.
|
|
198
|
+
- **CLICK pill vs outline mismatch:** place the pill from the highlighted element’s box after layout; re-highlight after fixing helpers if the first shot drifted.
|
|
199
|
+
- **Dark forms:** bump spotlight opacity toward 0.55 so the fade reads.
|
|
200
|
+
- **DPR:** post-process centres must be CSS × devicePixelRatio.
|
|
201
|
+
- **`place` appends below existing content** unless you bulk-remove first when rebuilding.
|
|
202
|
+
- **Verify images by node count / positions**, not by grepping `![` in stored content (TipTap converts markdown images).
|
|
203
|
+
- **Do not commit secrets** from the product under test; use throwaway trial data in screenshots.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Pairing with fat-marker-flows
|
|
208
|
+
|
|
209
|
+
| Skill | Fidelity | Source |
|
|
210
|
+
|-------|----------|--------|
|
|
211
|
+
| `fat-marker-flows` | Rough Shape Up sketches | Image model |
|
|
212
|
+
| `howto-filmstrips` | Real product UI | Browser capture + CSS |
|
|
213
|
+
|
|
214
|
+
Same canvas can hold a fat-marker “proposed” row and a how-to “as shipped” row — keep the visual language of each skill intact so readers never confuse sketch with screenshot.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How-to filmstrip highlight helpers for the page under test.
|
|
3
|
+
*
|
|
4
|
+
* Evaluate this entire file in the page (CDP Runtime.evaluate / browser console).
|
|
5
|
+
* Then call:
|
|
6
|
+
* __cnHowto.highlight(el, { label: 'CLICK' | 'TYPE' | 'DONE' })
|
|
7
|
+
* __cnHowto.clear()
|
|
8
|
+
* __cnHowto.findExact('Contact', { minW: 100, minH: 36, preferX: 1100 })
|
|
9
|
+
*
|
|
10
|
+
* Uses a fixed full-viewport radial overlay so the spotlight is not clipped by
|
|
11
|
+
* parent overflow (unlike element box-shadow: 0 0 0 9999px).
|
|
12
|
+
*
|
|
13
|
+
* Accent colours are intentional for overlays on third-party product UIs
|
|
14
|
+
* (not CreatorNotes app chrome): crimson #C43036, done green #2F9E6A.
|
|
15
|
+
*/
|
|
16
|
+
(() => {
|
|
17
|
+
const CRIMSON = "#C43036";
|
|
18
|
+
const GREEN = "#2F9E6A";
|
|
19
|
+
const LABEL_FG = "#ffffff";
|
|
20
|
+
const LABEL_SHADOW = "0 2px 8px rgba(0,0,0,0.35)";
|
|
21
|
+
const STYLE_ID = "cn-howto-filmstrip-style";
|
|
22
|
+
const OVERLAY_ID = "cn-howto-filmstrip-overlay";
|
|
23
|
+
const LABEL_ID = "cn-howto-filmstrip-label";
|
|
24
|
+
const HL_CLASS = "cn-howto-filmstrip-hl";
|
|
25
|
+
|
|
26
|
+
function ensureStyle() {
|
|
27
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
28
|
+
const s = document.createElement("style");
|
|
29
|
+
s.id = STYLE_ID;
|
|
30
|
+
s.textContent = `
|
|
31
|
+
.${HL_CLASS} {
|
|
32
|
+
outline: 3px solid var(--cn-howto-accent, ${CRIMSON}) !important;
|
|
33
|
+
outline-offset: 3px !important;
|
|
34
|
+
border-radius: 6px !important;
|
|
35
|
+
box-shadow: 0 0 0 6px color-mix(in srgb, var(--cn-howto-accent, ${CRIMSON}) 18%, transparent) !important;
|
|
36
|
+
background-color: color-mix(in srgb, var(--cn-howto-accent, ${CRIMSON}) 12%, transparent) !important;
|
|
37
|
+
position: relative !important;
|
|
38
|
+
z-index: 2147483646 !important;
|
|
39
|
+
}
|
|
40
|
+
#${OVERLAY_ID} {
|
|
41
|
+
position: fixed;
|
|
42
|
+
inset: 0;
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
z-index: 2147483645;
|
|
45
|
+
}
|
|
46
|
+
#${LABEL_ID} {
|
|
47
|
+
position: fixed;
|
|
48
|
+
z-index: 2147483647;
|
|
49
|
+
color: ${LABEL_FG};
|
|
50
|
+
font: 700 11px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
51
|
+
letter-spacing: 0.08em;
|
|
52
|
+
padding: 5px 8px;
|
|
53
|
+
border-radius: 4px;
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
box-shadow: ${LABEL_SHADOW};
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
document.documentElement.appendChild(s);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function clear() {
|
|
62
|
+
document.querySelectorAll("." + HL_CLASS).forEach((el) => {
|
|
63
|
+
el.classList.remove(HL_CLASS);
|
|
64
|
+
el.style.removeProperty("--cn-howto-accent");
|
|
65
|
+
});
|
|
66
|
+
document.getElementById(OVERLAY_ID)?.remove();
|
|
67
|
+
document.getElementById(LABEL_ID)?.remove();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function placeSpotlight(cx, cy, { maxOpacity = 0.4, holeR = 100, fadeMult = 5.5 } = {}) {
|
|
71
|
+
let overlay = document.getElementById(OVERLAY_ID);
|
|
72
|
+
if (!overlay) {
|
|
73
|
+
overlay = document.createElement("div");
|
|
74
|
+
overlay.id = OVERLAY_ID;
|
|
75
|
+
document.documentElement.appendChild(overlay);
|
|
76
|
+
}
|
|
77
|
+
const rampEnd = holeR * fadeMult;
|
|
78
|
+
overlay.style.background = `radial-gradient(
|
|
79
|
+
circle at ${cx}px ${cy}px,
|
|
80
|
+
rgba(0,0,0,0) 0px,
|
|
81
|
+
rgba(0,0,0,0) ${holeR}px,
|
|
82
|
+
rgba(0,0,0,${maxOpacity * 0.35}) ${holeR + (rampEnd - holeR) * 0.35}px,
|
|
83
|
+
rgba(0,0,0,${maxOpacity}) ${rampEnd}px,
|
|
84
|
+
rgba(0,0,0,${maxOpacity}) 100%
|
|
85
|
+
)`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function placeLabel(r, text, accent) {
|
|
89
|
+
document.getElementById(LABEL_ID)?.remove();
|
|
90
|
+
const label = document.createElement("div");
|
|
91
|
+
label.id = LABEL_ID;
|
|
92
|
+
label.textContent = text;
|
|
93
|
+
label.style.background = accent;
|
|
94
|
+
document.documentElement.appendChild(label);
|
|
95
|
+
const lw = label.offsetWidth;
|
|
96
|
+
const lh = label.offsetHeight;
|
|
97
|
+
let left = r.left + (r.width - lw) / 2;
|
|
98
|
+
let top = r.top - lh - 8;
|
|
99
|
+
if (top < 8) top = r.bottom + 8;
|
|
100
|
+
left = Math.max(8, Math.min(left, window.innerWidth - lw - 8));
|
|
101
|
+
label.style.left = left + "px";
|
|
102
|
+
label.style.top = top + "px";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function highlight(el, opts = {}) {
|
|
106
|
+
if (!el) return { ok: false, reason: "no element" };
|
|
107
|
+
ensureStyle();
|
|
108
|
+
clear();
|
|
109
|
+
|
|
110
|
+
const label = (opts.label || "CLICK").toUpperCase();
|
|
111
|
+
const isDone = label === "DONE";
|
|
112
|
+
const accent = isDone ? GREEN : CRIMSON;
|
|
113
|
+
const maxOpacity = opts.maxOpacity ?? (isDone ? 0.3 : 0.4);
|
|
114
|
+
|
|
115
|
+
el.style.setProperty("--cn-howto-accent", accent);
|
|
116
|
+
el.classList.add(HL_CLASS);
|
|
117
|
+
el.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
118
|
+
|
|
119
|
+
const r = el.getBoundingClientRect();
|
|
120
|
+
const cx = r.left + r.width / 2;
|
|
121
|
+
const cy = r.top + r.height / 2;
|
|
122
|
+
const holeR = opts.holeR ?? Math.max(80, Math.max(r.width, r.height) * 0.9);
|
|
123
|
+
|
|
124
|
+
placeSpotlight(cx, cy, { maxOpacity, holeR, fadeMult: opts.fadeMult ?? 5.5 });
|
|
125
|
+
placeLabel(r, label, accent);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
ok: true,
|
|
129
|
+
tag: el.tagName,
|
|
130
|
+
text: (el.getAttribute("aria-label") || el.textContent || "")
|
|
131
|
+
.replace(/\s+/g, " ")
|
|
132
|
+
.trim()
|
|
133
|
+
.slice(0, 80),
|
|
134
|
+
box: { x: r.x, y: r.y, w: r.width, h: r.height },
|
|
135
|
+
center: { x: cx, y: cy },
|
|
136
|
+
label,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function findExact(exact, opts = {}) {
|
|
141
|
+
const minW = opts.minW ?? 20;
|
|
142
|
+
const minH = opts.minH ?? 20;
|
|
143
|
+
const maxH = opts.maxH ?? 120;
|
|
144
|
+
const selectors =
|
|
145
|
+
'button, a, [role="button"], [role="menuitem"], [role="tab"], [role="radio"], label, input, div, span, li';
|
|
146
|
+
|
|
147
|
+
const candidates = [...document.querySelectorAll(selectors)]
|
|
148
|
+
.map((el) => {
|
|
149
|
+
const r = el.getBoundingClientRect();
|
|
150
|
+
const text = (el.getAttribute("aria-label") || el.textContent || "")
|
|
151
|
+
.replace(/\s+/g, " ")
|
|
152
|
+
.trim();
|
|
153
|
+
const style = getComputedStyle(el);
|
|
154
|
+
return {
|
|
155
|
+
el,
|
|
156
|
+
text,
|
|
157
|
+
r,
|
|
158
|
+
area: r.width * r.height,
|
|
159
|
+
visible:
|
|
160
|
+
r.width >= minW &&
|
|
161
|
+
r.height >= minH &&
|
|
162
|
+
r.height <= maxH &&
|
|
163
|
+
style.visibility !== "hidden" &&
|
|
164
|
+
style.display !== "none",
|
|
165
|
+
};
|
|
166
|
+
})
|
|
167
|
+
.filter((c) => c.text === exact && c.visible);
|
|
168
|
+
|
|
169
|
+
if (!candidates.length) return null;
|
|
170
|
+
|
|
171
|
+
candidates.sort((a, b) => {
|
|
172
|
+
let scoreA = a.area;
|
|
173
|
+
let scoreB = b.area;
|
|
174
|
+
if (opts.preferLarge !== false) {
|
|
175
|
+
scoreA = -a.area;
|
|
176
|
+
scoreB = -b.area;
|
|
177
|
+
}
|
|
178
|
+
if (opts.preferX != null) {
|
|
179
|
+
scoreA += Math.abs(a.r.x - opts.preferX) * 8;
|
|
180
|
+
scoreB += Math.abs(b.r.x - opts.preferX) * 8;
|
|
181
|
+
}
|
|
182
|
+
if (opts.preferY != null) {
|
|
183
|
+
scoreA += Math.abs(a.r.y - opts.preferY) * 8;
|
|
184
|
+
scoreB += Math.abs(b.r.y - opts.preferY) * 8;
|
|
185
|
+
}
|
|
186
|
+
return scoreA - scoreB;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return candidates[0].el;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
window.__cnHowto = { highlight, clear, findExact, ensureStyle };
|
|
193
|
+
window.__cnHighlight = (el, opts) => highlight(el, opts);
|
|
194
|
+
window.__cnClearHighlight = clear;
|
|
195
|
+
window.__cnFindExact = findExact;
|
|
196
|
+
|
|
197
|
+
return { ok: true, api: ["highlight", "clear", "findExact"] };
|
|
198
|
+
})();
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Soft radial spotlight post-process for how-to filmstrip frames.
|
|
3
|
+
|
|
4
|
+
Use when the in-page CSS overlay was weak or missing. Centres are CSS pixels
|
|
5
|
+
from getBoundingClientRect; pass --dpr for retina screenshots (often 2).
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
python3 soft-spotlight.py --in A3.png --out A3.png --cx 276 --cy 219 --dpr 2 --opacity 0.55
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
from PIL import Image
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def soft_spotlight(
|
|
21
|
+
im: Image.Image,
|
|
22
|
+
cx: float,
|
|
23
|
+
cy: float,
|
|
24
|
+
hole_r: float = 180,
|
|
25
|
+
max_opacity: float = 0.4,
|
|
26
|
+
fade_mult: float = 5.5,
|
|
27
|
+
) -> Image.Image:
|
|
28
|
+
w, h = im.size
|
|
29
|
+
ys = np.arange(h)[:, None]
|
|
30
|
+
xs = np.arange(w)[None, :]
|
|
31
|
+
dist = np.sqrt((xs - cx) ** 2 + (ys - cy) ** 2)
|
|
32
|
+
ramp_end = hole_r * fade_mult
|
|
33
|
+
t = np.clip((dist - hole_r) / max(ramp_end - hole_r, 1), 0, 1)
|
|
34
|
+
t = t * t * (3 - 2 * t) # smoothstep
|
|
35
|
+
alpha = (t * max_opacity * 255).astype(np.uint8)
|
|
36
|
+
overlay = np.zeros((h, w, 4), dtype=np.uint8)
|
|
37
|
+
overlay[..., 3] = alpha
|
|
38
|
+
base = im.convert("RGBA")
|
|
39
|
+
return Image.alpha_composite(base, Image.fromarray(overlay, "RGBA"))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def main() -> None:
|
|
43
|
+
p = argparse.ArgumentParser(description=__doc__)
|
|
44
|
+
p.add_argument("--in", dest="src", required=True, help="Input PNG")
|
|
45
|
+
p.add_argument("--out", dest="dst", required=True, help="Output PNG")
|
|
46
|
+
p.add_argument("--cx", type=float, required=True, help="Centre X in CSS pixels")
|
|
47
|
+
p.add_argument("--cy", type=float, required=True, help="Centre Y in CSS pixels")
|
|
48
|
+
p.add_argument("--dpr", type=float, default=1.0, help="Device pixel ratio (default 1)")
|
|
49
|
+
p.add_argument("--hole", type=float, default=None, help="Clear hole radius in device pixels")
|
|
50
|
+
p.add_argument("--opacity", type=float, default=0.4, help="Max dim opacity 0–1")
|
|
51
|
+
p.add_argument("--fade-mult", type=float, default=5.5, help="Fade length as multiple of hole")
|
|
52
|
+
args = p.parse_args()
|
|
53
|
+
|
|
54
|
+
src = Path(args.src)
|
|
55
|
+
dst = Path(args.dst)
|
|
56
|
+
im = Image.open(src)
|
|
57
|
+
cx = args.cx * args.dpr
|
|
58
|
+
cy = args.cy * args.dpr
|
|
59
|
+
hole = args.hole if args.hole is not None else max(160.0, 90.0 * args.dpr)
|
|
60
|
+
|
|
61
|
+
out = soft_spotlight(
|
|
62
|
+
im,
|
|
63
|
+
cx,
|
|
64
|
+
cy,
|
|
65
|
+
hole_r=hole,
|
|
66
|
+
max_opacity=args.opacity,
|
|
67
|
+
fade_mult=args.fade_mult,
|
|
68
|
+
)
|
|
69
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
70
|
+
out.convert("RGB").save(dst, quality=92)
|
|
71
|
+
print(f"wrote {dst} center=({cx:.0f},{cy:.0f}) hole={hole:.0f} opacity={args.opacity}")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
main()
|