@topy-ai/maggie 0.8.14 → 0.8.16
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-zh-TW.md +1 -1
- package/README.md +1 -1
- package/bundled-references/captions-transcription.md +21 -1
- package/bundled-references/design-editor-patterns.md +104 -0
- package/bundled-references/ffmpeg-recipes.md +21 -0
- package/bundled-references/generative-visuals.md +50 -0
- package/bundled-references/image-recipes.md +47 -0
- package/bundled-references/programmatic-video.md +22 -0
- package/bundled-references/video-timeline-model.md +56 -0
- package/bundled-references/web-animation-patterns.md +34 -0
- package/bundled-skills/maggie-image/SKILL.md +9 -3
- package/bundled-skills/maggie-video/SKILL.md +1 -1
- package/bundled-tools/clis/maggie_image.py +90 -3
- package/bundled-tools/clis/maggie_video.py +22 -14
- package/package.json +1 -1
- package/references/captions-transcription.md +21 -1
- package/references/design-editor-patterns.md +104 -0
- package/references/ffmpeg-recipes.md +21 -0
- package/references/generative-visuals.md +50 -0
- package/references/image-recipes.md +47 -0
- package/references/programmatic-video.md +22 -0
- package/references/video-timeline-model.md +56 -0
- package/references/web-animation-patterns.md +34 -0
package/README-zh-TW.md
CHANGED
|
@@ -143,7 +143,7 @@ structure drift 或重複 treatment product 時 fail closed。
|
|
|
143
143
|
deployment、memory、feedback 和 MaggieDash。內容先 draft/review,外部寫入、
|
|
144
144
|
publish 與 production deployment 需要明確確認。
|
|
145
145
|
|
|
146
|
-
目前 npm 版本為 `0.8.14
|
|
146
|
+
目前 npm 版本為 `0.8.16`,把先前僅 README 的 repo 解稀疏為完整源碼並逐一代碼級研究(驗證所有 reference 並補 net-new:Remotion delayRender gate、opentoonz BSD 可移植的 xsheet 時間線、綠幕/LUT/卡拉OK 濾鏡、whisper turbo + 字幕旗標、Babylon NullEngine 無頭),並新增 maggie_image.py trim/auto-orient 與更豐富的 captions 旗標。先前 0.8.15 補齊除 Q 外所有設計類的覆蓋:maggie_image.py 新增 svg-export(Inkscape)/composite/look,新增 design-editor-patterns reference,並擴充 web-animation/generative-visuals/video-timeline;docs/design-coverage-audit.md 逐 repo 確認。先前 0.8.14 新增 `maggie-ai-media`(去背/放大/arm's-length ComfyUI 的命令生成器,自身不下載模型、不用 GPU),讓 Q 類達到同級;重型執行仍受成本把關。先前 0.8.13 新增 AI 媒體生成規劃 reference(Q 類:自託管模型概覽、程式碼授權≠權重授權規則、商用安全子集 rembg/Real-ESRGAN、成本/BYOK 守則;實際建置待明確許可)。先前 0.8.12 收尾其餘設計類:新增 `maggie-image`(影像處理 CLI:尺寸/OG/favicon/WebP-AVIF/svg/montage)與 web 動效、生成式視覺、圖像配方、字幕四個 reference。先前 0.8.11 收尾 N 類影片功能:`maggie_video.py compile` 再補上視頻 clip ken-burns、sidechain ducking、以及非透明度 overlay 效果(move/slide、圖片 zoom),並新增 `autocut` 子命令(silencedetect 去靜音)。先前 0.8.10 新增圖片 ken-burns + 文字透明度關鍵幀與 `captions`(whisper)子命令。先前 0.8.9 新增 `compile`(宣告式 timeline JSON→單一 ffmpeg 命令)。先前 0.8.8 新增 `maggie-video`(製作與處理行銷影片:剪輯、字幕、裁切成各渠道比例、浮水印、轉碼、響度正規化、clip 組裝、程式化動畫),附一個實測可用的 ffmpeg 配方 CLI(`maggie_video.py`),從參考庫的影片專案(moviepy/editly/ffmpeg 命令層、Revideo/Motion Canvas/CCapture 程式化渲染、MLT/OpenShot/Olive 的 timeline 資料形狀)提煉而來;另加 `ffmpeg-recipes`、`programmatic-video`、`video-timeline-model` 三個 reference。先前 0.8.7 把 redesign 稽核併入 `maggie-design`(改編自 MIT 的 `elayadesign/redesign-skill`):掃描 + 診斷 AI 通病/缺失狀態/雜亂程式碼,再經 in-place/verify 流程就地修正,因此「稽核/打磨/升級既有站點」會路由到 maggie-design。先前 0.8.6 補齊兩個設計技能:加入完整的生產 reference,並把設計來源明確為 Figma 非必需(實時 URL、既有程式碼、Figma、或純截圖)。先前 0.8.5 採納兩個設計技能(改編自 MIT 的 `elayadesign/ai-design-skills`):maggie-landing-page(轉化策略 + 視覺系統紀律,具體數值為可被專案 DESIGN.md 覆蓋的預設值;由 maggie-design 生產與驗證)與 maggie-design-motion(靜態設計→像素級動畫 HTML 複刻→匯出 MP4 + GIF)。先前 0.8.4 將技能庫擴展成完整的「一人用 AI 跑一家公司」C-suite,新增八條職能線:maggie-sales(CRM 中立的銷售管線)、maggie-finance(只解釋的 CFO 指標,含確定性 maggie_finance.py 計算器)、maggie-support(面向客戶的客戶成功)、maggie-product(路線圖 + 預註冊實驗)、maggie-fundraising(pitch deck、data room、投資人更新)、maggie-legal(ToS/隱私/DPA/SOC2 readiness)、maggie-monetization(定價/paywall/dunning,金錢操作需人工批准)、maggie-orchestrator(CEO 編排層:將目標拆成帶審批門的 mission 分派到各職能線,含 maggie_orchestrator.py 規劃器)。先前 0.8.3 將 cmo.so/www 開發經驗沉澱進技能庫:新增兩個技能 maggie-skill-authoring(依 catalog 與 MCP 工具白名單撰寫/校驗社區營銷 playbook 技能)與 maggie-feedback-triage(反饋的團隊接收端:決策/定級/分派、PRD + issue 流程、24/7 隊列守護);新增多個 reference(OAuth PKCE 登入、Expo 約定與 Router 骨架、MCP evals 測試框架、conversation cards、WordPress→Firebase 認證遷移手冊);並增補 maggie-assistant-tools(tool≤user 每輪工具過濾、agent loop 安全不變量、preview-only 橋接代理、MCP resources/prompts、注解加固、CLI 與 ChatGPT 插件打包)、maggie-auth-reference(自清理登入測試套件、自簽單次令牌)、maggie-mobile-app(OTA 開機拉取、live==built 部署守衛)、maggie-deployment(pm2 單包發布、live-hash 校驗)與 maggie-ops(template-as-code 郵件同步)。先前 0.8.2 新增 maggie-spirit(為 AI 品牌生成平面像素 spirit/sprite 系統)與 goal-led AI agent 設計參考;0.8.0 為安全優化 roadmap(scan、image-patch、標頭評分、SSVC、GDPR 日誌規則、新 MCP 工具)。先前 0.8.0 為安全優化 roadmap(scan、image-patch、標頭評分、SSVC、GDPR 日誌規則、新 MCP 工具),含 fix-plan 修補風險分級 T1–T4(判斷補丁是否安全套用)與 host-impact 補丁影響面量測(哪些服務需重啟、是否需重開機)、public-check、Maggie Security、batch 31 排程 agent routines、報告收件匣與無人值守 agent 限制、PHP runtime 盤點與主機鎖、pull 網站改寫、query 點子與社群佇列檢查,batch 30 MaggieDash 先裝核心、release privacy gate、feedback 備援、社群連結與圖片檢查、大量頁面產生與 app 檢查,batch 29 預約規則、部署、app QA、助理與社群功能,以及 batch 28 產品 app、assistant tools、mobile、product release、skills catalog 與 bridge host 功能、batch 26、27 feedback 修正與 idempotent `maggie update`與 Booking email-template 合約/CLI validator 同步。本版完成 2026-09-24 booking feedback batch:Calendar grid/free-slot entry 與 host modal focus-restoration evidence。本版新增 Starter marketplace provisioning plan;本版完成 feedback batches 22、23:加入 declarative browser interaction evidence、design markup/style/content-key gate、compiler source anchoring、entity double-escape protection、`update --help` read-only、noindex hypothetical indexability、可過期 baseline acknowledgement、DOM-only link extraction regression,以及 MaggieDash 0.2.10 的 content override、短期 browser session、CDN-safe public-session cache contracts。authentication 和 isolated dev server 仍由 host 負責。`maggie-booking` workflow、傳統 email/password、Stripe、Resend、public booking flow 及既有安全邊界維持不變;provider-bound video generation 與 transactional delivery 仍記錄在 issue #39,前一批延後功能仍在 issue #38,不會直接成為 active memory。0.7.33 記錄並審查一筆更正回饋;確認 0.7.32 已正確處理 batch index,沒有修改已驗證的 shared behavior。0.7.32 加入 feedback 一基索引支援、MaggieDash panel 的 source/freshness/error evidence、Consent Mode 與實際 write/no-op reconciliation、SEO baseline recapture、sitemap origin rebasing、content-diff scope、migration ledger reconciliation、deployment credential preflight、release provenance/runtime preflight、icon release gate、opt-in blog auto-publish gate,以及 least-privilege VPS deployer。也修復 top-level `maggie feedback` dispatcher parity。0.7.31 加入 update 差異摘要、atomic installer copy、subset install manifest merge,以及 inventory drift 時 doctor non-zero。0.7.30 補上 feedback tracking issue closeout gate 與 batch 14/15 audit ledger。0.7.29 修正 npm package landing page 使用英文 README;0.7.28 加入 versioned Gemini model policy、明確 fallback 與 provenance、bundled-first CLI
|
|
147
147
|
dispatch、`maggie --version`、feedback batch review 聚合與重複偵測、marketplace enrichment evidence、booking
|
|
148
148
|
worker/resolver evidence,以及 read-only migration preflight。它也包含 host-owned mobile app surface contract、signed-in
|
|
149
149
|
camera-state QA、直接 Astro route resolution、correlated feedback batch,以及
|
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ Maggie keeps the existing project foundation and asks for decisions before
|
|
|
89
89
|
shared routes, analytics, or publishing boundaries change. The current
|
|
90
90
|
package ships 39 installable skills and a local-first MaggieDash foundation.
|
|
91
91
|
|
|
92
|
-
This package is `0.8.
|
|
92
|
+
This package is `0.8.16` — de-sparses the earlier README-only repos to full source and studies them at code level (confirm + net-new: Remotion delayRender gate, opentoonz BSD port target, green-screen/LUT/karaoke filters, whisper turbo + caption flags, Babylon NullEngine), plus maggie_image.py trim/auto-orient and richer captions flags. `0.8.15` closed the non-Q design coverage gap: `maggie_image.py` gains svg-export/composite/look, a new design-editor-patterns reference, and growth in web-animation/generative-visuals/video-timeline references. `0.8.14` adds `maggie-ai-media` (bg removal / upscaling / arm's-length ComfyUI as a command generator; no model downloads or GPU itself). `0.8.13` adds the AI-media-generation planning reference (category Q: licensing + safe subset + cost guardrails; build gated on go-ahead). `0.8.12` adds `maggie-image` (process images via an ImageMagick recipe CLI) + references for web animation, generative visuals, image recipes, and captions. `0.8.11` - `maggie_video.py compile` now also does video-clip ken-burns, sidechain ducking, and non-opacity overlay effects (move/slide, image zoom), and a new `autocut` subcommand removes silent gaps. `0.8.10` added image ken-burns + text opacity keyframes and the `captions` (whisper) subcommand. `0.8.9` added `compile` (declarative timeline JSON -> one ffmpeg command). `0.8.8` added `maggie-video` (produce and process marketing video: cut, caption, resize to channel aspects, watermark, transcode, normalize loudness, assemble clips, render code-drawn animation) with a tested ffmpeg-recipe CLI, distilled from the reference library's video projects; plus references `ffmpeg-recipes`, `programmatic-video`, `video-timeline-model`. `0.8.7` folded a redesign audit into `maggie-design` (from the MIT `elayadesign/redesign-skill`): scan + diagnose generic AI-design patterns/weak states/sloppy code, then fix in place via the in-place/verify flow, so "audit/polish/upgrade an existing site" routes to maggie-design. `0.8.6` completed the two adopted design skills with full production references and made the design source Figma-optional (live URL, existing code, Figma, or a screenshot). `0.8.5` adopted the two design skills (adapted, MIT, from `elayadesign/ai-design-skills`): `maggie-landing-page` (conversion strategy + a visual-system discipline whose values defer to the project's DESIGN.md) and `maggie-design-motion` (static design → pixel-exact animated HTML replica → MP4 + GIF export). `0.8.4` expanded the library into a full "one person runs a company with AI" C-suite with eight new function lanes: `maggie-sales` (CRM-neutral pipeline), `maggie-finance` (explain-only CFO metrics + a deterministic `maggie_finance.py` calculator), `maggie-support` (customer success), `maggie-product` (roadmap + pre-registered experiments), `maggie-fundraising` (deck, data room, investor updates), `maggie-legal` (ToS/privacy/DPA/SOC2 readiness), `maggie-monetization` (pricing/paywalls/dunning; money actions human-approved), and `maggie-orchestrator` (the CEO layer that decomposes a goal into gated missions across the lanes, with a `maggie_orchestrator.py` planner). `0.8.3` folded cmo.so/www development learnings in (maggie-skill-authoring, maggie-feedback-triage, and mobile/MCP/auth references); `0.8.2` added `maggie-spirit`; `0.8.0` was the security optimization roadmap.
|
|
93
93
|
|
|
94
94
|
The 0.7.59 release made `maggie security host-audit` (the deep
|
|
95
95
|
lynis audit over SSH) robust on hosts where a storage test can stall: lynis runs
|
|
@@ -9,7 +9,7 @@ Distilled from the reference library's R-category projects.
|
|
|
9
9
|
|
|
10
10
|
| Engine | What / how | License | Reach for it when |
|
|
11
11
|
|---|---|---|---|
|
|
12
|
-
| openai-whisper |
|
|
12
|
+
| openai-whisper | `whisper IN --model turbo --output_format srt --output_dir DIR` (default model is now **`turbo`** = large-v3-turbo; formats `txt/vtt/srt/tsv/json`) | MIT | the default; simplest install (`pip install openai-whisper`) |
|
|
13
13
|
| whisper.cpp | C/C++ port, fast on CPU, GGML models: `whisper-cli -m model.bin -f IN -osrt -of OUTBASE` | MIT | no GPU / fastest CPU / embedding in a pipeline |
|
|
14
14
|
| whisperX | whisper + forced alignment for **word-level timestamps** and diarization: `whisperx IN --model large-v3 --output_format srt --output_dir DIR` | BSD-4 | word-accurate caption timing or speaker labels |
|
|
15
15
|
|
|
@@ -38,4 +38,24 @@ Model size trades speed for accuracy: `tiny` / `base` (fast, rough) -> `small` /
|
|
|
38
38
|
API is ever wired in instead, the global spend-first rule applies - state the cost.
|
|
39
39
|
- Keep caption text inside the safe area (see `maggie-video` channel presets).
|
|
40
40
|
|
|
41
|
+
## Caption-shaping flags (built into openai-whisper)
|
|
42
|
+
|
|
43
|
+
The core CLI already does what we previously routed to whisperX or post-processing
|
|
44
|
+
(`maggie_video.py captions` exposes these):
|
|
45
|
+
|
|
46
|
+
- `--word_timestamps True` - word-level timings (whisperX still wins on alignment +
|
|
47
|
+
diarization, but core whisper now has them).
|
|
48
|
+
- `--highlight_words True` - **karaoke-style** per-word highlight in SRT/VTT (the
|
|
49
|
+
social-caption effect); render the ASS with ffmpeg `subtitles`.
|
|
50
|
+
- `--max_line_width` / `--max_line_count` / `--max_words_per_line` - native line
|
|
51
|
+
wrapping so captions fit the channel safe-area, no post-processing.
|
|
52
|
+
- `--initial_prompt "<brand, product names>"` - bias the model toward correct brand/
|
|
53
|
+
jargon spelling (the concrete mitigation for the mishears-brand-terms risk; still
|
|
54
|
+
human-review).
|
|
55
|
+
- Anti-hallucination over music/silence: `--hallucination_silence_threshold`,
|
|
56
|
+
`--compression_ratio_threshold`, `--logprob_threshold`, `--no_speech_threshold` -
|
|
57
|
+
worth setting for music-bed marketing clips.
|
|
58
|
+
- `--task translate` (foreign audio -> English subs), `--clip_timestamps` (only given
|
|
59
|
+
ranges).
|
|
60
|
+
|
|
41
61
|
See `maggie-video` for the subcommands and the burn-in / soft-mux / compile options.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Design-editor patterns
|
|
2
|
+
|
|
3
|
+
Borrowable logic and creativity from open-source design, whiteboard, vector and raster
|
|
4
|
+
**editors** (reference library category P), for making and handling marketing visuals
|
|
5
|
+
programmatically. We adopt **concepts and data shapes, not code** (most are GPL/AGPL/
|
|
6
|
+
MPL or custom-licensed; the few MIT ones are reimplemented, not bulk-copied). Pairs
|
|
7
|
+
with [image recipes](image-recipes.md), [generative visuals](generative-visuals.md),
|
|
8
|
+
and [AI media generation](ai-media-generation.md).
|
|
9
|
+
|
|
10
|
+
## Non-destructive edit recipe (darktable)
|
|
11
|
+
|
|
12
|
+
darktable (GPL) edits by a **replayable history stack of named module invocations**,
|
|
13
|
+
stored in an **XMP sidecar** beside the untouched original - never mutating the source;
|
|
14
|
+
the image is reconstructed by replaying the stack. Borrow this as a maggie "image edit
|
|
15
|
+
recipe": a small JSON `[ {op, params}, ... ]` stored next to the original and replayed
|
|
16
|
+
by `maggie_image.py` (each op -> an ImageMagick/sharp command). It is **reproducible,
|
|
17
|
+
auditable, re-editable, and batchable** - apply one "look" recipe to every photo in a
|
|
18
|
+
campaign for consistent brand grading. `darktable-cli <input> [sidecar.xmp]
|
|
19
|
+
<output-dir>` renders from such a stack (XMP optional/auto-discovered, final arg is a
|
|
20
|
+
**directory**; GPL binary, arm's-length). Two source details worth adopting: **params
|
|
21
|
+
versioning** (each module keeps `legacy_params` for forward-compatible migration -
|
|
22
|
+
version your recipe ops) and **"Styles" = saved reusable history** (name a look once,
|
|
23
|
+
apply to many).
|
|
24
|
+
|
|
25
|
+
## LLM-generatable scene / diagram formats
|
|
26
|
+
|
|
27
|
+
- **Excalidraw** (`.excalidraw` JSON, MIT) - a flat list of elements (`{type:
|
|
28
|
+
rectangle|ellipse|diamond|text|line|arrow|freedraw|image|frame, x, y, width, height,
|
|
29
|
+
strokeColor, backgroundColor, fillStyle, roughness, seed, roundness, groupIds,
|
|
30
|
+
boundElements}`) with a separate `files` asset map and ratio-based arrow/label
|
|
31
|
+
bindings that survive resize. **Emit it from a prompt** for diagrams, flowcharts,
|
|
32
|
+
annotated screenshots -> open in-app or render to SVG/PNG, with an on-brand hand-drawn
|
|
33
|
+
(rough.js) look.
|
|
34
|
+
- **drawio / mxGraph** (`mxGraphModel` XML, Apache-2.0 code; diagram output
|
|
35
|
+
unrestricted) - `<mxCell>` nodes with `value` (label), a compact `style` DSL
|
|
36
|
+
(`rounded=1;fillColor=#dae8fc;strokeColor=#6c8ebf;`), `vertex="1"` or `edge="1"` with
|
|
37
|
+
`source`/`target`, and `<mxGeometry>`. Trivially generatable for org charts, funnels,
|
|
38
|
+
architecture diagrams; render headless to SVG/PNG (don't redistribute their icon/
|
|
39
|
+
stencil sets).
|
|
40
|
+
|
|
41
|
+
## SVG as the document (Method-Draw) + safe ingest
|
|
42
|
+
|
|
43
|
+
Method-Draw (MIT, from SVG-Edit) treats the **live SVG DOM as the single source of
|
|
44
|
+
truth** - `XMLSerializer` is the save format; no separate scene JSON. Two borrows:
|
|
45
|
+
(a) the simplest possible model for programmatic marketing SVGs (build the DOM,
|
|
46
|
+
serialize); (b) a **sanitize whitelist** (`svgWhiteList_`) of allowed SVG elements/
|
|
47
|
+
attributes - essential for safely ingesting user- or AI-supplied SVG before rendering
|
|
48
|
+
(strips scripts/unknowns); pair with svgo in [image recipes](image-recipes.md). Its
|
|
49
|
+
command `apply/unapply` history is the generic edit-history pattern (and the backbone
|
|
50
|
+
of the edit-recipe above).
|
|
51
|
+
|
|
52
|
+
## Design-doc patterns (penpot, tldraw)
|
|
53
|
+
|
|
54
|
+
- **penpot** (MPL, concept) - a design doc in **open standards (SVG/CSS/HTML/JSON)**
|
|
55
|
+
with first-class **Design Tokens as the single source of truth** between brand and
|
|
56
|
+
code, **Components + Variants** (one card, many variants = reusable marketing
|
|
57
|
+
templates), CSS Grid/Flex layout on the doc, and an **MCP server** making the doc
|
|
58
|
+
agent-readable. Strong alignment with Maggie's brand-kit + MCP posture.
|
|
59
|
+
- **tldraw** (custom license, concept) - an infinite-canvas **reactive record store**
|
|
60
|
+
of typed shape records (geometry + props + `parentId` + fractional index) with
|
|
61
|
+
bindings/assets/pages, and the explicit framing that **an LLM agent operates on the
|
|
62
|
+
canvas document as data** - reinforcing the "generate the scene JSON" approach.
|
|
63
|
+
|
|
64
|
+
## AI-edit vocabulary (krita-ai-diffusion)
|
|
65
|
+
|
|
66
|
+
krita-ai-diffusion (GPL, concept) bolts generative AI onto a layer/selection editor
|
|
67
|
+
over a ComfyUI backend. The borrowable vocabulary for precise AI image edits (beyond
|
|
68
|
+
full-frame generation): **mask/selection-scoped generative fill** (inpaint, expand,
|
|
69
|
+
add/remove inside a region), **layer-as-region prompting** (a text prompt per image
|
|
70
|
+
area defined by a layer), and **conditioning** via ControlNet (scribble/lineart/canny/
|
|
71
|
+
pose/depth/segmentation) and IP-Adapter (reference image, style/composition transfer).
|
|
72
|
+
The plugin-over-backend boundary (editor model stays; AI is a swappable backend)
|
|
73
|
+
mirrors the arm's-length posture in [AI media generation](ai-media-generation.md).
|
|
74
|
+
|
|
75
|
+
## Licensing
|
|
76
|
+
|
|
77
|
+
Invoke binaries at arm's length (never vendor): inkscape, darktable (GPL). Concepts
|
|
78
|
+
only: penpot (MPL), tldraw (custom), krita/krita-ai-diffusion (GPL), drawio icon sets.
|
|
79
|
+
MIT and freely borrowable as ideas (still reimplement, don't bulk-copy): excalidraw,
|
|
80
|
+
Method-Draw, rough.js, Pinta. drawio code Apache-2.0; its diagram output is
|
|
81
|
+
unrestricted.
|
|
82
|
+
|
|
83
|
+
## From full-source study (net-new)
|
|
84
|
+
|
|
85
|
+
- **tldraw** - the LLM mutation surface is `editor.createShapes/updateShapes/
|
|
86
|
+
deleteShapes` (batch partial mutations); the store ships schema **migration
|
|
87
|
+
sequences**, a composable **validation layer**, and a **side-effects manager**
|
|
88
|
+
(before/after create/change/delete hooks). `parentId` can be a page *or* a shape;
|
|
89
|
+
pages carry a fractional `index`. Adopt the batch-mutation + validate + migrate
|
|
90
|
+
shape as the model for an agent-written canvas doc.
|
|
91
|
+
- **penpot** - **design tokens are W3C DTCG** (import/export + aliasing), components
|
|
92
|
+
have **variants**, shapes carry **flex/grid layout**; the agent boundary is an
|
|
93
|
+
**official MCP server talking to a sandboxed in-app plugin over WebSocket** - a
|
|
94
|
+
strong arm's-length model for making a design doc agent-writable (mirrors Maggie's
|
|
95
|
+
own MCP posture).
|
|
96
|
+
- **drawio** - the `mxConstants` STYLE_* key table is a **validated allow-list** for
|
|
97
|
+
LLM-emitted styles; `mxEdgeStyle` routing + hierarchical/tree/organic **auto-layout**
|
|
98
|
+
mean a generated node+edge list can self-position; `.drawio` pages are often
|
|
99
|
+
**deflate+base64** compressed.
|
|
100
|
+
- **krita** - an **adjustment/filter layer holds a serialized filter config** = a
|
|
101
|
+
non-destructive recipe living in the layer stack; ops are **mask/selection-scoped**;
|
|
102
|
+
`.kra` is `zip(manifest XML + per-layer blobs)`; a **Python scripting API** and a
|
|
103
|
+
JSON-manifest plugin boundary let a generative backend register like any filter -
|
|
104
|
+
the "AI as a swappable backend" posture.
|
|
@@ -128,3 +128,24 @@ maggie tool maggie_video.py compile --spec timeline.json # declarative timelin
|
|
|
128
128
|
maggie tool maggie_video.py --run encode --input in.mov --output out.mp4 # actually runs
|
|
129
129
|
maggie tool maggie_video.py presets
|
|
130
130
|
```
|
|
131
|
+
|
|
132
|
+
## More filters worth reaching for (confirmed in libavfilter)
|
|
133
|
+
|
|
134
|
+
- **Green-screen / keying** (UGC, product on a brand background):
|
|
135
|
+
`chromakey=0x00FF00:0.1:0.0` (or `colorkey`), clean fringes with `despill`.
|
|
136
|
+
- **Fade to/from black** (distinct from clip crossfade): `fade=t=in:st=0:d=0.5`,
|
|
137
|
+
`fade=t=out:st=9.5:d=0.5`.
|
|
138
|
+
- **Brand color grade / LUT**: `lut3d=brand.cube`, or `curves`/`eq`/`colorbalance`/`hue`.
|
|
139
|
+
- **Karaoke captions**: `subtitles=in.ass` with a full ASS file (word highlight) -
|
|
140
|
+
pairs with whisper `--highlight_words` ([captions](captions-transcription.md)).
|
|
141
|
+
- **Focus/credits**: `gblur` + `vignette`; `scroll` for scrolling outros.
|
|
142
|
+
- **GPU fast path** when hardware is present: `overlay_cuda`/`overlay_vulkan`,
|
|
143
|
+
`xfade_opencl` for long renders.
|
|
144
|
+
|
|
145
|
+
## Target-filesize social presets (HandBrake idea)
|
|
146
|
+
|
|
147
|
+
Beyond aspect, encode to **fit under a platform's upload cap**: pick a two-pass video
|
|
148
|
+
bitrate from the cap and duration - `bitrate_bits = size_bytes * 8 / duration - audio`
|
|
149
|
+
- e.g. "25 MB / 30 s / 1080p". A named preset bundles `(upload cap, max duration) ->
|
|
150
|
+
resolution + bitrate`. (HandBrake ships exactly these as "Social 25 MB 30 Seconds"
|
|
151
|
+
presets.)
|
|
@@ -92,3 +92,53 @@ zdog, pts, hydra, regl, Babylon.js, react-three-fiber, fogleman/primitive, svg.j
|
|
|
92
92
|
nannou - licenses in the table above. Capture pipeline: see
|
|
93
93
|
[programmatic video](programmatic-video.md), [design-motion production](design-motion-production.md),
|
|
94
94
|
[ffmpeg recipes](ffmpeg-recipes.md).
|
|
95
|
+
|
|
96
|
+
## More patterns (from the desktop/editor study)
|
|
97
|
+
|
|
98
|
+
- **The shared sketch model** (processing / openFrameworks / nannou / p5): a `setup()`
|
|
99
|
+
once + per-frame `draw()` loop with seeded `random()/noise()`. openFrameworks (MIT)
|
|
100
|
+
splits it into `setup()/update()/draw()` (sim vs render); nannou (MIT/Apache)
|
|
101
|
+
formalizes Model-Update-View. The reusable discipline: **keep state separate from the
|
|
102
|
+
render fn, index by frame, seed all randomness** - that is what makes a loop
|
|
103
|
+
reproducible and headless-capturable. Default to p5/three/regl in the browser;
|
|
104
|
+
reach for a desktop framework only for heavy GPU throughput or offline high-res
|
|
105
|
+
render the browser can't sustain. (Processing non-core is GPL - reimplement.)
|
|
106
|
+
- **Hand-drawn scene JSON (excalidraw, MIT).** `.excalidraw` is a flat list of
|
|
107
|
+
elements (`{type, x, y, w, h, strokeColor, backgroundColor, fillStyle:
|
|
108
|
+
hachure|cross-hatch|solid|zigzag, roughness, seed, roundness}`) rendered with
|
|
109
|
+
rough.js. It is **LLM-generatable**: emit the JSON for a diagram/flowchart/annotated
|
|
110
|
+
screenshot, then render to SVG/PNG. The rough.js mapping for an on-brand hand-made
|
|
111
|
+
look: `seed` (determinism), `fillStyle`, `fillWeight = strokeWidth/2`,
|
|
112
|
+
`hachureGap = strokeWidth*4`, `roughness`, `disableMultiStroke` for non-solid strokes.
|
|
113
|
+
- **Vector shape morphing** (synfig concept): tween between two paths by interpolating
|
|
114
|
+
each control point's vertex + in/out tangents + width - smooth logo/blob/path morphs.
|
|
115
|
+
- **Repeater / radial stamp** (Lottie concept): one shape -> N transformed copies with
|
|
116
|
+
an incremental transform + opacity ramp (bursts, confetti, radial brand patterns) -
|
|
117
|
+
cheap, on-brand, deterministic.
|
|
118
|
+
- For AI-assisted editing vocabulary (mask/selection-scoped generation, layer-as-region
|
|
119
|
+
prompting, ControlNet/IP-Adapter conditioning), see
|
|
120
|
+
[AI media generation](ai-media-generation.md) and
|
|
121
|
+
[design editor patterns](design-editor-patterns.md).
|
|
122
|
+
|
|
123
|
+
### Headless capture + 3D export (from full-source study)
|
|
124
|
+
|
|
125
|
+
How to render these engines **without a screen**, and extra output formats worth
|
|
126
|
+
knowing:
|
|
127
|
+
|
|
128
|
+
- **Babylon.js `NullEngine`** (Apache-2.0) - first-class **server-side headless**
|
|
129
|
+
rendering (no GPU/canvas); the cleanest headless story for render-automation jobs,
|
|
130
|
+
plus a built-in **procedural-texture library** (brick/cloud/fire/marble/noise/wood),
|
|
131
|
+
`CreateScreenshotUsingRenderTarget` for 4K+ stills from a small viewport, and
|
|
132
|
+
**NodeMaterial** (shaders serialize to JSON - an LLM-emittable look). This is the
|
|
133
|
+
concrete reason to pick Babylon over three for automation.
|
|
134
|
+
- **three.js** (MIT) - `readRenderTargetPixels()`/`...Async` read pixels from an
|
|
135
|
+
offscreen `WebGLRenderTarget` (true headless high-res, not on-screen canvas);
|
|
136
|
+
**SVGRenderer** emits a 3D scene as editable SVG; **USDZExporter** turns a 3D product
|
|
137
|
+
into a free **iOS AR Quick Look** asset; **GPUComputationRenderer** (ping-pong FBO
|
|
138
|
+
sim: flocking/fluid) = a living, seeded generative hero background.
|
|
139
|
+
- **openFrameworks** (MIT) - `ofFbo` offscreen framebuffer for arbitrary-res stills;
|
|
140
|
+
**ofxEmscripten** compiles a desktop sketch to WebAssembly for the browser;
|
|
141
|
+
**ofxSvg** parses + emits structured SVG.
|
|
142
|
+
- **Processing** - `PSurfaceNone` (headless) and `createGraphics(big)` (render larger
|
|
143
|
+
than the screen -> high-res still). License at feature granularity: core raster is
|
|
144
|
+
LGPL, but **SVG/PDF export is in non-core (GPL)** - reimplement, don't vendor.
|
|
@@ -87,3 +87,50 @@ sharp (Apache-2.0), squoosh codecs (Apache-2.0), imagemin (MIT), cwebp/avifenc
|
|
|
87
87
|
(BSD). **Avoid vendoring code from** Upscayl (AGPL-3.0) - for AI upscaling invoke the
|
|
88
88
|
separate `realesrgan-ncnn-vulkan` binary instead. sharp/squoosh quality defaults are
|
|
89
89
|
adopted as the preset numbers.
|
|
90
|
+
|
|
91
|
+
## SVG beyond resvg/ImageMagick (Inkscape, arm's-length)
|
|
92
|
+
|
|
93
|
+
Inkscape's headless CLI (GPL app, invoked like ImageMagick) fills gaps resvg and IM
|
|
94
|
+
can't: **font outlining, PDF/EPS, and per-id slicing**. `maggie_image.py svg-export`
|
|
95
|
+
generates these.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
inkscape in.svg --export-type=png --export-filename=out.png --export-width=1200 \
|
|
99
|
+
--export-area-drawing --export-background=#ffffff --export-background-opacity=1
|
|
100
|
+
inkscape in.svg --export-type=pdf --export-filename=out.pdf # print collateral
|
|
101
|
+
inkscape in.svg --export-text-to-path --export-type=svg --export-filename=flat.svg # outline fonts for handoff
|
|
102
|
+
inkscape in.svg --export-id=badge --export-id-only --export-type=png --export-filename=badge.png # slice one element
|
|
103
|
+
inkscape in.svg --export-type=png --export-dpi=300 --export-area-page --export-filename=print.png
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Layered composite + named looks (Pinta vocabulary)
|
|
107
|
+
|
|
108
|
+
Blend modes map from a raster editor's layer stack onto ImageMagick `-compose`:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
convert base.png overlay.png -gravity center -compose Multiply -composite out.png
|
|
112
|
+
# modes: Over, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
|
|
113
|
+
# HardLight, SoftLight, Difference, Exclusion
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Named "looks" (each a one-line style preset - a lightweight take on darktable's
|
|
117
|
+
non-destructive edit recipe): `grayscale` (`-colorspace Gray`), `sepia`
|
|
118
|
+
(`-sepia-tone 80%`), `posterize` (`-posterize 4`), `duotone` (`-colorspace Gray
|
|
119
|
+
-level-colors '#1a1a2e','#e94560'`), `vignette` (`-background black -vignette 0x20`),
|
|
120
|
+
`oilpaint` (`-paint 4`), `sketch` (`-colorspace Gray -charcoal 1`), `blur`/`sharpen`.
|
|
121
|
+
`maggie_image.py composite` and `maggie_image.py look` generate these. For a
|
|
122
|
+
reusable, batchable edit *recipe* (a JSON stack of named ops applied to many photos),
|
|
123
|
+
see [design editor patterns](design-editor-patterns.md).
|
|
124
|
+
|
|
125
|
+
## More ImageMagick ops worth baking in (confirmed in source)
|
|
126
|
+
|
|
127
|
+
- **`-auto-orient`** first in every pipeline - fixes sideways phone photos by EXIF
|
|
128
|
+
(`maggie_image.py` resize/social/trim already prepend it).
|
|
129
|
+
- **`-thumbnail WxH`** - metadata-stripping fast resize; a better default than
|
|
130
|
+
`-resize` for web/OG thumbnails.
|
|
131
|
+
- **`-fuzz N% -trim +repage`** - trim a uniform border or cut a product/logo out of
|
|
132
|
+
its background (`maggie_image.py trim`).
|
|
133
|
+
- **`-clut` / `-hald-clut`** - repeatable LUT brand grading (raster equivalent of
|
|
134
|
+
ffmpeg `lut3d`).
|
|
135
|
+
- **`-distort perspective '<src coords> <dst coords>'`** - place a screenshot into a
|
|
136
|
+
device mockup.
|
|
@@ -78,3 +78,25 @@ apply.
|
|
|
78
78
|
`libx264 -crf 14-20 -preset slow/medium -pix_fmt yuv420p -movflags +faststart`,
|
|
79
79
|
even dimensions, plus 960px / 800x500 GIF deliverables. For transparent output,
|
|
80
80
|
Revideo uses per-format pixel formats (`yuva420p` WebM, `yuva444p10le` ProRes).
|
|
81
|
+
|
|
82
|
+
## Remotion's real renderer (from source) and the ideas to borrow
|
|
83
|
+
|
|
84
|
+
Source study (Remotion License - concept only, no vendoring) shows Remotion is **not**
|
|
85
|
+
the base64-PNG pipe we lump with Revideo/Motion Canvas: it drives headless Chromium
|
|
86
|
+
over CDP, captures frames via **shared memory**, and encodes with a **per-platform
|
|
87
|
+
native Rust sidecar that statically links FFmpeg** (a long-running streaming process),
|
|
88
|
+
plus a bundled `ffmpeg` for the final stitch. Borrowable ideas (improve our Part C):
|
|
89
|
+
|
|
90
|
+
- **A readiness gate, not just a fake clock.** `delayRender()`/`continueRender()`: a
|
|
91
|
+
component declares async work pending and the renderer blocks the screenshot until
|
|
92
|
+
all handles clear, reporting **labeled** open handles on timeout. Add an explicit
|
|
93
|
+
readiness handshake (plus a per-frame `await document.fonts.ready`) to Part C so no
|
|
94
|
+
frame is captured before fonts/data/images are ready - prevents FOUT/half-loaded
|
|
95
|
+
frames.
|
|
96
|
+
- **Tab-pool concurrency**: open N browser pages, each seeking a different frame in
|
|
97
|
+
parallel (frame range / N).
|
|
98
|
+
- **Chunked parallel encode + seamless concat**: split the frame range, encode chunks
|
|
99
|
+
independently, concat without re-encode - throughput for long renders.
|
|
100
|
+
- **Kept-open, LRU-cached source-video decoders**: for embedded video assets, keep the
|
|
101
|
+
decoder open and cache frames so repeated seeks to a timestamp are cheap (our flat
|
|
102
|
+
timeline currently punts this to raw ffmpeg `-ss`).
|
|
@@ -130,3 +130,59 @@ arm's length, never linked or vendored.
|
|
|
130
130
|
keyframe/ease vocabulary, the licensing note - stable and engine-neutral.
|
|
131
131
|
- **`maggie-video` skill:** channel presets, caption/CTA safe-areas, the operational
|
|
132
132
|
ffmpeg command layer (via `maggie_video.py`), and tool wiring.
|
|
133
|
+
|
|
134
|
+
## Extensions from the animation-tool study (O-category)
|
|
135
|
+
|
|
136
|
+
Concepts to grow the model (adopt the data shape / vocabulary; code only from the
|
|
137
|
+
MIT/BSD sources - rlottie MIT, opentoonz/tahoma2d BSD; synfig/friction/wick/Natron
|
|
138
|
+
GPL = concept only):
|
|
139
|
+
|
|
140
|
+
- **Richer keyframe easing** (synfig). Extend `{t, v, ease}` with: **per-side ease**
|
|
141
|
+
(`easeIn` != `easeOut`), **`clamped`** (auto-smooth that won't overshoot the keyed
|
|
142
|
+
value), **`hold`/`constant`**, and optional **TCB** `{tension, continuity, bias}`.
|
|
143
|
+
Add **`fullRotations`** on a rotation keyframe (wick) to control spin count/direction
|
|
144
|
+
rather than shortest-path. These precompute to per-frame values for ffmpeg and map to
|
|
145
|
+
CSS/Lottie beziers. (compile currently interpolates linearly; this is the target
|
|
146
|
+
vocabulary.)
|
|
147
|
+
- **Lottie JSON as the companion vector-motion-graphics format** (rlottie, MIT). For
|
|
148
|
+
logo stings, animated icons and kinetic type, use Lottie (After-Effects/Figma
|
|
149
|
+
exportable, in-browser renderable via lottie-web) alongside the MLT/NLE shape. Borrow
|
|
150
|
+
its primitives: **Trim-path** (`start%/end%/offset` - the formal version of the
|
|
151
|
+
"draw a line on" trick in [design-motion production](design-motion-production.md)),
|
|
152
|
+
**Repeater** (N copies with a transform + opacity ramp), **track mattes**
|
|
153
|
+
(`Alpha/Luma`), **transform parenting**, and **time remap** (`tm`).
|
|
154
|
+
- **Nested clips / precomps** (wick/lottie). A clip may hold its own timeline with a
|
|
155
|
+
playback mode (`loop | playOnce | single`) and be instanced - reusable lower-thirds,
|
|
156
|
+
intro/outro stingers; a composable alternative to the flat track list.
|
|
157
|
+
- **Decomposed transform + animatable pivot** (friction). Split transform into
|
|
158
|
+
`pos / scale / rot / shear / pivot / opacity`, each its own keyframe curve, with a
|
|
159
|
+
**movable pivot** for correct scale/rotate around a moving anchor.
|
|
160
|
+
- **Blend-mode / compositing vocabulary** (Natron `MergingFunctionEnum`). The allowed
|
|
161
|
+
`blendMode` values on overlay clips: Porter-Duff (`Over, Under, In, Out, ATop, Copy,
|
|
162
|
+
Matte`) + blends (`Multiply, Screen, Overlay, SoftLight, HardLight, ColorBurn,
|
|
163
|
+
ColorDodge, Difference, Exclusion, Hue, Saturation, Color, Luminosity`).
|
|
164
|
+
- **Xsheet tabular timing** (opentoonz/tahoma2d, **BSD - code reusable with
|
|
165
|
+
attribution, a direct port target**). An optional rows=frames / columns=assets
|
|
166
|
+
exposure grid (cells = a drawing exposed for N frames; a *hold* is the same cell
|
|
167
|
+
repeated). The source implements this (and more of our model than we first credited)
|
|
168
|
+
in `TXsheet` / `TXshCellColumn` (`std::vector<TXshCell> m_cells`) / `TXshCell`
|
|
169
|
+
(`{level, TFrameId}`) / `TFrameId` (`{frame, letter}`), plus the cell-op vocabulary
|
|
170
|
+
(`reverseCells, swingCells, stepCells, reframeCells, timeStretch`). It also backs, as
|
|
171
|
+
BSD code: the **decomposed transform channels** (`TStageObject::Channel` T_X/T_Y/
|
|
172
|
+
T_Angle/T_ScaleX/... each a keyframe curve, with parenting + `T_Path` follow-spline),
|
|
173
|
+
a **richer easing enum** (`TDoubleKeyframe::Type` = Constant / Linear / SpeedInOut /
|
|
174
|
+
EaseInOut / EaseInOutPercentage / Exponential / Expression / File), **nested
|
|
175
|
+
sub-xsheets** (`TXshChildLevel` = precomp), and a **node-graph fx schematic**
|
|
176
|
+
(`FxDag`/`TFx`). So the easing/transform/nested-clip/effect-graph extensions above
|
|
177
|
+
have a BSD implementation to port, not only GPL concept sources.
|
|
178
|
+
- **Strip/effect model + full blend set** (blender VSE `Strip`, concept). The Video
|
|
179
|
+
Sequence Editor's `Strip` (input1/input2, effect strips CROSS/WIPE/GLOW/SPEED/
|
|
180
|
+
ADJUSTMENT/TEXT, a Photoshop-complete `StripBlendMode`) and **F-curve modifier stack**
|
|
181
|
+
(noise/cycles/limits/stepped) + **drivers** (property-driven channels) are strong
|
|
182
|
+
concept borrows for overlay/effect clips.
|
|
183
|
+
- **OTIO interchange** (kdenlive, concept). Document a mapping to OpenTimelineIO (the
|
|
184
|
+
ASWF-standard timeline interchange): gap=blank, stack=track, externalReference=asset
|
|
185
|
+
src - so the model can round-trip with real NLEs.
|
|
186
|
+
- **Optional node-graph "effect graph"** (Natron, concept) for branched layered effects
|
|
187
|
+
(mask -> blur -> merge) that a linear track can't express - heavy; a documented
|
|
188
|
+
escape hatch, not the default.
|
|
@@ -362,3 +362,37 @@ Most are MIT and safe to reference/learn from freely. The four to flag: **GSAP**
|
|
|
362
362
|
(proprietary no-charge), **typed.js** (GPL), **animate.css** (Hippocratic 2.1), and
|
|
363
363
|
**synfig/friction** (GPL desktop tools). For the flagged ones we adopt the *pattern*
|
|
364
364
|
and author our own code.
|
|
365
|
+
|
|
366
|
+
## Authoring motion visually, playing it in code (Theatre.js)
|
|
367
|
+
|
|
368
|
+
[`theatre-js/theatre`](https://github.com/theatre-js/theatre) (Apache-2.0) is a
|
|
369
|
+
motion-design *editor* (`@theatre/studio`) that writes a plain serializable **project
|
|
370
|
+
state**, replayed by a tiny headless runtime (`@theatre/core`) against three.js,
|
|
371
|
+
HTML/SVG, or any JS variable. The borrowable pattern is the **declarative keyframe
|
|
372
|
+
document**, not the editor: store motion as JSON - a `sequence` with `length` +
|
|
373
|
+
`subUnitsPerUnit` (an fps snap-grid) -> **tracks keyed by property path** ->
|
|
374
|
+
**keyframes** each carrying `{ position, value, handles:[lx,ly,rx,ry],
|
|
375
|
+
type:'bezier'|'hold' }` (per-keyframe bezier handles = per-segment easing baked into
|
|
376
|
+
data; `value` may be non-numeric). Playback mirrors CSS: `play({ iterationCount,
|
|
377
|
+
range, rate, direction:'alternateReverse' })`. Author a brand motion once, commit the
|
|
378
|
+
JSON as a reusable asset, replay it deterministically with no editor shipped - the
|
|
379
|
+
authoring story for `maggie-design-motion` (keep the motion *spec* as data, not
|
|
380
|
+
imperative GSAP calls). Reach for it when motion must be re-edited by non-coders or
|
|
381
|
+
reused across pages; a one-shot reveal stays plain CSS/GSAP.
|
|
382
|
+
|
|
383
|
+
## Interactive, input-driven motion (Rive state machines)
|
|
384
|
+
|
|
385
|
+
[`rive-app/rive-runtime`](https://github.com/rive-app/rive-runtime) (MIT) drives
|
|
386
|
+
vector animation with a **state machine** instead of fixed playback - the pattern for
|
|
387
|
+
interactive hero elements, product configurators and mascots. Model: a small **input**
|
|
388
|
+
surface (`bool`, `number`, `trigger`) -> **transitions** guarded by
|
|
389
|
+
**conditions/comparators** (`number > 0.5`, trigger fired) -> **states** (play an
|
|
390
|
+
animation, or a **BlendState1D** that blends along a number input). A **listener**
|
|
391
|
+
layer maps pointer/scroll/keyboard events to input changes; states run in parallel
|
|
392
|
+
**layers**; transitions carry exit-time, ease interpolators, and **random weights**
|
|
393
|
+
for non-repetitive idles. Borrow it in the browser without Rive: model an interactive
|
|
394
|
+
hero as `inputs -> conditions -> states` - declare inputs (`hovered:bool`,
|
|
395
|
+
`scroll:0..1`, `clicked:trigger`), bind DOM events to them, and switch CSS/WAAPI/GSAP
|
|
396
|
+
timelines by state rather than scripting each handler; a number input + interpolation
|
|
397
|
+
gives scroll-linked response, random-picked idle transitions give a "living" element.
|
|
398
|
+
(Rive's own MIT player is also a legitimate option.)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maggie-image
|
|
3
3
|
description: Process marketing images - resize and fit to channel/OG sizes, convert to WebP/AVIF, make favicon and OG-image sets, strip metadata, compress, optimize and render SVG, and build contact-sheet montages. A recipe generator over ImageMagick (primary) with dedicated tools (svgo/resvg/cwebp/avifenc/pngquant) used when installed. Use when the user wants to resize, convert, optimize, favicon, watermark, or batch-process images for a site or social post.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.1.
|
|
5
|
+
version: 0.1.3
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maggie Image
|
|
@@ -58,8 +58,14 @@ maggie tool maggie_image.py presets
|
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
Subcommands: `resize`, `social`, `webp`, `avif`, `favicon`, `strip`, `compress`,
|
|
61
|
-
`svgo`, `svg2png`, `
|
|
62
|
-
|
|
61
|
+
`svgo`, `svg2png`, `svg-export` (Inkscape: PDF/EPS, text-to-path, per-id slicing),
|
|
62
|
+
`composite` (blend-mode layering), `look` (named style presets: sepia/duotone/
|
|
63
|
+
posterize/vignette/...), `montage`, `presets`. `--run` (before the subcommand)
|
|
64
|
+
executes when the tool is present; otherwise the command is printed for review.
|
|
65
|
+
|
|
66
|
+
For reusable, batchable edit *recipes* and generatable scene/diagram formats
|
|
67
|
+
(excalidraw/drawio), the non-destructive edit-stack idea, and SVG-ingest safety, see
|
|
68
|
+
[design editor patterns](../../references/design-editor-patterns.md).
|
|
63
69
|
|
|
64
70
|
## Defaults and quality
|
|
65
71
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maggie-video
|
|
3
3
|
description: Produce and process marketing video - render a composition to MP4/GIF/WebM, assemble clips/images/text/captions/audio on a timeline, cut to channel aspects (reel/square/youtube), burn in captions, normalize loudness, watermark, transcode, and make social cuts. Engine-neutral over the renderer (ffmpeg for assembly/transcode, a programmatic engine for code-drawn animation). Use when the user wants to make, edit, cut, caption, resize, or export a video for marketing.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.1.
|
|
5
|
+
version: 0.1.5
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maggie Video
|
|
@@ -10,7 +10,7 @@ and are generate-only until it is installed. Web-delivery quality defaults follo
|
|
|
10
10
|
sharp/squoosh (JPEG/WebP ~80, AVIF ~50); OG/social are cover-cropped, logos pad.
|
|
11
11
|
|
|
12
12
|
Subcommands: resize, social, webp, avif, favicon, strip, compress, svgo, svg2png,
|
|
13
|
-
montage, presets.
|
|
13
|
+
svg-export, composite, look, montage, presets.
|
|
14
14
|
"""
|
|
15
15
|
import argparse
|
|
16
16
|
import shlex
|
|
@@ -59,18 +59,25 @@ def _resize_ops(w, h, mode, pad):
|
|
|
59
59
|
|
|
60
60
|
def c_resize(a):
|
|
61
61
|
w, h = a.size.lower().split("x")
|
|
62
|
-
cmd = _im() + [a.input, "-strip"] + _resize_ops(w, h, a.mode, a.pad) + \
|
|
62
|
+
cmd = _im() + [a.input, "-auto-orient", "-strip"] + _resize_ops(w, h, a.mode, a.pad) + \
|
|
63
63
|
["-quality", str(a.quality), a.output]
|
|
64
64
|
return emit(cmd, a.run, _im_tool())
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
def c_social(a):
|
|
68
68
|
w, h = SOCIAL[a.preset]
|
|
69
|
-
cmd = _im() + [a.input, "-strip"] + _resize_ops(w, h, a.mode, a.pad) + \
|
|
69
|
+
cmd = _im() + [a.input, "-auto-orient", "-strip"] + _resize_ops(w, h, a.mode, a.pad) + \
|
|
70
70
|
["-quality", str(a.quality), a.output]
|
|
71
71
|
return emit(cmd, a.run, _im_tool())
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
def c_trim(a):
|
|
75
|
+
"""Trim uniform border / cut a product or logo out of its background
|
|
76
|
+
(ImageMagick -fuzz -trim; +repage resets the virtual canvas)."""
|
|
77
|
+
cmd = _im() + [a.input, "-auto-orient", "-fuzz", f"{a.fuzz}%", "-trim", "+repage", a.output]
|
|
78
|
+
return emit(cmd, a.run, _im_tool())
|
|
79
|
+
|
|
80
|
+
|
|
74
81
|
def c_webp(a):
|
|
75
82
|
if shutil.which("cwebp") and not a.force_im:
|
|
76
83
|
return emit(["cwebp", "-q", str(a.quality), "-m", "6", a.input, "-o", a.output], a.run, "cwebp")
|
|
@@ -152,6 +159,63 @@ def c_montage(a):
|
|
|
152
159
|
return emit(cmd, a.run, _montage()[0])
|
|
153
160
|
|
|
154
161
|
|
|
162
|
+
def c_svg_export(a):
|
|
163
|
+
"""Inkscape headless export - fills the gaps resvg/ImageMagick can't: text-to-path
|
|
164
|
+
font outlining, PDF/EPS for print, and per-id slicing. GPL app, invoked at arm's
|
|
165
|
+
length (like ImageMagick)."""
|
|
166
|
+
args = ["inkscape", a.input, f"--export-type={a.type}", f"--export-filename={a.output}"]
|
|
167
|
+
if a.width:
|
|
168
|
+
args.append(f"--export-width={a.width}")
|
|
169
|
+
if a.dpi:
|
|
170
|
+
args.append(f"--export-dpi={a.dpi}")
|
|
171
|
+
if a.area == "drawing":
|
|
172
|
+
args.append("--export-area-drawing")
|
|
173
|
+
elif a.area == "page":
|
|
174
|
+
args.append("--export-area-page")
|
|
175
|
+
if a.id:
|
|
176
|
+
args += [f"--export-id={a.id}", "--export-id-only"]
|
|
177
|
+
if a.text_to_path:
|
|
178
|
+
args.append("--export-text-to-path")
|
|
179
|
+
if a.background:
|
|
180
|
+
args += [f"--export-background={a.background}", "--export-background-opacity=1"]
|
|
181
|
+
print("# Inkscape: text-to-path outlining (font-independent handoff), PDF/EPS, per-id slicing.")
|
|
182
|
+
return emit(args, a.run, "inkscape")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def c_composite(a):
|
|
186
|
+
"""Layer an overlay onto a base with a blend mode (Pinta/Natron vocabulary ->
|
|
187
|
+
ImageMagick -compose). Modes: Over, Multiply, Screen, Overlay, Darken, Lighten,
|
|
188
|
+
ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion."""
|
|
189
|
+
cmd = _im() + [a.base, a.overlay]
|
|
190
|
+
if a.gravity:
|
|
191
|
+
cmd += ["-gravity", a.gravity]
|
|
192
|
+
cmd += ["-compose", a.mode, "-composite", a.output]
|
|
193
|
+
return emit(cmd, a.run, _im_tool())
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
LOOKS = {
|
|
197
|
+
"grayscale": ["-colorspace", "Gray"],
|
|
198
|
+
"sepia": ["-sepia-tone", "80%"],
|
|
199
|
+
"posterize": ["-posterize", "4"],
|
|
200
|
+
"oilpaint": ["-paint", "4"],
|
|
201
|
+
"sketch": ["-colorspace", "Gray", "-charcoal", "1"],
|
|
202
|
+
"vignette": ["-background", "black", "-vignette", "0x20"],
|
|
203
|
+
"blur": ["-blur", "0x8"],
|
|
204
|
+
"sharpen": ["-unsharp", "0x1.5"],
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def c_look(a):
|
|
209
|
+
"""Apply a named 'look' (a reusable, non-destructive style preset; the darktable
|
|
210
|
+
edit-recipe idea in a single op). `duotone` maps shadows->--dark, highlights->--light."""
|
|
211
|
+
if a.look == "duotone":
|
|
212
|
+
ops = ["-colorspace", "Gray", "-level-colors", f"{a.dark},{a.light}"]
|
|
213
|
+
else:
|
|
214
|
+
ops = LOOKS[a.look]
|
|
215
|
+
cmd = _im() + [a.input, "-strip"] + ops + [a.output]
|
|
216
|
+
return emit(cmd, a.run, _im_tool())
|
|
217
|
+
|
|
218
|
+
|
|
155
219
|
def c_presets(a):
|
|
156
220
|
print("Social/OG size presets (use with `social --preset <name>`; cover-cropped):")
|
|
157
221
|
for name, (w, h) in SOCIAL.items():
|
|
@@ -196,6 +260,9 @@ def main(argv=None):
|
|
|
196
260
|
fv.add_argument("--input", required=True); fv.add_argument("--out-dir", dest="out_dir", required=True)
|
|
197
261
|
fv.set_defaults(fn=c_favicon)
|
|
198
262
|
|
|
263
|
+
tr = sub.add_parser("trim", help="trim border / cut product out of its background")
|
|
264
|
+
io(tr); tr.add_argument("--fuzz", type=int, default=5, help="color tolerance %%"); tr.set_defaults(fn=c_trim)
|
|
265
|
+
|
|
199
266
|
st = sub.add_parser("strip", help="strip metadata (EXIF/GPS/ICC)"); io(st); st.set_defaults(fn=c_strip)
|
|
200
267
|
co = sub.add_parser("compress", help="compress JPEG/PNG"); io(co)
|
|
201
268
|
co.add_argument("--quality", type=int, default=82); co.set_defaults(fn=c_compress)
|
|
@@ -211,6 +278,26 @@ def main(argv=None):
|
|
|
211
278
|
mo.add_argument("--pad", type=int, default=10); mo.add_argument("--background", default="#ffffff")
|
|
212
279
|
mo.set_defaults(fn=c_montage)
|
|
213
280
|
|
|
281
|
+
se = sub.add_parser("svg-export", help="Inkscape headless export (pdf/eps/png/svg, text-to-path, by-id)")
|
|
282
|
+
se.add_argument("--input", required=True); se.add_argument("--output", required=True)
|
|
283
|
+
se.add_argument("--type", default="png", help="png,pdf,ps,eps,svg")
|
|
284
|
+
se.add_argument("--width", type=int); se.add_argument("--dpi", type=int)
|
|
285
|
+
se.add_argument("--area", choices=["drawing", "page"], default="drawing")
|
|
286
|
+
se.add_argument("--id", help="export only this element/layer id")
|
|
287
|
+
se.add_argument("--text-to-path", dest="text_to_path", action="store_true", help="outline fonts")
|
|
288
|
+
se.add_argument("--background"); se.set_defaults(fn=c_svg_export)
|
|
289
|
+
|
|
290
|
+
cp = sub.add_parser("composite", help="layer an overlay on a base with a blend mode")
|
|
291
|
+
cp.add_argument("--base", required=True); cp.add_argument("--overlay", required=True)
|
|
292
|
+
cp.add_argument("--output", required=True); cp.add_argument("--mode", default="Over")
|
|
293
|
+
cp.add_argument("--gravity"); cp.set_defaults(fn=c_composite)
|
|
294
|
+
|
|
295
|
+
lk = sub.add_parser("look", help="apply a named look (sepia/duotone/posterize/vignette/...)")
|
|
296
|
+
lk.add_argument("--input", required=True); lk.add_argument("--output", required=True)
|
|
297
|
+
lk.add_argument("--look", choices=list(LOOKS) + ["duotone"], required=True)
|
|
298
|
+
lk.add_argument("--dark", default="#1a1a2e"); lk.add_argument("--light", default="#e94560")
|
|
299
|
+
lk.set_defaults(fn=c_look)
|
|
300
|
+
|
|
214
301
|
sub.add_parser("presets", help="list size presets").set_defaults(fn=c_presets)
|
|
215
302
|
|
|
216
303
|
a = ap.parse_args(argv)
|
|
@@ -511,17 +511,20 @@ def c_captions(a):
|
|
|
511
511
|
cmd = [tool, "-m", a.model, "-f", a.input, "-osrt", "-of",
|
|
512
512
|
os.path.join(out_dir, base)]
|
|
513
513
|
print(f"# whisper.cpp writes {os.path.join(out_dir, base)}.srt; --model is the .bin path")
|
|
514
|
-
|
|
515
|
-
tool = "whisperx"
|
|
516
|
-
cmd = [tool, a.input, "--model", a.model, "--output_format",
|
|
514
|
+
else: # openai-whisper (default) / whisperx - same flag surface
|
|
515
|
+
tool = "whisperx" if a.engine == "whisperx" else "whisper"
|
|
516
|
+
cmd = [tool, a.input, "--model", a.model, "--output_format", a.format,
|
|
517
517
|
"--output_dir", out_dir] + lang
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
518
|
+
if a.word_timestamps:
|
|
519
|
+
cmd += ["--word_timestamps", "True"]
|
|
520
|
+
if a.highlight_words:
|
|
521
|
+
cmd += ["--highlight_words", "True"] # karaoke-style per-word highlight
|
|
522
|
+
if a.initial_prompt:
|
|
523
|
+
cmd += ["--initial_prompt", a.initial_prompt] # bias brand/product spellings
|
|
524
|
+
print(f"# {tool} writes {os.path.join(out_dir, base)}.{a.format} in --output_dir; "
|
|
525
|
+
f"openai-whisper's default model is now 'turbo' (large-v3-turbo).")
|
|
526
|
+
print("# transcription is local/offline (no paid API); a larger model is slower but better.")
|
|
527
|
+
print("# --highlight-words gives karaoke captions; --initial-prompt fixes brand-term spelling.")
|
|
525
528
|
print("# then: maggie_video.py subtitle --input video.mp4 --srt <that>.srt --output out.mp4 (burn in)")
|
|
526
529
|
return emit(cmd, a.run, tool=tool)
|
|
527
530
|
|
|
@@ -602,11 +605,16 @@ def main(argv=None):
|
|
|
602
605
|
ac.add_argument("--margin", type=float, default=0.1, help="padding kept around speech (s)")
|
|
603
606
|
ac.set_defaults(fn=c_autocut)
|
|
604
607
|
|
|
605
|
-
ca = sub.add_parser("captions", help="transcribe speech to SRT (local whisper)")
|
|
606
|
-
ca.add_argument("--input", required=True); ca.add_argument("--output", required=True, help="target
|
|
608
|
+
ca = sub.add_parser("captions", help="transcribe speech to SRT/VTT (local whisper)")
|
|
609
|
+
ca.add_argument("--input", required=True); ca.add_argument("--output", required=True, help="target caption file")
|
|
607
610
|
ca.add_argument("--engine", choices=["whisper", "whispercpp", "whisperx"], default="whisper")
|
|
608
|
-
ca.add_argument("--model", default="
|
|
609
|
-
ca.add_argument("--
|
|
611
|
+
ca.add_argument("--model", default="turbo", help="model (openai-whisper default 'turbo'); .bin path for whispercpp")
|
|
612
|
+
ca.add_argument("--format", default="srt", help="srt|vtt|txt|tsv|json (openai-whisper/whisperx)")
|
|
613
|
+
ca.add_argument("--lang", default="auto")
|
|
614
|
+
ca.add_argument("--word-timestamps", dest="word_timestamps", action="store_true")
|
|
615
|
+
ca.add_argument("--highlight-words", dest="highlight_words", action="store_true", help="karaoke per-word highlight")
|
|
616
|
+
ca.add_argument("--initial-prompt", dest="initial_prompt", help="bias brand/product term spelling")
|
|
617
|
+
ca.set_defaults(fn=c_captions)
|
|
610
618
|
|
|
611
619
|
sub.add_parser("presets", help="list channel aspect presets").set_defaults(fn=c_presets)
|
|
612
620
|
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ Distilled from the reference library's R-category projects.
|
|
|
9
9
|
|
|
10
10
|
| Engine | What / how | License | Reach for it when |
|
|
11
11
|
|---|---|---|---|
|
|
12
|
-
| openai-whisper |
|
|
12
|
+
| openai-whisper | `whisper IN --model turbo --output_format srt --output_dir DIR` (default model is now **`turbo`** = large-v3-turbo; formats `txt/vtt/srt/tsv/json`) | MIT | the default; simplest install (`pip install openai-whisper`) |
|
|
13
13
|
| whisper.cpp | C/C++ port, fast on CPU, GGML models: `whisper-cli -m model.bin -f IN -osrt -of OUTBASE` | MIT | no GPU / fastest CPU / embedding in a pipeline |
|
|
14
14
|
| whisperX | whisper + forced alignment for **word-level timestamps** and diarization: `whisperx IN --model large-v3 --output_format srt --output_dir DIR` | BSD-4 | word-accurate caption timing or speaker labels |
|
|
15
15
|
|
|
@@ -38,4 +38,24 @@ Model size trades speed for accuracy: `tiny` / `base` (fast, rough) -> `small` /
|
|
|
38
38
|
API is ever wired in instead, the global spend-first rule applies - state the cost.
|
|
39
39
|
- Keep caption text inside the safe area (see `maggie-video` channel presets).
|
|
40
40
|
|
|
41
|
+
## Caption-shaping flags (built into openai-whisper)
|
|
42
|
+
|
|
43
|
+
The core CLI already does what we previously routed to whisperX or post-processing
|
|
44
|
+
(`maggie_video.py captions` exposes these):
|
|
45
|
+
|
|
46
|
+
- `--word_timestamps True` - word-level timings (whisperX still wins on alignment +
|
|
47
|
+
diarization, but core whisper now has them).
|
|
48
|
+
- `--highlight_words True` - **karaoke-style** per-word highlight in SRT/VTT (the
|
|
49
|
+
social-caption effect); render the ASS with ffmpeg `subtitles`.
|
|
50
|
+
- `--max_line_width` / `--max_line_count` / `--max_words_per_line` - native line
|
|
51
|
+
wrapping so captions fit the channel safe-area, no post-processing.
|
|
52
|
+
- `--initial_prompt "<brand, product names>"` - bias the model toward correct brand/
|
|
53
|
+
jargon spelling (the concrete mitigation for the mishears-brand-terms risk; still
|
|
54
|
+
human-review).
|
|
55
|
+
- Anti-hallucination over music/silence: `--hallucination_silence_threshold`,
|
|
56
|
+
`--compression_ratio_threshold`, `--logprob_threshold`, `--no_speech_threshold` -
|
|
57
|
+
worth setting for music-bed marketing clips.
|
|
58
|
+
- `--task translate` (foreign audio -> English subs), `--clip_timestamps` (only given
|
|
59
|
+
ranges).
|
|
60
|
+
|
|
41
61
|
See `maggie-video` for the subcommands and the burn-in / soft-mux / compile options.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Design-editor patterns
|
|
2
|
+
|
|
3
|
+
Borrowable logic and creativity from open-source design, whiteboard, vector and raster
|
|
4
|
+
**editors** (reference library category P), for making and handling marketing visuals
|
|
5
|
+
programmatically. We adopt **concepts and data shapes, not code** (most are GPL/AGPL/
|
|
6
|
+
MPL or custom-licensed; the few MIT ones are reimplemented, not bulk-copied). Pairs
|
|
7
|
+
with [image recipes](image-recipes.md), [generative visuals](generative-visuals.md),
|
|
8
|
+
and [AI media generation](ai-media-generation.md).
|
|
9
|
+
|
|
10
|
+
## Non-destructive edit recipe (darktable)
|
|
11
|
+
|
|
12
|
+
darktable (GPL) edits by a **replayable history stack of named module invocations**,
|
|
13
|
+
stored in an **XMP sidecar** beside the untouched original - never mutating the source;
|
|
14
|
+
the image is reconstructed by replaying the stack. Borrow this as a maggie "image edit
|
|
15
|
+
recipe": a small JSON `[ {op, params}, ... ]` stored next to the original and replayed
|
|
16
|
+
by `maggie_image.py` (each op -> an ImageMagick/sharp command). It is **reproducible,
|
|
17
|
+
auditable, re-editable, and batchable** - apply one "look" recipe to every photo in a
|
|
18
|
+
campaign for consistent brand grading. `darktable-cli <input> [sidecar.xmp]
|
|
19
|
+
<output-dir>` renders from such a stack (XMP optional/auto-discovered, final arg is a
|
|
20
|
+
**directory**; GPL binary, arm's-length). Two source details worth adopting: **params
|
|
21
|
+
versioning** (each module keeps `legacy_params` for forward-compatible migration -
|
|
22
|
+
version your recipe ops) and **"Styles" = saved reusable history** (name a look once,
|
|
23
|
+
apply to many).
|
|
24
|
+
|
|
25
|
+
## LLM-generatable scene / diagram formats
|
|
26
|
+
|
|
27
|
+
- **Excalidraw** (`.excalidraw` JSON, MIT) - a flat list of elements (`{type:
|
|
28
|
+
rectangle|ellipse|diamond|text|line|arrow|freedraw|image|frame, x, y, width, height,
|
|
29
|
+
strokeColor, backgroundColor, fillStyle, roughness, seed, roundness, groupIds,
|
|
30
|
+
boundElements}`) with a separate `files` asset map and ratio-based arrow/label
|
|
31
|
+
bindings that survive resize. **Emit it from a prompt** for diagrams, flowcharts,
|
|
32
|
+
annotated screenshots -> open in-app or render to SVG/PNG, with an on-brand hand-drawn
|
|
33
|
+
(rough.js) look.
|
|
34
|
+
- **drawio / mxGraph** (`mxGraphModel` XML, Apache-2.0 code; diagram output
|
|
35
|
+
unrestricted) - `<mxCell>` nodes with `value` (label), a compact `style` DSL
|
|
36
|
+
(`rounded=1;fillColor=#dae8fc;strokeColor=#6c8ebf;`), `vertex="1"` or `edge="1"` with
|
|
37
|
+
`source`/`target`, and `<mxGeometry>`. Trivially generatable for org charts, funnels,
|
|
38
|
+
architecture diagrams; render headless to SVG/PNG (don't redistribute their icon/
|
|
39
|
+
stencil sets).
|
|
40
|
+
|
|
41
|
+
## SVG as the document (Method-Draw) + safe ingest
|
|
42
|
+
|
|
43
|
+
Method-Draw (MIT, from SVG-Edit) treats the **live SVG DOM as the single source of
|
|
44
|
+
truth** - `XMLSerializer` is the save format; no separate scene JSON. Two borrows:
|
|
45
|
+
(a) the simplest possible model for programmatic marketing SVGs (build the DOM,
|
|
46
|
+
serialize); (b) a **sanitize whitelist** (`svgWhiteList_`) of allowed SVG elements/
|
|
47
|
+
attributes - essential for safely ingesting user- or AI-supplied SVG before rendering
|
|
48
|
+
(strips scripts/unknowns); pair with svgo in [image recipes](image-recipes.md). Its
|
|
49
|
+
command `apply/unapply` history is the generic edit-history pattern (and the backbone
|
|
50
|
+
of the edit-recipe above).
|
|
51
|
+
|
|
52
|
+
## Design-doc patterns (penpot, tldraw)
|
|
53
|
+
|
|
54
|
+
- **penpot** (MPL, concept) - a design doc in **open standards (SVG/CSS/HTML/JSON)**
|
|
55
|
+
with first-class **Design Tokens as the single source of truth** between brand and
|
|
56
|
+
code, **Components + Variants** (one card, many variants = reusable marketing
|
|
57
|
+
templates), CSS Grid/Flex layout on the doc, and an **MCP server** making the doc
|
|
58
|
+
agent-readable. Strong alignment with Maggie's brand-kit + MCP posture.
|
|
59
|
+
- **tldraw** (custom license, concept) - an infinite-canvas **reactive record store**
|
|
60
|
+
of typed shape records (geometry + props + `parentId` + fractional index) with
|
|
61
|
+
bindings/assets/pages, and the explicit framing that **an LLM agent operates on the
|
|
62
|
+
canvas document as data** - reinforcing the "generate the scene JSON" approach.
|
|
63
|
+
|
|
64
|
+
## AI-edit vocabulary (krita-ai-diffusion)
|
|
65
|
+
|
|
66
|
+
krita-ai-diffusion (GPL, concept) bolts generative AI onto a layer/selection editor
|
|
67
|
+
over a ComfyUI backend. The borrowable vocabulary for precise AI image edits (beyond
|
|
68
|
+
full-frame generation): **mask/selection-scoped generative fill** (inpaint, expand,
|
|
69
|
+
add/remove inside a region), **layer-as-region prompting** (a text prompt per image
|
|
70
|
+
area defined by a layer), and **conditioning** via ControlNet (scribble/lineart/canny/
|
|
71
|
+
pose/depth/segmentation) and IP-Adapter (reference image, style/composition transfer).
|
|
72
|
+
The plugin-over-backend boundary (editor model stays; AI is a swappable backend)
|
|
73
|
+
mirrors the arm's-length posture in [AI media generation](ai-media-generation.md).
|
|
74
|
+
|
|
75
|
+
## Licensing
|
|
76
|
+
|
|
77
|
+
Invoke binaries at arm's length (never vendor): inkscape, darktable (GPL). Concepts
|
|
78
|
+
only: penpot (MPL), tldraw (custom), krita/krita-ai-diffusion (GPL), drawio icon sets.
|
|
79
|
+
MIT and freely borrowable as ideas (still reimplement, don't bulk-copy): excalidraw,
|
|
80
|
+
Method-Draw, rough.js, Pinta. drawio code Apache-2.0; its diagram output is
|
|
81
|
+
unrestricted.
|
|
82
|
+
|
|
83
|
+
## From full-source study (net-new)
|
|
84
|
+
|
|
85
|
+
- **tldraw** - the LLM mutation surface is `editor.createShapes/updateShapes/
|
|
86
|
+
deleteShapes` (batch partial mutations); the store ships schema **migration
|
|
87
|
+
sequences**, a composable **validation layer**, and a **side-effects manager**
|
|
88
|
+
(before/after create/change/delete hooks). `parentId` can be a page *or* a shape;
|
|
89
|
+
pages carry a fractional `index`. Adopt the batch-mutation + validate + migrate
|
|
90
|
+
shape as the model for an agent-written canvas doc.
|
|
91
|
+
- **penpot** - **design tokens are W3C DTCG** (import/export + aliasing), components
|
|
92
|
+
have **variants**, shapes carry **flex/grid layout**; the agent boundary is an
|
|
93
|
+
**official MCP server talking to a sandboxed in-app plugin over WebSocket** - a
|
|
94
|
+
strong arm's-length model for making a design doc agent-writable (mirrors Maggie's
|
|
95
|
+
own MCP posture).
|
|
96
|
+
- **drawio** - the `mxConstants` STYLE_* key table is a **validated allow-list** for
|
|
97
|
+
LLM-emitted styles; `mxEdgeStyle` routing + hierarchical/tree/organic **auto-layout**
|
|
98
|
+
mean a generated node+edge list can self-position; `.drawio` pages are often
|
|
99
|
+
**deflate+base64** compressed.
|
|
100
|
+
- **krita** - an **adjustment/filter layer holds a serialized filter config** = a
|
|
101
|
+
non-destructive recipe living in the layer stack; ops are **mask/selection-scoped**;
|
|
102
|
+
`.kra` is `zip(manifest XML + per-layer blobs)`; a **Python scripting API** and a
|
|
103
|
+
JSON-manifest plugin boundary let a generative backend register like any filter -
|
|
104
|
+
the "AI as a swappable backend" posture.
|
|
@@ -128,3 +128,24 @@ maggie tool maggie_video.py compile --spec timeline.json # declarative timelin
|
|
|
128
128
|
maggie tool maggie_video.py --run encode --input in.mov --output out.mp4 # actually runs
|
|
129
129
|
maggie tool maggie_video.py presets
|
|
130
130
|
```
|
|
131
|
+
|
|
132
|
+
## More filters worth reaching for (confirmed in libavfilter)
|
|
133
|
+
|
|
134
|
+
- **Green-screen / keying** (UGC, product on a brand background):
|
|
135
|
+
`chromakey=0x00FF00:0.1:0.0` (or `colorkey`), clean fringes with `despill`.
|
|
136
|
+
- **Fade to/from black** (distinct from clip crossfade): `fade=t=in:st=0:d=0.5`,
|
|
137
|
+
`fade=t=out:st=9.5:d=0.5`.
|
|
138
|
+
- **Brand color grade / LUT**: `lut3d=brand.cube`, or `curves`/`eq`/`colorbalance`/`hue`.
|
|
139
|
+
- **Karaoke captions**: `subtitles=in.ass` with a full ASS file (word highlight) -
|
|
140
|
+
pairs with whisper `--highlight_words` ([captions](captions-transcription.md)).
|
|
141
|
+
- **Focus/credits**: `gblur` + `vignette`; `scroll` for scrolling outros.
|
|
142
|
+
- **GPU fast path** when hardware is present: `overlay_cuda`/`overlay_vulkan`,
|
|
143
|
+
`xfade_opencl` for long renders.
|
|
144
|
+
|
|
145
|
+
## Target-filesize social presets (HandBrake idea)
|
|
146
|
+
|
|
147
|
+
Beyond aspect, encode to **fit under a platform's upload cap**: pick a two-pass video
|
|
148
|
+
bitrate from the cap and duration - `bitrate_bits = size_bytes * 8 / duration - audio`
|
|
149
|
+
- e.g. "25 MB / 30 s / 1080p". A named preset bundles `(upload cap, max duration) ->
|
|
150
|
+
resolution + bitrate`. (HandBrake ships exactly these as "Social 25 MB 30 Seconds"
|
|
151
|
+
presets.)
|
|
@@ -92,3 +92,53 @@ zdog, pts, hydra, regl, Babylon.js, react-three-fiber, fogleman/primitive, svg.j
|
|
|
92
92
|
nannou - licenses in the table above. Capture pipeline: see
|
|
93
93
|
[programmatic video](programmatic-video.md), [design-motion production](design-motion-production.md),
|
|
94
94
|
[ffmpeg recipes](ffmpeg-recipes.md).
|
|
95
|
+
|
|
96
|
+
## More patterns (from the desktop/editor study)
|
|
97
|
+
|
|
98
|
+
- **The shared sketch model** (processing / openFrameworks / nannou / p5): a `setup()`
|
|
99
|
+
once + per-frame `draw()` loop with seeded `random()/noise()`. openFrameworks (MIT)
|
|
100
|
+
splits it into `setup()/update()/draw()` (sim vs render); nannou (MIT/Apache)
|
|
101
|
+
formalizes Model-Update-View. The reusable discipline: **keep state separate from the
|
|
102
|
+
render fn, index by frame, seed all randomness** - that is what makes a loop
|
|
103
|
+
reproducible and headless-capturable. Default to p5/three/regl in the browser;
|
|
104
|
+
reach for a desktop framework only for heavy GPU throughput or offline high-res
|
|
105
|
+
render the browser can't sustain. (Processing non-core is GPL - reimplement.)
|
|
106
|
+
- **Hand-drawn scene JSON (excalidraw, MIT).** `.excalidraw` is a flat list of
|
|
107
|
+
elements (`{type, x, y, w, h, strokeColor, backgroundColor, fillStyle:
|
|
108
|
+
hachure|cross-hatch|solid|zigzag, roughness, seed, roundness}`) rendered with
|
|
109
|
+
rough.js. It is **LLM-generatable**: emit the JSON for a diagram/flowchart/annotated
|
|
110
|
+
screenshot, then render to SVG/PNG. The rough.js mapping for an on-brand hand-made
|
|
111
|
+
look: `seed` (determinism), `fillStyle`, `fillWeight = strokeWidth/2`,
|
|
112
|
+
`hachureGap = strokeWidth*4`, `roughness`, `disableMultiStroke` for non-solid strokes.
|
|
113
|
+
- **Vector shape morphing** (synfig concept): tween between two paths by interpolating
|
|
114
|
+
each control point's vertex + in/out tangents + width - smooth logo/blob/path morphs.
|
|
115
|
+
- **Repeater / radial stamp** (Lottie concept): one shape -> N transformed copies with
|
|
116
|
+
an incremental transform + opacity ramp (bursts, confetti, radial brand patterns) -
|
|
117
|
+
cheap, on-brand, deterministic.
|
|
118
|
+
- For AI-assisted editing vocabulary (mask/selection-scoped generation, layer-as-region
|
|
119
|
+
prompting, ControlNet/IP-Adapter conditioning), see
|
|
120
|
+
[AI media generation](ai-media-generation.md) and
|
|
121
|
+
[design editor patterns](design-editor-patterns.md).
|
|
122
|
+
|
|
123
|
+
### Headless capture + 3D export (from full-source study)
|
|
124
|
+
|
|
125
|
+
How to render these engines **without a screen**, and extra output formats worth
|
|
126
|
+
knowing:
|
|
127
|
+
|
|
128
|
+
- **Babylon.js `NullEngine`** (Apache-2.0) - first-class **server-side headless**
|
|
129
|
+
rendering (no GPU/canvas); the cleanest headless story for render-automation jobs,
|
|
130
|
+
plus a built-in **procedural-texture library** (brick/cloud/fire/marble/noise/wood),
|
|
131
|
+
`CreateScreenshotUsingRenderTarget` for 4K+ stills from a small viewport, and
|
|
132
|
+
**NodeMaterial** (shaders serialize to JSON - an LLM-emittable look). This is the
|
|
133
|
+
concrete reason to pick Babylon over three for automation.
|
|
134
|
+
- **three.js** (MIT) - `readRenderTargetPixels()`/`...Async` read pixels from an
|
|
135
|
+
offscreen `WebGLRenderTarget` (true headless high-res, not on-screen canvas);
|
|
136
|
+
**SVGRenderer** emits a 3D scene as editable SVG; **USDZExporter** turns a 3D product
|
|
137
|
+
into a free **iOS AR Quick Look** asset; **GPUComputationRenderer** (ping-pong FBO
|
|
138
|
+
sim: flocking/fluid) = a living, seeded generative hero background.
|
|
139
|
+
- **openFrameworks** (MIT) - `ofFbo` offscreen framebuffer for arbitrary-res stills;
|
|
140
|
+
**ofxEmscripten** compiles a desktop sketch to WebAssembly for the browser;
|
|
141
|
+
**ofxSvg** parses + emits structured SVG.
|
|
142
|
+
- **Processing** - `PSurfaceNone` (headless) and `createGraphics(big)` (render larger
|
|
143
|
+
than the screen -> high-res still). License at feature granularity: core raster is
|
|
144
|
+
LGPL, but **SVG/PDF export is in non-core (GPL)** - reimplement, don't vendor.
|
|
@@ -87,3 +87,50 @@ sharp (Apache-2.0), squoosh codecs (Apache-2.0), imagemin (MIT), cwebp/avifenc
|
|
|
87
87
|
(BSD). **Avoid vendoring code from** Upscayl (AGPL-3.0) - for AI upscaling invoke the
|
|
88
88
|
separate `realesrgan-ncnn-vulkan` binary instead. sharp/squoosh quality defaults are
|
|
89
89
|
adopted as the preset numbers.
|
|
90
|
+
|
|
91
|
+
## SVG beyond resvg/ImageMagick (Inkscape, arm's-length)
|
|
92
|
+
|
|
93
|
+
Inkscape's headless CLI (GPL app, invoked like ImageMagick) fills gaps resvg and IM
|
|
94
|
+
can't: **font outlining, PDF/EPS, and per-id slicing**. `maggie_image.py svg-export`
|
|
95
|
+
generates these.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
inkscape in.svg --export-type=png --export-filename=out.png --export-width=1200 \
|
|
99
|
+
--export-area-drawing --export-background=#ffffff --export-background-opacity=1
|
|
100
|
+
inkscape in.svg --export-type=pdf --export-filename=out.pdf # print collateral
|
|
101
|
+
inkscape in.svg --export-text-to-path --export-type=svg --export-filename=flat.svg # outline fonts for handoff
|
|
102
|
+
inkscape in.svg --export-id=badge --export-id-only --export-type=png --export-filename=badge.png # slice one element
|
|
103
|
+
inkscape in.svg --export-type=png --export-dpi=300 --export-area-page --export-filename=print.png
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Layered composite + named looks (Pinta vocabulary)
|
|
107
|
+
|
|
108
|
+
Blend modes map from a raster editor's layer stack onto ImageMagick `-compose`:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
convert base.png overlay.png -gravity center -compose Multiply -composite out.png
|
|
112
|
+
# modes: Over, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
|
|
113
|
+
# HardLight, SoftLight, Difference, Exclusion
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Named "looks" (each a one-line style preset - a lightweight take on darktable's
|
|
117
|
+
non-destructive edit recipe): `grayscale` (`-colorspace Gray`), `sepia`
|
|
118
|
+
(`-sepia-tone 80%`), `posterize` (`-posterize 4`), `duotone` (`-colorspace Gray
|
|
119
|
+
-level-colors '#1a1a2e','#e94560'`), `vignette` (`-background black -vignette 0x20`),
|
|
120
|
+
`oilpaint` (`-paint 4`), `sketch` (`-colorspace Gray -charcoal 1`), `blur`/`sharpen`.
|
|
121
|
+
`maggie_image.py composite` and `maggie_image.py look` generate these. For a
|
|
122
|
+
reusable, batchable edit *recipe* (a JSON stack of named ops applied to many photos),
|
|
123
|
+
see [design editor patterns](design-editor-patterns.md).
|
|
124
|
+
|
|
125
|
+
## More ImageMagick ops worth baking in (confirmed in source)
|
|
126
|
+
|
|
127
|
+
- **`-auto-orient`** first in every pipeline - fixes sideways phone photos by EXIF
|
|
128
|
+
(`maggie_image.py` resize/social/trim already prepend it).
|
|
129
|
+
- **`-thumbnail WxH`** - metadata-stripping fast resize; a better default than
|
|
130
|
+
`-resize` for web/OG thumbnails.
|
|
131
|
+
- **`-fuzz N% -trim +repage`** - trim a uniform border or cut a product/logo out of
|
|
132
|
+
its background (`maggie_image.py trim`).
|
|
133
|
+
- **`-clut` / `-hald-clut`** - repeatable LUT brand grading (raster equivalent of
|
|
134
|
+
ffmpeg `lut3d`).
|
|
135
|
+
- **`-distort perspective '<src coords> <dst coords>'`** - place a screenshot into a
|
|
136
|
+
device mockup.
|
|
@@ -78,3 +78,25 @@ apply.
|
|
|
78
78
|
`libx264 -crf 14-20 -preset slow/medium -pix_fmt yuv420p -movflags +faststart`,
|
|
79
79
|
even dimensions, plus 960px / 800x500 GIF deliverables. For transparent output,
|
|
80
80
|
Revideo uses per-format pixel formats (`yuva420p` WebM, `yuva444p10le` ProRes).
|
|
81
|
+
|
|
82
|
+
## Remotion's real renderer (from source) and the ideas to borrow
|
|
83
|
+
|
|
84
|
+
Source study (Remotion License - concept only, no vendoring) shows Remotion is **not**
|
|
85
|
+
the base64-PNG pipe we lump with Revideo/Motion Canvas: it drives headless Chromium
|
|
86
|
+
over CDP, captures frames via **shared memory**, and encodes with a **per-platform
|
|
87
|
+
native Rust sidecar that statically links FFmpeg** (a long-running streaming process),
|
|
88
|
+
plus a bundled `ffmpeg` for the final stitch. Borrowable ideas (improve our Part C):
|
|
89
|
+
|
|
90
|
+
- **A readiness gate, not just a fake clock.** `delayRender()`/`continueRender()`: a
|
|
91
|
+
component declares async work pending and the renderer blocks the screenshot until
|
|
92
|
+
all handles clear, reporting **labeled** open handles on timeout. Add an explicit
|
|
93
|
+
readiness handshake (plus a per-frame `await document.fonts.ready`) to Part C so no
|
|
94
|
+
frame is captured before fonts/data/images are ready - prevents FOUT/half-loaded
|
|
95
|
+
frames.
|
|
96
|
+
- **Tab-pool concurrency**: open N browser pages, each seeking a different frame in
|
|
97
|
+
parallel (frame range / N).
|
|
98
|
+
- **Chunked parallel encode + seamless concat**: split the frame range, encode chunks
|
|
99
|
+
independently, concat without re-encode - throughput for long renders.
|
|
100
|
+
- **Kept-open, LRU-cached source-video decoders**: for embedded video assets, keep the
|
|
101
|
+
decoder open and cache frames so repeated seeks to a timestamp are cheap (our flat
|
|
102
|
+
timeline currently punts this to raw ffmpeg `-ss`).
|
|
@@ -130,3 +130,59 @@ arm's length, never linked or vendored.
|
|
|
130
130
|
keyframe/ease vocabulary, the licensing note - stable and engine-neutral.
|
|
131
131
|
- **`maggie-video` skill:** channel presets, caption/CTA safe-areas, the operational
|
|
132
132
|
ffmpeg command layer (via `maggie_video.py`), and tool wiring.
|
|
133
|
+
|
|
134
|
+
## Extensions from the animation-tool study (O-category)
|
|
135
|
+
|
|
136
|
+
Concepts to grow the model (adopt the data shape / vocabulary; code only from the
|
|
137
|
+
MIT/BSD sources - rlottie MIT, opentoonz/tahoma2d BSD; synfig/friction/wick/Natron
|
|
138
|
+
GPL = concept only):
|
|
139
|
+
|
|
140
|
+
- **Richer keyframe easing** (synfig). Extend `{t, v, ease}` with: **per-side ease**
|
|
141
|
+
(`easeIn` != `easeOut`), **`clamped`** (auto-smooth that won't overshoot the keyed
|
|
142
|
+
value), **`hold`/`constant`**, and optional **TCB** `{tension, continuity, bias}`.
|
|
143
|
+
Add **`fullRotations`** on a rotation keyframe (wick) to control spin count/direction
|
|
144
|
+
rather than shortest-path. These precompute to per-frame values for ffmpeg and map to
|
|
145
|
+
CSS/Lottie beziers. (compile currently interpolates linearly; this is the target
|
|
146
|
+
vocabulary.)
|
|
147
|
+
- **Lottie JSON as the companion vector-motion-graphics format** (rlottie, MIT). For
|
|
148
|
+
logo stings, animated icons and kinetic type, use Lottie (After-Effects/Figma
|
|
149
|
+
exportable, in-browser renderable via lottie-web) alongside the MLT/NLE shape. Borrow
|
|
150
|
+
its primitives: **Trim-path** (`start%/end%/offset` - the formal version of the
|
|
151
|
+
"draw a line on" trick in [design-motion production](design-motion-production.md)),
|
|
152
|
+
**Repeater** (N copies with a transform + opacity ramp), **track mattes**
|
|
153
|
+
(`Alpha/Luma`), **transform parenting**, and **time remap** (`tm`).
|
|
154
|
+
- **Nested clips / precomps** (wick/lottie). A clip may hold its own timeline with a
|
|
155
|
+
playback mode (`loop | playOnce | single`) and be instanced - reusable lower-thirds,
|
|
156
|
+
intro/outro stingers; a composable alternative to the flat track list.
|
|
157
|
+
- **Decomposed transform + animatable pivot** (friction). Split transform into
|
|
158
|
+
`pos / scale / rot / shear / pivot / opacity`, each its own keyframe curve, with a
|
|
159
|
+
**movable pivot** for correct scale/rotate around a moving anchor.
|
|
160
|
+
- **Blend-mode / compositing vocabulary** (Natron `MergingFunctionEnum`). The allowed
|
|
161
|
+
`blendMode` values on overlay clips: Porter-Duff (`Over, Under, In, Out, ATop, Copy,
|
|
162
|
+
Matte`) + blends (`Multiply, Screen, Overlay, SoftLight, HardLight, ColorBurn,
|
|
163
|
+
ColorDodge, Difference, Exclusion, Hue, Saturation, Color, Luminosity`).
|
|
164
|
+
- **Xsheet tabular timing** (opentoonz/tahoma2d, **BSD - code reusable with
|
|
165
|
+
attribution, a direct port target**). An optional rows=frames / columns=assets
|
|
166
|
+
exposure grid (cells = a drawing exposed for N frames; a *hold* is the same cell
|
|
167
|
+
repeated). The source implements this (and more of our model than we first credited)
|
|
168
|
+
in `TXsheet` / `TXshCellColumn` (`std::vector<TXshCell> m_cells`) / `TXshCell`
|
|
169
|
+
(`{level, TFrameId}`) / `TFrameId` (`{frame, letter}`), plus the cell-op vocabulary
|
|
170
|
+
(`reverseCells, swingCells, stepCells, reframeCells, timeStretch`). It also backs, as
|
|
171
|
+
BSD code: the **decomposed transform channels** (`TStageObject::Channel` T_X/T_Y/
|
|
172
|
+
T_Angle/T_ScaleX/... each a keyframe curve, with parenting + `T_Path` follow-spline),
|
|
173
|
+
a **richer easing enum** (`TDoubleKeyframe::Type` = Constant / Linear / SpeedInOut /
|
|
174
|
+
EaseInOut / EaseInOutPercentage / Exponential / Expression / File), **nested
|
|
175
|
+
sub-xsheets** (`TXshChildLevel` = precomp), and a **node-graph fx schematic**
|
|
176
|
+
(`FxDag`/`TFx`). So the easing/transform/nested-clip/effect-graph extensions above
|
|
177
|
+
have a BSD implementation to port, not only GPL concept sources.
|
|
178
|
+
- **Strip/effect model + full blend set** (blender VSE `Strip`, concept). The Video
|
|
179
|
+
Sequence Editor's `Strip` (input1/input2, effect strips CROSS/WIPE/GLOW/SPEED/
|
|
180
|
+
ADJUSTMENT/TEXT, a Photoshop-complete `StripBlendMode`) and **F-curve modifier stack**
|
|
181
|
+
(noise/cycles/limits/stepped) + **drivers** (property-driven channels) are strong
|
|
182
|
+
concept borrows for overlay/effect clips.
|
|
183
|
+
- **OTIO interchange** (kdenlive, concept). Document a mapping to OpenTimelineIO (the
|
|
184
|
+
ASWF-standard timeline interchange): gap=blank, stack=track, externalReference=asset
|
|
185
|
+
src - so the model can round-trip with real NLEs.
|
|
186
|
+
- **Optional node-graph "effect graph"** (Natron, concept) for branched layered effects
|
|
187
|
+
(mask -> blur -> merge) that a linear track can't express - heavy; a documented
|
|
188
|
+
escape hatch, not the default.
|
|
@@ -362,3 +362,37 @@ Most are MIT and safe to reference/learn from freely. The four to flag: **GSAP**
|
|
|
362
362
|
(proprietary no-charge), **typed.js** (GPL), **animate.css** (Hippocratic 2.1), and
|
|
363
363
|
**synfig/friction** (GPL desktop tools). For the flagged ones we adopt the *pattern*
|
|
364
364
|
and author our own code.
|
|
365
|
+
|
|
366
|
+
## Authoring motion visually, playing it in code (Theatre.js)
|
|
367
|
+
|
|
368
|
+
[`theatre-js/theatre`](https://github.com/theatre-js/theatre) (Apache-2.0) is a
|
|
369
|
+
motion-design *editor* (`@theatre/studio`) that writes a plain serializable **project
|
|
370
|
+
state**, replayed by a tiny headless runtime (`@theatre/core`) against three.js,
|
|
371
|
+
HTML/SVG, or any JS variable. The borrowable pattern is the **declarative keyframe
|
|
372
|
+
document**, not the editor: store motion as JSON - a `sequence` with `length` +
|
|
373
|
+
`subUnitsPerUnit` (an fps snap-grid) -> **tracks keyed by property path** ->
|
|
374
|
+
**keyframes** each carrying `{ position, value, handles:[lx,ly,rx,ry],
|
|
375
|
+
type:'bezier'|'hold' }` (per-keyframe bezier handles = per-segment easing baked into
|
|
376
|
+
data; `value` may be non-numeric). Playback mirrors CSS: `play({ iterationCount,
|
|
377
|
+
range, rate, direction:'alternateReverse' })`. Author a brand motion once, commit the
|
|
378
|
+
JSON as a reusable asset, replay it deterministically with no editor shipped - the
|
|
379
|
+
authoring story for `maggie-design-motion` (keep the motion *spec* as data, not
|
|
380
|
+
imperative GSAP calls). Reach for it when motion must be re-edited by non-coders or
|
|
381
|
+
reused across pages; a one-shot reveal stays plain CSS/GSAP.
|
|
382
|
+
|
|
383
|
+
## Interactive, input-driven motion (Rive state machines)
|
|
384
|
+
|
|
385
|
+
[`rive-app/rive-runtime`](https://github.com/rive-app/rive-runtime) (MIT) drives
|
|
386
|
+
vector animation with a **state machine** instead of fixed playback - the pattern for
|
|
387
|
+
interactive hero elements, product configurators and mascots. Model: a small **input**
|
|
388
|
+
surface (`bool`, `number`, `trigger`) -> **transitions** guarded by
|
|
389
|
+
**conditions/comparators** (`number > 0.5`, trigger fired) -> **states** (play an
|
|
390
|
+
animation, or a **BlendState1D** that blends along a number input). A **listener**
|
|
391
|
+
layer maps pointer/scroll/keyboard events to input changes; states run in parallel
|
|
392
|
+
**layers**; transitions carry exit-time, ease interpolators, and **random weights**
|
|
393
|
+
for non-repetitive idles. Borrow it in the browser without Rive: model an interactive
|
|
394
|
+
hero as `inputs -> conditions -> states` - declare inputs (`hovered:bool`,
|
|
395
|
+
`scroll:0..1`, `clicked:trigger`), bind DOM events to them, and switch CSS/WAAPI/GSAP
|
|
396
|
+
timelines by state rather than scripting each handler; a number input + interpolation
|
|
397
|
+
gives scroll-linked response, random-picked idle transitions give a "living" element.
|
|
398
|
+
(Rive's own MIT player is also a legitimate option.)
|