@erclx/canon 5.76.0 → 5.78.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/auto-ship/references/ui-checklist.md +9 -1
  4. package/claude/skills/ci-workflow/REQUIREMENT.md +8 -2
  5. package/claude/skills/ci-workflow/SKILL.md +3 -0
  6. package/claude/skills/code-craft/REQUIREMENT.md +1 -1
  7. package/claude/skills/code-craft/SKILL.md +7 -0
  8. package/claude/skills/code-craft/references/adopted.md +8 -0
  9. package/claude/skills/pr-evidence/SKILL.md +6 -1
  10. package/claude/skills/pr-evidence/references/evidence.md +1 -0
  11. package/claude/skills/pr-evidence/references/reel.md +9 -1
  12. package/claude/skills/review-craft/references/ui.md +13 -1
  13. package/claude/skills/review-pr/references/body-variants.md +2 -0
  14. package/claude/skills/review-pr/references/close-out.md +2 -0
  15. package/claude/skills/review-pr/references/post.md +1 -0
  16. package/claude/skills/review-ui/REQUIREMENT.md +1 -0
  17. package/claude/skills/review-ui/SKILL.md +2 -2
  18. package/claude/skills/review-ui/references/driving.md +32 -4
  19. package/claude/skills/review-ui/references/post.md +6 -2
  20. package/claude/skills/role-orchestrator/SKILL.md +2 -2
  21. package/claude/skills/role-orchestrator/references/orchestrator-output.md +24 -1
  22. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +3 -2
  23. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +35 -4
  24. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +1 -1
  25. package/claude/skills/role-worker/SKILL.md +1 -0
  26. package/claude/skills/test-craft/SKILL.md +1 -0
  27. package/claude/skills/ui-checklist/REQUIREMENT.md +1 -1
  28. package/claude/skills/ui-checklist/SKILL.md +2 -1
  29. package/claude/skills/ui-craft/references/capture.md +16 -0
  30. package/claude/skills/ui-film/REQUIREMENT.md +2 -2
  31. package/claude/skills/ui-film/SKILL.md +6 -1
  32. package/claude/skills/ui-film/references/compose-craft.md +68 -11
  33. package/claude/skills/ui-film/references/config.md +2 -2
  34. package/claude/skills/ui-film/references/handoff.md +1 -1
  35. package/claude/skills/ui-film/references/harness.md +71 -0
  36. package/claude/skills/ui-film/references/take-craft.md +42 -17
  37. package/docs/agents/targets.md +3 -1
  38. package/docs/workflow/operating-model.md +6 -5
  39. package/docs/workflow/visual-design-workflow.md +2 -1
  40. package/governance/ledger/skills/code-craft/SKILL.md +9 -0
  41. package/governance/ledger/skills/test-craft/SKILL.md +1 -0
  42. package/governance/ledger/skills/ui-craft/capture.md +18 -5
  43. package/package.json +5 -4
  44. package/src/commands/pr.ts +117 -31
  45. package/src/commands/take.ts +12 -1
  46. package/src/commands/targets.ts +11 -1
  47. package/src/design/components.ts +5 -107
  48. package/src/design/favicon.ts +21 -17
  49. package/src/design/render.ts +9 -27
  50. package/src/design/template.ts +42 -0
  51. package/src/design/templates/favicon.svg +17 -0
  52. package/src/design/templates/hand-drawn-figure.css +54 -0
  53. package/src/design/templates/preview.html +27 -0
  54. package/src/design/templates/scrollbar.css +29 -0
  55. package/src/design/templates/status.css +24 -0
  56. package/src/gate/embedded.ts +400 -0
  57. package/src/gate/stages.ts +8 -0
  58. package/src/pr/evidence.ts +43 -4
  59. package/src/pr/frames.ts +1 -6
  60. package/src/pr/lift.ts +77 -9
  61. package/src/pr/rest.ts +2 -0
  62. package/src/pr/review-scope.ts +28 -0
  63. package/src/pr/review-state.ts +5 -5
  64. package/src/pr/waiver.ts +45 -0
  65. package/src/take/camera.ts +337 -208
  66. package/src/take/film.ts +7 -1
  67. package/src/take/log.ts +43 -2
  68. package/src/take/perform.ts +85 -13
  69. package/src/take/plan.ts +26 -5
  70. package/src/take/reel.ts +30 -5
  71. package/src/take/screencast.ts +110 -3
  72. package/src/take/stepper.ts +24 -4
  73. package/src/targets/registry.ts +99 -14
  74. package/src/targets/resolve.ts +3 -1
  75. package/tooling/astro/configs/card.config.mjs +4 -0
  76. package/tooling/astro/configs/scripts/check-card-exclusion.sh +7 -2
  77. package/tooling/astro/reference.md +2 -1
  78. package/tooling/web/configs/.github/workflows/readme-screenshot.yml +3 -1
  79. package/tooling/web/configs/.github/workflows/verify.yml +5 -2
  80. package/tooling/web/configs/scripts/install-playwright-deps.sh +52 -0
  81. package/tooling/web/reference.md +5 -0
  82. package/src/commands/fixtures/gh.sh +0 -64
  83. package/src/take/fixtures/busy.html +0 -107
  84. package/src/take/fixtures/fade.html +0 -49
  85. package/src/take/fixtures/fetch.html +0 -38
  86. package/src/take/fixtures/input.html +0 -138
  87. package/src/take/zoom/NOTICE.md +0 -45
  88. package/src/take/zoom/math-utils.ts +0 -69
  89. package/src/take/zoom/region-utils.ts +0 -55
  90. package/src/take/zoom/spring.ts +0 -133
