@1agh/maude 0.42.0 → 0.43.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 (236) hide show
  1. package/apps/studio/.ai/cache/_stats.json +7 -0
  2. package/apps/studio/acp/bootstrap-brief.ts +12 -2
  3. package/apps/studio/annotations-layer.tsx +1055 -278
  4. package/apps/studio/annotations-model.ts +58 -0
  5. package/apps/studio/api.ts +173 -22
  6. package/apps/studio/bin/_ingest-footage.mjs +386 -0
  7. package/apps/studio/bin/_probe-footage-playwright.mjs +269 -0
  8. package/apps/studio/bin/_video-playwright.mjs +141 -71
  9. package/apps/studio/bin/ingest-footage.sh +27 -0
  10. package/apps/studio/bin/photo-adjust.sh +163 -0
  11. package/apps/studio/bin/photo-bg-remove.sh +160 -0
  12. package/apps/studio/bin/probe-footage.sh +28 -0
  13. package/apps/studio/bin/read-annotations.mjs +125 -2
  14. package/apps/studio/canvas-edit.ts +459 -10
  15. package/apps/studio/canvas-lib.tsx +523 -5
  16. package/apps/studio/canvas-pipeline.ts +65 -7
  17. package/apps/studio/canvas-shell.tsx +156 -16
  18. package/apps/studio/client/app.jsx +451 -34
  19. package/apps/studio/client/export-center.jsx +35 -1
  20. package/apps/studio/client/github.js +4 -0
  21. package/apps/studio/client/panels/GitPanel.jsx +8 -0
  22. package/apps/studio/client/panels/RepoBranchSwitcher.jsx +133 -21
  23. package/apps/studio/client/panels/StickerPicker.jsx +160 -0
  24. package/apps/studio/client/panels/TimelinePanel.jsx +15 -2
  25. package/apps/studio/client/photo-knobs.jsx +437 -0
  26. package/apps/studio/client/styles/3-shell-maude.css +42 -0
  27. package/apps/studio/commands/edit-source-command.ts +31 -4
  28. package/apps/studio/context-menu.tsx +31 -6
  29. package/apps/studio/dist/client.bundle.js +5561 -19
  30. package/apps/studio/dist/comment-mount.js +2 -2
  31. package/apps/studio/dist/runtime/.min-sizes.json +1 -0
  32. package/apps/studio/dist/runtime/@imgly_background-removal.js +5543 -0
  33. package/apps/studio/dist/runtime/pixi-js.js +519 -519
  34. package/apps/studio/dist/styles.css +1 -1
  35. package/apps/studio/dom-selection.ts +25 -0
  36. package/apps/studio/exporters/jobs.ts +47 -5
  37. package/apps/studio/exporters/video.ts +24 -4
  38. package/apps/studio/footage/schema.test.ts +195 -0
  39. package/apps/studio/footage/schema.ts +484 -0
  40. package/apps/studio/footage-store.ts +235 -0
  41. package/apps/studio/fs-watch.ts +10 -0
  42. package/apps/studio/git/endpoints.ts +68 -7
  43. package/apps/studio/git/service.ts +196 -20
  44. package/apps/studio/github/service.ts +67 -0
  45. package/apps/studio/handoff.ts +3 -2
  46. package/apps/studio/http.ts +173 -14
  47. package/apps/studio/input-router.tsx +10 -0
  48. package/apps/studio/inspect.ts +53 -1
  49. package/apps/studio/paths.ts +10 -0
  50. package/apps/studio/photo/filters.ts +285 -0
  51. package/apps/studio/photo/pipeline.ts +607 -0
  52. package/apps/studio/photo/schema.ts +367 -0
  53. package/apps/studio/photo-store.ts +154 -0
  54. package/apps/studio/runtime-bundle.ts +29 -6
  55. package/apps/studio/server.ts +5 -1
  56. package/apps/studio/stickers/figjam-doodle/manifest.json +104 -0
  57. package/apps/studio/stickers/figjam-doodle/slice1.png +0 -0
  58. package/apps/studio/stickers/figjam-doodle/slice10.png +0 -0
  59. package/apps/studio/stickers/figjam-doodle/slice11.png +0 -0
  60. package/apps/studio/stickers/figjam-doodle/slice12.png +0 -0
  61. package/apps/studio/stickers/figjam-doodle/slice13.png +0 -0
  62. package/apps/studio/stickers/figjam-doodle/slice14.png +0 -0
  63. package/apps/studio/stickers/figjam-doodle/slice15.png +0 -0
  64. package/apps/studio/stickers/figjam-doodle/slice16.png +0 -0
  65. package/apps/studio/stickers/figjam-doodle/slice17.png +0 -0
  66. package/apps/studio/stickers/figjam-doodle/slice18.png +0 -0
  67. package/apps/studio/stickers/figjam-doodle/slice19.png +0 -0
  68. package/apps/studio/stickers/figjam-doodle/slice2.png +0 -0
  69. package/apps/studio/stickers/figjam-doodle/slice20.png +0 -0
  70. package/apps/studio/stickers/figjam-doodle/slice21.png +0 -0
  71. package/apps/studio/stickers/figjam-doodle/slice22.png +0 -0
  72. package/apps/studio/stickers/figjam-doodle/slice23.png +0 -0
  73. package/apps/studio/stickers/figjam-doodle/slice24.png +0 -0
  74. package/apps/studio/stickers/figjam-doodle/slice3.png +0 -0
  75. package/apps/studio/stickers/figjam-doodle/slice4.png +0 -0
  76. package/apps/studio/stickers/figjam-doodle/slice5.png +0 -0
  77. package/apps/studio/stickers/figjam-doodle/slice6.png +0 -0
  78. package/apps/studio/stickers/figjam-doodle/slice7.png +0 -0
  79. package/apps/studio/stickers/figjam-doodle/slice8.png +0 -0
  80. package/apps/studio/stickers/figjam-doodle/slice9.png +0 -0
  81. package/apps/studio/stickers/life-style/best.png +0 -0
  82. package/apps/studio/stickers/life-style/come-on.png +0 -0
  83. package/apps/studio/stickers/life-style/cut.png +0 -0
  84. package/apps/studio/stickers/life-style/detox.png +0 -0
  85. package/apps/studio/stickers/life-style/just.png +0 -0
  86. package/apps/studio/stickers/life-style/manifest.json +68 -0
  87. package/apps/studio/stickers/life-style/mirror.png +0 -0
  88. package/apps/studio/stickers/life-style/nice.png +0 -0
  89. package/apps/studio/stickers/life-style/objects.png +0 -0
  90. package/apps/studio/stickers/life-style/ok.png +0 -0
  91. package/apps/studio/stickers/life-style/queen.png +0 -0
  92. package/apps/studio/stickers/life-style/star.png +0 -0
  93. package/apps/studio/stickers/life-style/sun.png +0 -0
  94. package/apps/studio/stickers/life-style/water.png +0 -0
  95. package/apps/studio/stickers/life-style/yeah.png +0 -0
  96. package/apps/studio/stickers/life-style/you-can.png +0 -0
  97. package/apps/studio/stickers/opposing-thoughts/check-the-deets.png +0 -0
  98. package/apps/studio/stickers/opposing-thoughts/cut-it.png +0 -0
  99. package/apps/studio/stickers/opposing-thoughts/dope.png +0 -0
  100. package/apps/studio/stickers/opposing-thoughts/fresh.png +0 -0
  101. package/apps/studio/stickers/opposing-thoughts/hot.png +0 -0
  102. package/apps/studio/stickers/opposing-thoughts/idea.png +0 -0
  103. package/apps/studio/stickers/opposing-thoughts/keep-exploring.png +0 -0
  104. package/apps/studio/stickers/opposing-thoughts/killed-it.png +0 -0
  105. package/apps/studio/stickers/opposing-thoughts/love-it.png +0 -0
  106. package/apps/studio/stickers/opposing-thoughts/manifest.json +88 -0
  107. package/apps/studio/stickers/opposing-thoughts/not-sure.png +0 -0
  108. package/apps/studio/stickers/opposing-thoughts/ok.png +0 -0
  109. package/apps/studio/stickers/opposing-thoughts/pure-gold.png +0 -0
  110. package/apps/studio/stickers/opposing-thoughts/save-for-later.png +0 -0
  111. package/apps/studio/stickers/opposing-thoughts/steal-this.png +0 -0
  112. package/apps/studio/stickers/opposing-thoughts/take-a-peek.png +0 -0
  113. package/apps/studio/stickers/opposing-thoughts/this-or-that.png +0 -0
  114. package/apps/studio/stickers/opposing-thoughts/thoughts.png +0 -0
  115. package/apps/studio/stickers/opposing-thoughts/vibes.png +0 -0
  116. package/apps/studio/stickers/opposing-thoughts/winner.png +0 -0
  117. package/apps/studio/stickers/opposing-thoughts/wip.png +0 -0
  118. package/apps/studio/stickers/project-status/group-100.png +0 -0
  119. package/apps/studio/stickers/project-status/group-101.png +0 -0
  120. package/apps/studio/stickers/project-status/group-102.png +0 -0
  121. package/apps/studio/stickers/project-status/group-103.png +0 -0
  122. package/apps/studio/stickers/project-status/group-104.png +0 -0
  123. package/apps/studio/stickers/project-status/group-105.png +0 -0
  124. package/apps/studio/stickers/project-status/group-106.png +0 -0
  125. package/apps/studio/stickers/project-status/group-107.png +0 -0
  126. package/apps/studio/stickers/project-status/group-108.png +0 -0
  127. package/apps/studio/stickers/project-status/group-109.png +0 -0
  128. package/apps/studio/stickers/project-status/group-110.png +0 -0
  129. package/apps/studio/stickers/project-status/group-111.png +0 -0
  130. package/apps/studio/stickers/project-status/group-112.png +0 -0
  131. package/apps/studio/stickers/project-status/group-113.png +0 -0
  132. package/apps/studio/stickers/project-status/group-114.png +0 -0
  133. package/apps/studio/stickers/project-status/group-115.png +0 -0
  134. package/apps/studio/stickers/project-status/group-117.png +0 -0
  135. package/apps/studio/stickers/project-status/group-118.png +0 -0
  136. package/apps/studio/stickers/project-status/group-119.png +0 -0
  137. package/apps/studio/stickers/project-status/group-120.png +0 -0
  138. package/apps/studio/stickers/project-status/group-121.png +0 -0
  139. package/apps/studio/stickers/project-status/group-122.png +0 -0
  140. package/apps/studio/stickers/project-status/group-41.png +0 -0
  141. package/apps/studio/stickers/project-status/group-42.png +0 -0
  142. package/apps/studio/stickers/project-status/group-43.png +0 -0
  143. package/apps/studio/stickers/project-status/group-44.png +0 -0
  144. package/apps/studio/stickers/project-status/group-45.png +0 -0
  145. package/apps/studio/stickers/project-status/group-46.png +0 -0
  146. package/apps/studio/stickers/project-status/group-47.png +0 -0
  147. package/apps/studio/stickers/project-status/group-48.png +0 -0
  148. package/apps/studio/stickers/project-status/group-49.png +0 -0
  149. package/apps/studio/stickers/project-status/group-50.png +0 -0
  150. package/apps/studio/stickers/project-status/group-51.png +0 -0
  151. package/apps/studio/stickers/project-status/group-52.png +0 -0
  152. package/apps/studio/stickers/project-status/group-53.png +0 -0
  153. package/apps/studio/stickers/project-status/group-54.png +0 -0
  154. package/apps/studio/stickers/project-status/group-55.png +0 -0
  155. package/apps/studio/stickers/project-status/group-56.png +0 -0
  156. package/apps/studio/stickers/project-status/group-57.png +0 -0
  157. package/apps/studio/stickers/project-status/group-58.png +0 -0
  158. package/apps/studio/stickers/project-status/group-59.png +0 -0
  159. package/apps/studio/stickers/project-status/group-60.png +0 -0
  160. package/apps/studio/stickers/project-status/group-61.png +0 -0
  161. package/apps/studio/stickers/project-status/group-62.png +0 -0
  162. package/apps/studio/stickers/project-status/group-63.png +0 -0
  163. package/apps/studio/stickers/project-status/group-64.png +0 -0
  164. package/apps/studio/stickers/project-status/group-65.png +0 -0
  165. package/apps/studio/stickers/project-status/group-66.png +0 -0
  166. package/apps/studio/stickers/project-status/group-67.png +0 -0
  167. package/apps/studio/stickers/project-status/group-68.png +0 -0
  168. package/apps/studio/stickers/project-status/group-69.png +0 -0
  169. package/apps/studio/stickers/project-status/group-70.png +0 -0
  170. package/apps/studio/stickers/project-status/group-71.png +0 -0
  171. package/apps/studio/stickers/project-status/group-72.png +0 -0
  172. package/apps/studio/stickers/project-status/group-73.png +0 -0
  173. package/apps/studio/stickers/project-status/group-74.png +0 -0
  174. package/apps/studio/stickers/project-status/group-75.png +0 -0
  175. package/apps/studio/stickers/project-status/group-76.png +0 -0
  176. package/apps/studio/stickers/project-status/group-77.png +0 -0
  177. package/apps/studio/stickers/project-status/group-78.png +0 -0
  178. package/apps/studio/stickers/project-status/group-79.png +0 -0
  179. package/apps/studio/stickers/project-status/group-80.png +0 -0
  180. package/apps/studio/stickers/project-status/group-81.png +0 -0
  181. package/apps/studio/stickers/project-status/group-82.png +0 -0
  182. package/apps/studio/stickers/project-status/group-83.png +0 -0
  183. package/apps/studio/stickers/project-status/group-84.png +0 -0
  184. package/apps/studio/stickers/project-status/group-85.png +0 -0
  185. package/apps/studio/stickers/project-status/group-86.png +0 -0
  186. package/apps/studio/stickers/project-status/group-87.png +0 -0
  187. package/apps/studio/stickers/project-status/group-88.png +0 -0
  188. package/apps/studio/stickers/project-status/group-89.png +0 -0
  189. package/apps/studio/stickers/project-status/group-90.png +0 -0
  190. package/apps/studio/stickers/project-status/group-91.png +0 -0
  191. package/apps/studio/stickers/project-status/group-92.png +0 -0
  192. package/apps/studio/stickers/project-status/group-93.png +0 -0
  193. package/apps/studio/stickers/project-status/group-94.png +0 -0
  194. package/apps/studio/stickers/project-status/group-96.png +0 -0
  195. package/apps/studio/stickers/project-status/group-97.png +0 -0
  196. package/apps/studio/stickers/project-status/group-98.png +0 -0
  197. package/apps/studio/stickers/project-status/group-99.png +0 -0
  198. package/apps/studio/stickers/project-status/manifest.json +328 -0
  199. package/apps/studio/test/acp-bootstrap-brief.test.ts +11 -0
  200. package/apps/studio/test/acp-commands.test.ts +2 -1
  201. package/apps/studio/test/asset-api.test.ts +3 -3
  202. package/apps/studio/test/canvas-edit.test.ts +17 -6
  203. package/apps/studio/test/canvas-origin-gate.test.ts +13 -0
  204. package/apps/studio/test/dynamic-text-edit.test.ts +162 -0
  205. package/apps/studio/test/edit-source-command.test.ts +23 -0
  206. package/apps/studio/test/element-structural-edit.test.ts +46 -0
  207. package/apps/studio/test/footage-store.test.ts +100 -0
  208. package/apps/studio/test/git-branches.test.ts +97 -0
  209. package/apps/studio/test/github-api.test.ts +56 -1
  210. package/apps/studio/test/input-router.test.ts +33 -0
  211. package/apps/studio/test/inspect-script-syntax.test.ts +53 -0
  212. package/apps/studio/test/photo-canvas-bundle.test.ts +61 -0
  213. package/apps/studio/test/photo-edit-api.test.ts +201 -0
  214. package/apps/studio/test/photo-filters.test.ts +149 -0
  215. package/apps/studio/test/photo-pipeline.test.ts +106 -0
  216. package/apps/studio/test/photo-taxonomy.test.ts +96 -0
  217. package/apps/studio/test/read-annotations.test.ts +164 -0
  218. package/apps/studio/test/shell-importmap.test.ts +49 -0
  219. package/apps/studio/test/text-editability-stamp.test.ts +131 -0
  220. package/apps/studio/test/timeline-parse.test.ts +57 -0
  221. package/apps/studio/test/tool-palette-insert-anchor.test.ts +5 -3
  222. package/apps/studio/test/undo-stack.test.ts +33 -0
  223. package/apps/studio/test/video-asset.test.ts +5 -5
  224. package/apps/studio/test/video-render-bridge.test.ts +23 -1
  225. package/apps/studio/text-caret.ts +239 -0
  226. package/apps/studio/tool-palette.tsx +43 -20
  227. package/apps/studio/undo-stack.ts +94 -2
  228. package/apps/studio/use-annotation-resize.tsx +4 -4
  229. package/apps/studio/use-canvas-media-drop.tsx +38 -1
  230. package/apps/studio/use-selection-set.tsx +21 -0
  231. package/apps/studio/video-comp.tsx +48 -7
  232. package/apps/studio/whats-new.json +53 -0
  233. package/cli/commands/design.mjs +34 -3
  234. package/cli/lib/gitignore-block.mjs +1 -0
  235. package/package.json +10 -10
  236. package/plugins/design/templates/_shell.html +1 -0
@@ -116,6 +116,18 @@ function registry(): Map<string, CompEntry> {
116
116
  return w.__maudeVideoComps;
117
117
  }
118
118
 
119
+ // rca/issue-video-artboard-frame-reset-on-edit — the LAST live-preview frame
120
+ // per comp, hoisted above every remount boundary (module scope, mirrors
121
+ // canvas-lib.tsx's `liveViewport`). A canvas edit (ACP/agent/inspector/text)
122
+ // remounts the canvas subtree (canvas-comment-mount.tsx `key={attempt}`), and
123
+ // video-comp.tsx's own module survives that remount — so a fresh VideoComp
124
+ // mount can read the Timeline's last position here instead of always opening
125
+ // on the static `posterFrame`. A full page load clears it — correct; the
126
+ // shell re-seeds via the `timeline-comps` re-announce (app.jsx) once the new
127
+ // Player registers. Never touched during capture (`hideChrome()` forces the
128
+ // deterministic frame 0 / render-shim frame regardless of this mirror).
129
+ const liveTimelineFrame = new Map<string, number>();
130
+
119
131
  function clamp(n: number, lo: number, hi: number): number {
120
132
  return Math.max(lo, Math.min(hi, n));
121
133
  }
@@ -226,7 +238,7 @@ export interface VideoCompProps extends VideoCompMeta {
226
238
  /** Show the Player's own transport chrome in PREVIEW. Auto-hidden during
227
239
  * capture/export (the `?hide-chrome=1` shell flag). Default true. */
228
240
  controls?: boolean;
229
- /** Loop preview playback. Default true. */
241
+ /** Loop preview playback. Default false — the user opts in via the Timeline. */
230
242
  loop?: boolean;
231
243
  /**
232
244
  * Autoplay in preview. Default: play unless the viewer prefers reduced motion
@@ -281,7 +293,7 @@ export function VideoComp({
281
293
  id,
282
294
  inputProps,
283
295
  controls,
284
- loop = true,
296
+ loop = false,
285
297
  autoPlay,
286
298
  }: VideoCompProps) {
287
299
  const ref = useRef<PlayerRef | null>(null);
@@ -301,9 +313,15 @@ export function VideoComp({
301
313
  // autoplay; capture never autoplays (the shim drives frames). Opens on a
302
314
  // poster frame ~35% in so a paused comp shows content, not an empty frame 0.
303
315
  const play = (autoPlay ?? false) && !capturing;
304
- const posterFrame = capturing
316
+ const maxFrame = Math.max(0, durationInFrames - 1);
317
+ const posterFrame = capturing ? 0 : Math.min(maxFrame, Math.round(durationInFrames * 0.35));
318
+ // rca/issue-video-artboard-frame-reset-on-edit — reopen on the Timeline's
319
+ // last known frame for this comp (survives the remount that tore this
320
+ // instance down), not the fixed poster-frame formula. Falls back to
321
+ // posterFrame on a genuinely first-ever mount (nothing recorded yet).
322
+ const initialFrame = capturing
305
323
  ? 0
306
- : Math.min(Math.max(0, durationInFrames - 1), Math.round(durationInFrames * 0.35));
324
+ : clamp(liveTimelineFrame.get(compId) ?? posterFrame, 0, maxFrame);
307
325
 
308
326
  // Register with the seek bridge for the lifetime of this mount.
309
327
  useEffect(() => {
@@ -353,8 +371,10 @@ export function VideoComp({
353
371
  if (!p) return;
354
372
  try {
355
373
  if (m.dgn === 'timeline-seek' && typeof m.frame === 'number') {
374
+ const f = clamp(Math.round(m.frame), 0, Math.max(0, durationInFrames - 1));
356
375
  p.pause();
357
- p.seekTo(clamp(Math.round(m.frame), 0, Math.max(0, durationInFrames - 1)));
376
+ p.seekTo(f);
377
+ liveTimelineFrame.set(compId, f);
358
378
  } else if (m.dgn === 'timeline-play') {
359
379
  p.play();
360
380
  } else if (m.dgn === 'timeline-pause') {
@@ -382,7 +402,9 @@ export function VideoComp({
382
402
  if (!p) return;
383
403
  const onFrame = () => {
384
404
  try {
385
- postToShell({ dgn: 'timeline-frame', id: compId, frame: p.getCurrentFrame() });
405
+ const f = p.getCurrentFrame();
406
+ liveTimelineFrame.set(compId, f);
407
+ postToShell({ dgn: 'timeline-frame', id: compId, frame: f });
386
408
  } catch {
387
409
  /* ignore */
388
410
  }