@@ -1,138 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <title>Input</title>
6
- <!--
7
- One target per input a take performs, each posting what the page saw to
8
- /report with a sequence number, so a test reads the inputs in the order
9
- the page received them after the take has closed the browser.
10
-
11
- - #handle follows a pointer-event drag and reports where it dropped and
12
- how many of its moves carried the held button
13
- - #frame reports each dblclick
14
- - #layer reports pointerdown, pointerup, and click with the Shift flag
15
- - #field takes focus for key steps, and every keyup reports its value
16
- -->
17
- <style>
18
- body {
19
- margin: 0;
20
- background: #f4f4f4;
21
- font: 24px sans-serif;
22
- }
23
-
24
- #handle {
25
- position: absolute;
26
- left: 200px;
27
- top: 200px;
28
- width: 80px;
29
- height: 80px;
30
- /* Neutral, so the reel's blue ring reads over it at any alpha. */
31
- background: #444;
32
- touch-action: none;
33
- }
34
-
35
- #lane {
36
- position: absolute;
37
- left: 700px;
38
- top: 160px;
39
- width: 300px;
40
- height: 160px;
41
- border: 2px dashed #555;
42
- box-sizing: border-box;
43
- }
44
-
45
- #frame,
46
- #layer {
47
- position: absolute;
48
- top: 500px;
49
- width: 200px;
50
- height: 100px;
51
- background: #ddd;
52
- user-select: none;
53
- }
54
-
55
- #frame {
56
- left: 200px;
57
- }
58
-
59
- #layer {
60
- left: 700px;
61
- }
62
-
63
- #field {
64
- position: absolute;
65
- left: 200px;
66
- top: 750px;
67
- width: 400px;
68
- height: 48px;
69
- font: inherit;
70
- }
71
- </style>
72
- </head>
73
- <body>
74
- <div id="lane"></div>
75
- <div id="handle"></div>
76
- <div id="frame">Frame</div>
77
- <div id="layer">Layer</div>
78
- <input id="field" />
79
- <script>
80
- let seq = 0
81
- const report = (entry) =>
82
- fetch('/report', {
83
- method: 'POST',
84
- body: JSON.stringify({ seq: (seq += 1), ...entry }),
85
- keepalive: true,
86
- })
87
-
88
- const handle = document.getElementById('handle')
89
- const lane = document.getElementById('lane')
90
- let drag = null
91
- handle.addEventListener('pointerdown', (event) => {
92
- handle.setPointerCapture(event.pointerId)
93
- drag = { held: 0, hover: 0 }
94
- })
95
- handle.addEventListener('pointermove', (event) => {
96
- if (!drag) return
97
- if (event.buttons === 1) drag.held += 1
98
- else drag.hover += 1
99
- handle.style.left = `${event.clientX - 40}px`
100
- handle.style.top = `${event.clientY - 40}px`
101
- })
102
- handle.addEventListener('pointerup', (event) => {
103
- if (!drag) return
104
- const box = lane.getBoundingClientRect()
105
- const onTarget =
106
- event.clientX >= box.left &&
107
- event.clientX <= box.right &&
108
- event.clientY >= box.top &&
109
- event.clientY <= box.bottom
110
- report({ type: 'drop', ...drag, onTarget, altKey: event.altKey })
111
- drag = null
112
- })
113
-
114
- document
115
- .getElementById('frame')
116
- .addEventListener('dblclick', () => report({ type: 'dblclick' }))
117
-
118
- const layer = document.getElementById('layer')
119
- for (const type of ['pointerdown', 'pointerup', 'click']) {
120
- layer.addEventListener(type, (event) =>
121
- report({ type, shiftKey: event.shiftKey }),
122
- )
123
- }
124
-
125
- const field = document.getElementById('field')
126
- document.addEventListener('keydown', (event) =>
127
- report({
128
- type: 'keydown',
129
- key: event.key,
130
- ctrlKey: event.ctrlKey,
131
- }),
132
- )
133
- document.addEventListener('keyup', (event) =>
134
- report({ type: 'keyup', key: event.key, value: field.value }),
135
- )
136
- </script>
137
- </body>
138
- </html>
@@ -1,45 +0,0 @@
1
- # Vendored zoom notice
2
-
3
- The files in this folder carry the zoom timing of [OpenScreen](https://github.com/siddharthvaddem/openscreen) at commit `ca8104c279da0d4b4481ec992ff103949e22c772`, under the MIT license below.
4
-
5
- ## What came from where
6
-
7
- | File | Source in OpenScreen, under `src/components/video-editor/videoPlayback/` |
8
- | ----------------- | -------------------------------------------------------------------------------------------------------- |
9
- | `math-utils.ts` | `mathUtils.ts` |
10
- | `region-utils.ts` | `zoomRegionUtils.ts`, with `TRANSITION_WINDOW_MS` and `ZOOM_IN_TRANSITION_WINDOW_MS` from `constants.ts` |
11
- | `spring.ts` | `motionSmoothing.ts` and `zoomSpring.ts` |
12
-
13
- ## What changed
14
-
15
- - The file names are kebab-case, as this repository names every TypeScript file, and the code is reformatted to its style
16
- - `math-utils.ts` keeps `clamp01`, `cubicBezier`, and `easeOutScreenStudio`, and drops the easings nothing here calls
17
- - `region-utils.ts` keeps `computeRegionStrength`, the connected-pan easing, and the window and gap constants. It drops the dominant-region search, its cache, the 3D rotation, and the cursor-follow focus, since the camera here aims at clicks and holds its focus by its own rule.
18
- - The zoom-out window is 700 ms rather than 1015.05 ms, and the connected pan runs 600 ms rather than 1000 ms, both on the operator's eye in groundwork track `193-ui-record`. <!-- canon-keep-retired --> The zoom-in window keeps OpenScreen's 1522.575 ms.
19
- - `spring.ts` keeps the zoom spring's stiffness 320, damping 40, mass 0.92, its rest thresholds, the delta clamp, and the overshoot clamp from `stepAxis`. OpenScreen steps that spring through the `motion` package, and this solves it in closed form instead, so no dependency comes with it.
20
-
21
- ## License
22
-
23
- ```plaintext
24
- MIT License
25
-
26
- Copyright (c) 2025 Siddharth Vaddem
27
-
28
- Permission is hereby granted, free of charge, to any person obtaining a copy
29
- of this software and associated documentation files (the "Software"), to deal
30
- in the Software without restriction, including without limitation the rights
31
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
- copies of the Software, and to permit persons to whom the Software is
33
- furnished to do so, subject to the following conditions:
34
-
35
- The above copyright notice and this permission notice shall be included in all
36
- copies or substantial portions of the Software.
37
-
38
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44
- SOFTWARE.
45
- ```
@@ -1,69 +0,0 @@
1
- // Vendored from OpenScreen at ca8104c, MIT. See NOTICE.md beside this file.
2
- // Source: src/components/video-editor/videoPlayback/mathUtils.ts
3
-
4
- export function clamp01(value: number) {
5
- return Math.max(0, Math.min(1, value))
6
- }
7
-
8
- function sampleCubicBezier(a1: number, a2: number, t: number) {
9
- const oneMinusT = 1 - t
10
- return (
11
- 3 * a1 * oneMinusT * oneMinusT * t + 3 * a2 * oneMinusT * t * t + t * t * t
12
- )
13
- }
14
-
15
- function sampleCubicBezierDerivative(a1: number, a2: number, t: number) {
16
- const oneMinusT = 1 - t
17
- return (
18
- 3 * a1 * oneMinusT * oneMinusT +
19
- 6 * (a2 - a1) * oneMinusT * t +
20
- 3 * (1 - a2) * t * t
21
- )
22
- }
23
-
24
- export function cubicBezier(
25
- x1: number,
26
- y1: number,
27
- x2: number,
28
- y2: number,
29
- t: number,
30
- ) {
31
- const targetX = clamp01(t)
32
- let solvedT = targetX
33
-
34
- for (let i = 0; i < 8; i += 1) {
35
- const currentX = sampleCubicBezier(x1, x2, solvedT) - targetX
36
- const currentDerivative = sampleCubicBezierDerivative(x1, x2, solvedT)
37
-
38
- if (Math.abs(currentX) < 1e-6 || Math.abs(currentDerivative) < 1e-6) {
39
- break
40
- }
41
-
42
- solvedT -= currentX / currentDerivative
43
- }
44
-
45
- let lower = 0
46
- let upper = 1
47
- solvedT = clamp01(solvedT)
48
-
49
- for (let i = 0; i < 10; i += 1) {
50
- const currentX = sampleCubicBezier(x1, x2, solvedT)
51
- if (Math.abs(currentX - targetX) < 1e-6) {
52
- break
53
- }
54
-
55
- if (currentX < targetX) {
56
- lower = solvedT
57
- } else {
58
- upper = solvedT
59
- }
60
-
61
- solvedT = (lower + upper) / 2
62
- }
63
-
64
- return sampleCubicBezier(y1, y2, solvedT)
65
- }
66
-
67
- export function easeOutScreenStudio(t: number) {
68
- return cubicBezier(0.16, 1, 0.3, 1, t)
69
- }
@@ -1,55 +0,0 @@
1
- // Vendored from OpenScreen at ca8104c, MIT. See NOTICE.md beside this file.
2
- // Source: src/components/video-editor/videoPlayback/zoomRegionUtils.ts and the
3
- // two window constants from constants.ts. The zoom-out window and the chained
4
- // pan's duration carry the operator's tuning, and NOTICE.md lists both.
5
-
6
- import {
7
- clamp01,
8
- cubicBezier,
9
- easeOutScreenStudio,
10
- } from '@/take/zoom/math-utils'
11
-
12
- /** OpenScreen's 1015.05 ms, shortened to 700 ms for a quicker zoom-out. */
13
- export const TRANSITION_WINDOW_MS = 700
14
- /** OpenScreen's zoom-in window, 1.5 times its original 1015.05 ms window. */
15
- export const ZOOM_IN_TRANSITION_WINDOW_MS = 1015.05 * 1.5
16
-
17
- export const CHAINED_ZOOM_PAN_GAP_MS = 1500
18
- /** OpenScreen's 1000 ms, shortened to 600 ms. */
19
- export const CONNECTED_ZOOM_PAN_DURATION_MS = 600
20
- export const ZOOM_IN_OVERLAP_MS = 500
21
-
22
- export interface ZoomRegion {
23
- startMs: number
24
- endMs: number
25
- }
26
-
27
- export function lerp(start: number, end: number, amount: number) {
28
- return start + (end - start) * amount
29
- }
30
-
31
- export function easeConnectedPan(value: number) {
32
- return cubicBezier(0.1, 0.0, 0.2, 1.0, value)
33
- }
34
-
35
- export function computeRegionStrength(region: ZoomRegion, timeMs: number) {
36
- const zoomInEnd = region.startMs + ZOOM_IN_OVERLAP_MS
37
- const leadInStart = zoomInEnd - ZOOM_IN_TRANSITION_WINDOW_MS
38
- const leadOutEnd = region.endMs + TRANSITION_WINDOW_MS
39
-
40
- if (timeMs < leadInStart || timeMs > leadOutEnd) {
41
- return 0
42
- }
43
-
44
- if (timeMs < zoomInEnd) {
45
- const progress = (timeMs - leadInStart) / ZOOM_IN_TRANSITION_WINDOW_MS
46
- return easeOutScreenStudio(progress)
47
- }
48
-
49
- if (timeMs <= region.endMs) {
50
- return 1
51
- }
52
-
53
- const progress = clamp01((timeMs - region.endMs) / TRANSITION_WINDOW_MS)
54
- return 1 - easeOutScreenStudio(progress)
55
- }
@@ -1,133 +0,0 @@
1
- // Adapted from OpenScreen at ca8104c, MIT. See NOTICE.md beside this file.
2
- // Source: getZoomSpringConfig, stepSpringValue, and clampDeltaMs in
3
- // src/components/video-editor/videoPlayback/motionSmoothing.ts, and stepAxis in
4
- // zoomSpring.ts. OpenScreen steps its spring through the `motion` package, and
5
- // this solves the same damped spring in closed form instead, so a target
6
- // inherits no dependency for one function.
7
-
8
- export interface SpringState {
9
- value: number
10
- velocity: number
11
- initialized: boolean
12
- }
13
-
14
- export interface SpringConfig {
15
- stiffness: number
16
- damping: number
17
- mass: number
18
- restDelta: number
19
- restSpeed: number
20
- }
21
-
22
- export const ZOOM_SPRING: SpringConfig = {
23
- stiffness: 320,
24
- damping: 40,
25
- mass: 0.92,
26
- restDelta: 0.0005,
27
- restSpeed: 0.015,
28
- }
29
-
30
- export function createSpringState(initialValue = 0): SpringState {
31
- return { value: initialValue, velocity: 0, initialized: false }
32
- }
33
-
34
- export function clampDeltaMs(deltaMs: number, fallbackMs = 1000 / 60) {
35
- if (!Number.isFinite(deltaMs) || deltaMs <= 0) {
36
- return fallbackMs
37
- }
38
-
39
- return Math.min(80, Math.max(1, deltaMs))
40
- }
41
-
42
- /**
43
- * Advances one axis toward `target` by `deltaMs`. The first call snaps to the
44
- * target, a spring at rest stays there, and a step that would cross a moving
45
- * target lands on it with no velocity, which keeps a quick chase from wobbling
46
- * on a reversal.
47
- */
48
- export function stepSpring(
49
- state: SpringState,
50
- target: number,
51
- deltaMs: number,
52
- config: SpringConfig = ZOOM_SPRING,
53
- ): number {
54
- if (!state.initialized || !Number.isFinite(state.value)) {
55
- state.value = target
56
- state.velocity = 0
57
- state.initialized = true
58
- return state.value
59
- }
60
-
61
- if (
62
- Math.abs(target - state.value) <= config.restDelta &&
63
- Math.abs(state.velocity) <= config.restSpeed
64
- ) {
65
- state.value = target
66
- state.velocity = 0
67
- return state.value
68
- }
69
-
70
- const before = state.value
71
- const [offset, velocity] = solve(
72
- state.value - target,
73
- state.velocity,
74
- clampDeltaMs(deltaMs) / 1000,
75
- config,
76
- )
77
- const after = target + offset
78
-
79
- const crossed =
80
- (before <= target && after > target) || (before >= target && after < target)
81
- if (crossed) {
82
- state.value = target
83
- state.velocity = 0
84
- return target
85
- }
86
-
87
- state.value = after
88
- state.velocity = velocity
89
- return after
90
- }
91
-
92
- /**
93
- * The displacement and velocity of a damped spring `seconds` after it sat at
94
- * `x0` from rest length moving at `v0`, for each of the three damping regimes.
95
- */
96
- function solve(
97
- x0: number,
98
- v0: number,
99
- seconds: number,
100
- { stiffness, damping, mass }: SpringConfig,
101
- ): [number, number] {
102
- const omega = Math.sqrt(stiffness / mass)
103
- const zeta = damping / (2 * Math.sqrt(stiffness * mass))
104
- const t = seconds
105
-
106
- if (zeta < 1) {
107
- const omegaD = omega * Math.sqrt(1 - zeta * zeta)
108
- const decay = Math.exp(-zeta * omega * t)
109
- const b = (v0 + zeta * omega * x0) / omegaD
110
- const cos = Math.cos(omegaD * t)
111
- const sin = Math.sin(omegaD * t)
112
- const x = decay * (x0 * cos + b * sin)
113
- const v =
114
- decay *
115
- (-zeta * omega * (x0 * cos + b * sin) + omegaD * (b * cos - x0 * sin))
116
- return [x, v]
117
- }
118
-
119
- if (zeta === 1) {
120
- const decay = Math.exp(-omega * t)
121
- const b = v0 + omega * x0
122
- return [(x0 + b * t) * decay, (b - omega * (x0 + b * t)) * decay]
123
- }
124
-
125
- const root = Math.sqrt(zeta * zeta - 1)
126
- const r1 = -omega * (zeta - root)
127
- const r2 = -omega * (zeta + root)
128
- const c1 = (v0 - r2 * x0) / (r1 - r2)
129
- const c2 = x0 - c1
130
- const e1 = Math.exp(r1 * t)
131
- const e2 = Math.exp(r2 * t)
132
- return [c1 * e1 + c2 * e2, c1 * r1 * e1 + c2 * r2 * e2]
133
- }