@@ -397,6 +419,25 @@ export function VideoComp({
397
419
  };
398
420
  }, [compId]);
399
421
 
422
+ // iframe → shell: with loop off (now the default), the Player stops itself
423
+ // at the last frame — nothing else tells the Timeline panel's Play/Pause
424
+ // button to flip back to Play, so it reads "still playing" forever. Mirror
425
+ // the Player's own `ended` event so the shell can resync (rca/issue-video-
426
+ // artboard-loop-defaults-on).
427
+ useEffect(() => {
428
+ const p = ref.current;
429
+ if (!p) return;
430
+ const onEnded = () => postToShell({ dgn: 'timeline-ended', id: compId });
431
+ p.addEventListener('ended', onEnded);
432
+ return () => {
433
+ try {
434
+ p.removeEventListener('ended', onEnded);
435
+ } catch {
436
+ /* ignore */
437
+ }
438
+ };
439
+ }, [compId]);
440
+
400
441
  const style = useMemo(() => ({ width: '100%', height: '100%', display: 'block' as const }), []);
401
442
 
402
443
  return (
@@ -416,7 +457,7 @@ export function VideoComp({
416
457
  controls={showControls}
417
458
  loop={loopState}
418
459
  autoPlay={play}
419
- initialFrame={posterFrame}
460
+ initialFrame={initialFrame}
420
461
  // Clicking the artboard must NOT toggle playback — it selects elements
421
462
  // for editing (the whole point of a canvas). Play only via the explicit
422
463
  // transport button (Player controls / Timeline panel). Same for the
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "$schema": "./whats-new.schema.json",
3
3
  "entries": [
4
+ {
5
+ "id": "photo-editor",
6
+ "version": "0.43.0",
7
+ "date": "2026-07-10",
8
+ "kind": "feature",
9
+ "title": "Edit photos right on the canvas",
10
+ "summary": "A new Photo tab in the Inspector lets you tune any photo on your canvas — brightness, contrast, saturation, exposure, hue, sepia, grayscale, duotone, grain, pattern overlays, and vignette/reveal masks — with a live preview, whether it's an image you placed in an artboard or one you dropped/pasted onto the canvas. One click removes the background entirely (runs in your browser, no upload). Reach it from the Inspector's Photo tab or right-click \"Edit Photo…\". Every edit is also scriptable headlessly via /design:photo, so an agent can tune a photo without touching a slider.",
11
+ "surface": "design-ui",
12
+ "tour": [
13
+ {
14
+ "target": "[data-tour=\"inspector-tabs\"]",
15
+ "title": "Photo tab",
16
+ "body": "Select any photo on the canvas and a Photo tab appears here — adjustments, duotone, grain, pattern, masks, and one-click background removal.",
17
+ "placement": "bottom"
18
+ }
19
+ ]
20
+ },
21
+ {
22
+ "id": "footage-analysis-director-reel",
23
+ "version": "0.43.0",
24
+ "date": "2026-07-10",
25
+ "kind": "feature",
26
+ "title": "Turn a folder of clips into a cut — Maude watches your footage first",
27
+ "summary": "New /design:reel: point Maude at a folder of raw video (or the clips already on your canvas) and it actually WATCHES the footage first — pulling keyframes from each clip to find the good shots and read its character — then directs them like an editor into a graphics-laden cut with titles and transitions, ready to scrub on the Timeline and export to MP4. It can use several moments from one clip, orders them so they tell a story, and needs no extra install (frames are decoded in the browser, no ffmpeg). Analysis is vision-only; drop in a music track and it rides under the finished cut.",
28
+ "surface": "design-ui"
29
+ },
30
+ {
31
+ "id": "ssh-remote-publish-and-pr-flow",
32
+ "version": "0.43.0",
33
+ "date": "2026-07-10",
34
+ "kind": "feature",
35
+ "title": "Share to a protected branch — via a pull request",
36
+ "summary": "On a GitHub project, \"Add to Shared version\" now pushes your draft and opens a pull request into main, so it works even when main is protected and a direct push would be rejected — the pull-request link opens right from the dialog. Publishing and getting the latest now work on SSH remotes too, and a blue \"Get latest\" button appears in the dock the moment a teammate's work is ahead, so you're nudged to pull without hunting for it.",
37
+ "surface": "design-ui"
38
+ },
39
+ {
40
+ "id": "unified-text-editing",
41
+ "version": "0.43.0",
42
+ "date": "2026-07-10",
43
+ "kind": "feature",
44
+ "title": "Edit any text on the canvas, inline",
45
+ "summary": "Every kind of text on the canvas now edits the same predictable way — click to place a blinking caret, type, Enter to confirm, Shift+Enter for a new line — across an element's copy, shape and sticky labels, standalone text, and section titles. Text that's filled in from a list or variable (like cards built from data) is now editable in place too: double-click and change the words directly, and it's traced back to the right source. Only genuinely computed text still sends you to chat or /design:edit.",
46
+ "surface": "design-ui"
47
+ },
48
+ {
49
+ "id": "whiteboard-annotation-improvements",
50
+ "version": "0.43.0",
51
+ "date": "2026-07-10",
52
+ "kind": "feature",
53
+ "title": "Bulk resize, sticky authors & fun stickers",
54
+ "summary": "Select several stickies, shapes or images together and resize the whole group proportionally with live corner handles, instead of one at a time. Sticky notes now show who drew them with a name badge. Text editing got a real pass: a visible blinking caret everywhere you edit text, double-click places the caret where you clicked instead of selecting everything, hovering text shows a text cursor, and a new shape or sticky auto-focuses so you can start typing immediately. Also new: a searchable, FigJam-style sticker picker with genuinely fun (not emoji) bundled sticker packs, and /design:board now understands generation requests like \"make me a team sprint retro\" directly.",
55
+ "surface": "design-ui"
56
+ },
4
57
  {
5
58
  "id": "background-export-notification-center",
6
59
  "version": "0.42.0",
@@ -47,6 +47,19 @@ const BIN_VERBS = new Set([
47
47
  'chat-open',
48
48
  'ensure-browser',
49
49
  'fetch-asset',
50
+ // feature-photo-editor (Stage G). `photo-adjust` is the thin non-browser
51
+ // parametric verb (curl → /_api/photo-edit). `photo-bg-remove` is the
52
+ // client-side @imgly ML harness (throwaway proof canvas + agent-browser
53
+ // attribute poll — see photo-bg-remove.sh's header for why).
54
+ 'photo-adjust',
55
+ 'photo-bg-remove',
56
+ // feature-footage-analysis-director. `ingest-footage` copies a folder of raw
57
+ // clips into assets/ (content-addressed, magic-byte sniffed). `probe-footage`
58
+ // decodes ONE clip in headless Chromium → keyframe PNGs for the footage-analyst's
59
+ // vision pass. Neither boots the dev server (probe is server-independent — it
60
+ // reads the clip as a file:// resource).
61
+ 'ingest-footage',
62
+ 'probe-footage',
50
63
  ]);
51
64
 
52
65
  // Bin verbs that boot the dev-server (directly, or by shelling into server-up.sh).
@@ -140,7 +153,7 @@ Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
140
153
  screenshot · server-up · prep · slug · bootstrap-check · runtime-health
141
154
  smoke · canvas-edit · handoff · asset-sweep · visual-sanity · fetch-asset
142
155
  draw-build · draw-proof · svg-optimize · to-lottie · read-annotations · annotate
143
- canvas-rects
156
+ canvas-rects · ingest-footage · probe-footage
144
157
  Invoke the bundled helper of the same name. maude resolves it from its
145
158
  own package root and sets CLAUDE_PLUGIN_ROOT for the child; stdout,
146
159
  stderr, and exit code pass straight through (so command-substitution
@@ -453,7 +466,22 @@ async function runExport({ args }) {
453
466
  }
454
467
 
455
468
  const format = positional[0];
456
- const VALID_FORMATS = new Set(['png', 'pdf', 'svg', 'html', 'pptx', 'canva', 'zip']);
469
+ // Includes the temporal formats (DDR-148): mp4/webm/gif render through the
470
+ // capture spine, same POST /_api/export the UI ⌘E dialog uses. Video export
471
+ // is always artboard-scoped (the comp's registered meta drives fps/duration).
472
+ const VALID_FORMATS = new Set([
473
+ 'png',
474
+ 'pdf',
475
+ 'svg',
476
+ 'html',
477
+ 'pptx',
478
+ 'canva',
479
+ 'zip',
480
+ 'mp4',
481
+ 'webm',
482
+ 'gif',
483
+ ]);
484
+ const VIDEO_FORMATS = new Set(['mp4', 'webm', 'gif']);
457
485
  if (!format || !VALID_FORMATS.has(format)) {
458
486
  process.stderr.write(
459
487
  `maude design export: missing or unknown <format>. Try one of: ${Array.from(VALID_FORMATS).join(', ')}\n`
@@ -461,7 +489,10 @@ async function runExport({ args }) {
461
489
  process.exit(2);
462
490
  }
463
491
 
464
- const scope = flags.scope ?? 'canvas-as-separate';
492
+ // Video formats default to artboard scope (the only scope video supports —
493
+ // scope.ts resolves the artboard under the active canvas); other formats keep
494
+ // the canvas-as-separate default.
495
+ const scope = flags.scope ?? (VIDEO_FORMATS.has(format) ? 'artboard' : 'canvas-as-separate');
465
496
  const VALID_SCOPES = new Set(['selection', 'artboard', 'canvas-as-separate', 'project-raw']);
466
497
  if (!VALID_SCOPES.has(scope)) {
467
498
  process.stderr.write(`maude design export: unknown --scope "${scope}"\n`);
@@ -44,6 +44,7 @@ export function buildBlock(designRel = '.design') {
44
44
  `${root}/_history/`,
45
45
  `${root}/_trash/`, // soft-deleted canvases (recoverable locally — Phase 22 delete)
46
46
  `${root}/_draw/`, // draw-agent proof canvases (regenerable — Phase 25)
47
+ `${root}/_photo/`, // photo-bg-remove headless proof canvases (regenerable — feature-photo-editor)
47
48
  `${root}/_smoke/`, // batch-screenshot output (regenerable — DDR-021)
48
49
  `${root}/_canvas-state/`, // per-machine canvas scratch + camera (`*.view.json`, DDR-115)
49
50
  `${root}/_chat/`, // ACP transcripts (per-machine)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1agh/maude",
3
- "version": "0.42.0",
3
+ "version": "0.43.0",
4
4
  "description": "Marketplace of Claude Code plugins by Michal Dovrtěl: `design` (canvas-first design iteration) + `flow` (generic agentic workflow loop with .ai second brain). Ships the `maude` CLI (with `mdcc` legacy alias) to scaffold workspace, run the design dev server, and manage configs.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -50,13 +50,13 @@
50
50
  "test:e2e:desktop:onboarding": "pnpm --filter @maude/desktop-e2e e2e:onboarding"
51
51
  },
52
52
  "optionalDependencies": {
53
- "@1agh/maude-darwin-arm64": "0.42.0",
54
- "@1agh/maude-darwin-x64": "0.42.0",
55
- "@1agh/maude-linux-arm64": "0.42.0",
56
- "@1agh/maude-linux-arm64-musl": "0.42.0",
57
- "@1agh/maude-linux-x64": "0.42.0",
58
- "@1agh/maude-linux-x64-musl": "0.42.0",
59
- "@1agh/maude-win32-x64": "0.42.0"
53
+ "@1agh/maude-darwin-arm64": "0.43.0",
54
+ "@1agh/maude-darwin-x64": "0.43.0",
55
+ "@1agh/maude-linux-arm64": "0.43.0",
56
+ "@1agh/maude-linux-arm64-musl": "0.43.0",
57
+ "@1agh/maude-linux-x64": "0.43.0",
58
+ "@1agh/maude-linux-x64-musl": "0.43.0",
59
+ "@1agh/maude-win32-x64": "0.43.0"
60
60
  },
61
61
  "files": [
62
62
  "cli",
@@ -94,9 +94,9 @@
94
94
  "scaffold"
95
95
  ],
96
96
  "devDependencies": {
97
- "@biomejs/biome": "^2.4.16",
97
+ "@biomejs/biome": "^2.5.3",
98
98
  "@changesets/cli": "^2.27.10",
99
- "@playwright/test": "^1.60.0"
99
+ "@playwright/test": "^1.61.1"
100
100
  },
101
101
  "dependencies": {
102
102
  "ajv": "^8.20.0",
@@ -135,6 +135,7 @@
135
135
  "react/jsx-runtime": "/_canvas-runtime/react_jsx-runtime.js",
136
136
  "react/jsx-dev-runtime": "/_canvas-runtime/react_jsx-dev-runtime.js",
137
137
  "pixi.js": "/_canvas-runtime/pixi-js.js",
138
+ "@imgly/background-removal": "/_canvas-runtime/@imgly_background-removal.js",
138
139
  "motion": "/_canvas-runtime/motion.js",
139
140
  "motion/react": "/_canvas-runtime/motion_react.js",
140
141
  "yjs": "/_canvas-runtime/yjs.js",