@topy-ai/maggie 0.8.11 → 0.8.12
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 +2 -2
- package/bundled-references/captions-transcription.md +41 -0
- package/bundled-references/generative-visuals.md +90 -0
- package/bundled-references/image-recipes.md +89 -0
- package/bundled-references/web-animation-patterns.md +364 -0
- package/bundled-skills/catalog.json +4 -0
- package/bundled-skills/maggie-design/SKILL.md +7 -2
- package/bundled-skills/maggie-design-motion/SKILL.md +4 -1
- package/bundled-skills/maggie-image/SKILL.md +100 -0
- package/bundled-skills/maggie-landing-page/SKILL.md +5 -1
- package/bundled-skills/maggie-spirit/SKILL.md +4 -2
- package/bundled-skills/maggie-video/SKILL.md +3 -2
- package/bundled-tools/clis/maggie_image.py +221 -0
- package/package.json +1 -1
- package/references/captions-transcription.md +41 -0
- package/references/generative-visuals.md +90 -0
- package/references/image-recipes.md +89 -0
- package/references/web-animation-patterns.md +364 -0
|
@@ -66,6 +66,10 @@
|
|
|
66
66
|
"name": "maggie-fundraising",
|
|
67
67
|
"description": "Fundraising and investor relations for a founder - draft a pitch deck and narrative, assemble a data room, write investor updates, keep cap-table and round hygiene, and prepare SEIS/EIS materials. Use when the user asks to prepare to raise, build a deck or data room, write an investor update, or organise round documents. Factual only; not securities, investment, legal, or tax advice. Pairs with maggie-finance and the TOPY/CEO tools."
|
|
68
68
|
},
|
|
69
|
+
{
|
|
70
|
+
"name": "maggie-image",
|
|
71
|
+
"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."
|
|
72
|
+
},
|
|
69
73
|
{
|
|
70
74
|
"name": "maggie-landing-page",
|
|
71
75
|
"description": "Build a high-converting landing page - intake, page structure, layout selection, conversion copy, SEO/AEO, plus a visual-system discipline (typography, spacing, radius, backgrounds, hero, icons, motion) whose specific values are defaults the project's DESIGN.md overrides. Use when building, editing, styling, or writing copy for a landing page, marketing page, or a page section meant to convert. Designs the page; maggie-design produces and validates it."
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maggie-design
|
|
3
3
|
description: Design authorized interior pages, review rendered responsive layouts, explicitly rebrand a packaged homepage/template, or audit and upgrade an existing site/app in place (fix generic AI-design patterns, weak states, and sloppy code). Use rebrand only with a named source brand and target brand. Use the redesign audit whenever the user wants to improve, polish, upgrade, refine, audit, or redesign an existing page, even when they just say it looks cheap, generic, or AI-made.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 1.7.
|
|
5
|
+
version: 1.7.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maggie Design
|
|
@@ -21,7 +21,12 @@ Concrete values come from
|
|
|
21
21
|
overridden by the project's own DESIGN.md/tokens. For building a new landing page
|
|
22
22
|
from scratch use [`maggie-landing-page`](../maggie-landing-page/SKILL.md); for
|
|
23
23
|
turning a design into an animated showcase use
|
|
24
|
-
[`maggie-design-motion`](../maggie-design-motion/SKILL.md).
|
|
24
|
+
[`maggie-design-motion`](../maggie-design-motion/SKILL.md). For page visuals and
|
|
25
|
+
assets: process images with [`maggie-image`](../maggie-image/SKILL.md)
|
|
26
|
+
([recipes](../../references/image-recipes.md)), add motion from
|
|
27
|
+
[web animation patterns](../../references/web-animation-patterns.md), and generate
|
|
28
|
+
code-drawn backgrounds/3D/stylized art from
|
|
29
|
+
[generative visuals](../../references/generative-visuals.md).
|
|
25
30
|
|
|
26
31
|
## In-place route evidence
|
|
27
32
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maggie-design-motion
|
|
3
3
|
description: Turn a static design (a Figma frame, screenshot, dashboard, card set, app screen, or a UI on a photo) into a pixel-exact HTML replica that loads from an empty state, then has every visual act out what it does in a seamless loop, and export an MP4 plus GIFs. Use when asked to animate a design, a Figma link, a screenshot, UI cards, a dashboard or hero image, or to make a showcase loop, motion mockup, or a video/GIF of a design. Also for bento/feature cards on a landing page.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.1.
|
|
5
|
+
version: 0.1.2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maggie Design Motion
|
|
@@ -287,6 +287,9 @@ size/dimensions/fps/duration; anything not reproduced exactly, named plainly.
|
|
|
287
287
|
- `maggie-spirit` - deterministic brand sprites/avatars (a different motion job).
|
|
288
288
|
- `maggie-landing-page` / `maggie-design` - where website motion lives and is
|
|
289
289
|
produced.
|
|
290
|
+
- [web animation patterns](../../references/web-animation-patterns.md) - the motion
|
|
291
|
+
vocabulary for the website context; [generative visuals](../../references/generative-visuals.md)
|
|
292
|
+
- code-drawn visuals you capture through this skill's Part C.
|
|
290
293
|
|
|
291
294
|
# Credits
|
|
292
295
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: maggie-image
|
|
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
|
+
metadata:
|
|
5
|
+
version: 0.1.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Maggie Image
|
|
9
|
+
|
|
10
|
+
The image-asset lane: turn a source image into the correctly-sized, correctly-
|
|
11
|
+
formatted, metadata-clean asset a site or social post needs. It is a **recipe
|
|
12
|
+
generator** like `maggie-video` - it prints the exact command (reviewable/loggable)
|
|
13
|
+
and runs it with `--run` when the tool is on PATH. It **invokes binaries at arm's
|
|
14
|
+
length** (no GPL code vendored).
|
|
15
|
+
|
|
16
|
+
This is image *processing*. For generating *new* visuals from a prompt see
|
|
17
|
+
`maggie media generate` (and the Q-category AI tools); for brand marks/avatars see
|
|
18
|
+
`maggie-spirit`; for generative/3D/stylized visuals see
|
|
19
|
+
[generative visuals](../../references/generative-visuals.md). Responsive-variant
|
|
20
|
+
manifests are `maggie_images.py` (a different concern).
|
|
21
|
+
|
|
22
|
+
Follow the [Maggie Memory Hook](../../references/memory-hook.md) at invocation and
|
|
23
|
+
completion.
|
|
24
|
+
|
|
25
|
+
## When to use
|
|
26
|
+
|
|
27
|
+
- Resize/crop an image to a channel or OG size (1200x630, 1080x1080, 9:16, ...).
|
|
28
|
+
- Convert to WebP/AVIF for faster pages.
|
|
29
|
+
- Make a favicon set and OG/social images.
|
|
30
|
+
- Strip EXIF/GPS metadata, compress, or optimize before publishing.
|
|
31
|
+
- Optimize an SVG (svgo) or render one to PNG (resvg).
|
|
32
|
+
- Build a contact sheet / grid for a carousel.
|
|
33
|
+
|
|
34
|
+
## Tool posture
|
|
35
|
+
|
|
36
|
+
ImageMagick (`magick` on IM7, else `convert`) is the primary path - almost always
|
|
37
|
+
present and covers nearly every raster op. Dedicated tools give better bytes-per-
|
|
38
|
+
quality and are used **automatically when installed**: `cwebp`/`avifenc` (encode),
|
|
39
|
+
`pngquant` (lossy PNG), `svgo` (SVG optimize), `resvg`/`rsvg-convert` (SVG render).
|
|
40
|
+
`--force-im` forces the ImageMagick path. Full commands are in
|
|
41
|
+
[image recipes](../../references/image-recipes.md).
|
|
42
|
+
|
|
43
|
+
## CLI
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
maggie tool maggie_image.py social --input hero.png --output og.jpg --preset og # 1200x630 cover-crop
|
|
47
|
+
maggie tool maggie_image.py resize --input a.jpg --output a.jpg --size 1080x1080 --mode cover
|
|
48
|
+
maggie tool maggie_image.py --run webp --input hero.png --output hero.webp --quality 80
|
|
49
|
+
maggie tool maggie_image.py --run avif --input hero.png --output hero.avif
|
|
50
|
+
maggie tool maggie_image.py --run favicon --input logo.png --out-dir public/
|
|
51
|
+
maggie tool maggie_image.py --run strip --input photo.jpg --output photo.jpg
|
|
52
|
+
maggie tool maggie_image.py --run compress --input big.jpg --output small.jpg --quality 82
|
|
53
|
+
maggie tool maggie_image.py svgo --input logo.svg --output logo.min.svg --multipass
|
|
54
|
+
maggie tool maggie_image.py svg2png --input logo.svg --output logo.png --width 512
|
|
55
|
+
maggie tool maggie_image.py --run montage --inputs a.png b.png c.png --output sheet.jpg --tile 3x
|
|
56
|
+
maggie tool maggie_image.py presets
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Subcommands: `resize`, `social`, `webp`, `avif`, `favicon`, `strip`, `compress`,
|
|
60
|
+
`svgo`, `svg2png`, `montage`, `presets`. `--run` (before the subcommand) executes
|
|
61
|
+
when the tool is present; otherwise the command is printed for review.
|
|
62
|
+
|
|
63
|
+
## Defaults and quality
|
|
64
|
+
|
|
65
|
+
- Metadata **stripped** on public assets (privacy + bytes).
|
|
66
|
+
- JPEG/WebP quality ~80, AVIF ~50 (sharp/squoosh web-delivery defaults).
|
|
67
|
+
- OG/social are **cover-cropped** (fill, no distortion); logos **contain-pad**.
|
|
68
|
+
- Favicon: `.ico` (64/48/32/16) + PNG set (16/32/48/180-apple-touch/192/512).
|
|
69
|
+
- SVG: svgo keeps `viewBox` and `title` (responsive + accessible); never rasterize an
|
|
70
|
+
SVG as a substitute for optimizing it.
|
|
71
|
+
|
|
72
|
+
## Quality bar
|
|
73
|
+
|
|
74
|
+
- Output is the exact target size with no distortion; cover vs pad chosen for the
|
|
75
|
+
content (photos crop, logos pad).
|
|
76
|
+
- Public images carry no EXIF/GPS; file sizes are web-appropriate (WebP/AVIF offered).
|
|
77
|
+
- SVGs stay vector and keep `viewBox`; a rendered PNG is only made on request.
|
|
78
|
+
- Every command is printed/logged before (or instead of) running.
|
|
79
|
+
|
|
80
|
+
## Guardrails
|
|
81
|
+
|
|
82
|
+
- Local tools only; invoke `convert`/`magick` and dedicated binaries at arm's length;
|
|
83
|
+
never vendor GPL/AGPL code (e.g. Upscayl is AGPL - for AI upscaling invoke the
|
|
84
|
+
separate `realesrgan-ncnn-vulkan` binary instead).
|
|
85
|
+
- Do not claim a file was produced unless `--run` executed and it exists.
|
|
86
|
+
- Do not upscale/alter a logo or product shot in a way that misrepresents it; keep
|
|
87
|
+
brand assets faithful.
|
|
88
|
+
- Reproducing copyrighted or third-party imagery is the caller's responsibility.
|
|
89
|
+
|
|
90
|
+
## Related skills
|
|
91
|
+
|
|
92
|
+
- `maggie-video` - the moving-image counterpart (same recipe-generator pattern).
|
|
93
|
+
- `maggie-spirit` - brand marks/avatars; `maggie-design` - where assets are placed
|
|
94
|
+
and the icon/responsive gates run.
|
|
95
|
+
- `maggie media generate` - generating new images from a prompt.
|
|
96
|
+
- [generative visuals](../../references/generative-visuals.md) - making visuals in code.
|
|
97
|
+
|
|
98
|
+
## Boundaries
|
|
99
|
+
|
|
100
|
+
- Processing and optimization only; generation and placement live in other lanes.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maggie-landing-page
|
|
3
3
|
description: Build a high-converting landing page - intake, page structure, layout selection, conversion copy, SEO/AEO, plus a visual-system discipline (typography, spacing, radius, backgrounds, hero, icons, motion) whose specific values are defaults the project's DESIGN.md overrides. Use when building, editing, styling, or writing copy for a landing page, marketing page, or a page section meant to convert. Designs the page; maggie-design produces and validates it.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.1.
|
|
5
|
+
version: 0.1.2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maggie Landing Page
|
|
@@ -156,6 +156,10 @@ icon inventory + glyph-render gates before release.
|
|
|
156
156
|
|
|
157
157
|
## B7. Motion
|
|
158
158
|
|
|
159
|
+
The motion vocabulary (eases, scroll-reveal, stagger, SVG draw-on, typing, page
|
|
160
|
+
transitions, Lottie, particles) with per-library guidance is in
|
|
161
|
+
[web animation patterns](../../references/web-animation-patterns.md).
|
|
162
|
+
|
|
159
163
|
Weighted, decelerating motion; never a browser-default curve. Default base curve
|
|
160
164
|
`cubic-bezier(0.22,1,0.36,1)` ~500ms for layout/position; 300ms (never under 200ms)
|
|
161
165
|
for hover colour/opacity. Animate only `transform`/`opacity`. Respect
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: maggie-spirit
|
|
3
3
|
description: Generate an AI brand's flat-pixel spirit (sprite) system - a logo mark that animates through a fixed 32-state base set, and per-agent avatar faces animated through the same states. Use for agent/brand avatars, logo marks, sprite-sheet and sprite-animation assets, and a shared motion vocabulary across Core and Service agents.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.1.
|
|
5
|
+
version: 0.1.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maggie Spirit
|
|
@@ -14,7 +14,9 @@ states** (power, work, comms, outcome, gov). Agents differ only by their
|
|
|
14
14
|
and status badges stay identical so a state reads the same everywhere.
|
|
15
15
|
|
|
16
16
|
Everything is deterministic (seeded by accent + persona) and self-contained
|
|
17
|
-
(Pillow only - no model calls, no per-image cost).
|
|
17
|
+
(Pillow only - no model calls, no per-image cost). For code-drawn generative
|
|
18
|
+
visuals (backgrounds, 3D, stylized photos) beyond the brand mark, see
|
|
19
|
+
[generative visuals](../../references/generative-visuals.md). It pairs with
|
|
18
20
|
[agent goal-led design](../../references/agent-goal-design.md): design the agent,
|
|
19
21
|
then give it a spirit.
|
|
20
22
|
|
|
@@ -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.4
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Maggie Video
|
|
@@ -92,7 +92,8 @@ paid API):
|
|
|
92
92
|
toggleable track.
|
|
93
93
|
|
|
94
94
|
Never fabricate a transcript; generate it from the real audio and have a human
|
|
95
|
-
review before publishing.
|
|
95
|
+
review before publishing. Engine choice and the full flow are in
|
|
96
|
+
[captions and transcription](../../references/captions-transcription.md).
|
|
96
97
|
|
|
97
98
|
## Channel presets and safe areas
|
|
98
99
|
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""maggie_image - generate correct image-processing commands for marketing assets.
|
|
3
|
+
|
|
4
|
+
A recipe generator distilled from ImageMagick, sharp, svgo, resvg, squoosh and
|
|
5
|
+
imagemin (see references/image-recipes.md). Each subcommand prints the exact command
|
|
6
|
+
(reviewable/loggable) and runs it with --run only when the tool is on PATH. Raster
|
|
7
|
+
ops prefer ImageMagick (`magick` on IM7, else `convert`) since it is almost always
|
|
8
|
+
present and covers nearly everything; vector ops use the dedicated tool (svgo, resvg)
|
|
9
|
+
and are generate-only until it is installed. Web-delivery quality defaults follow
|
|
10
|
+
sharp/squoosh (JPEG/WebP ~80, AVIF ~50); OG/social are cover-cropped, logos pad.
|
|
11
|
+
|
|
12
|
+
Subcommands: resize, social, webp, avif, favicon, strip, compress, svgo, svg2png,
|
|
13
|
+
montage, presets.
|
|
14
|
+
"""
|
|
15
|
+
import argparse
|
|
16
|
+
import shlex
|
|
17
|
+
import shutil
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
# OG/social use cover-crop; name -> (W, H)
|
|
22
|
+
SOCIAL = {"og": (1200, 630), "twitter": (1600, 900), "square": (1080, 1080),
|
|
23
|
+
"story": (1080, 1920), "reel": (1080, 1920), "landscape": (1920, 1080),
|
|
24
|
+
"linkedin": (1200, 627), "pinterest": (1000, 1500)}
|
|
25
|
+
FAVICON_PNG = [16, 32, 48, 180, 192, 512] # 180 = apple-touch
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _im():
|
|
29
|
+
return ["magick"] if shutil.which("magick") else ["convert"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _im_tool():
|
|
33
|
+
return _im()[0]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _montage():
|
|
37
|
+
return ["magick", "montage"] if shutil.which("magick") else ["montage"]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def emit(args, run, tool):
|
|
41
|
+
print(" ".join(shlex.quote(a) for a in args))
|
|
42
|
+
if not run:
|
|
43
|
+
return 0
|
|
44
|
+
if not shutil.which(tool):
|
|
45
|
+
sys.stderr.write(f"{tool} not found on PATH; printed the command only.\n")
|
|
46
|
+
return 3
|
|
47
|
+
return subprocess.run(args).returncode
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _resize_ops(w, h, mode, pad):
|
|
51
|
+
if mode == "cover":
|
|
52
|
+
return ["-resize", f"{w}x{h}^", "-gravity", "center", "-extent", f"{w}x{h}"]
|
|
53
|
+
if mode == "contain":
|
|
54
|
+
return ["-resize", f"{w}x{h}", "-background", pad, "-gravity", "center", "-extent", f"{w}x{h}"]
|
|
55
|
+
if mode == "shrink":
|
|
56
|
+
return ["-resize", f"{w}x{h}>"]
|
|
57
|
+
return ["-resize", f"{w}x{h}"] # fit
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def c_resize(a):
|
|
61
|
+
w, h = a.size.lower().split("x")
|
|
62
|
+
cmd = _im() + [a.input, "-strip"] + _resize_ops(w, h, a.mode, a.pad) + \
|
|
63
|
+
["-quality", str(a.quality), a.output]
|
|
64
|
+
return emit(cmd, a.run, _im_tool())
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def c_social(a):
|
|
68
|
+
w, h = SOCIAL[a.preset]
|
|
69
|
+
cmd = _im() + [a.input, "-strip"] + _resize_ops(w, h, a.mode, a.pad) + \
|
|
70
|
+
["-quality", str(a.quality), a.output]
|
|
71
|
+
return emit(cmd, a.run, _im_tool())
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def c_webp(a):
|
|
75
|
+
if shutil.which("cwebp") and not a.force_im:
|
|
76
|
+
return emit(["cwebp", "-q", str(a.quality), "-m", "6", a.input, "-o", a.output], a.run, "cwebp")
|
|
77
|
+
cmd = _im() + [a.input, "-strip", "-quality", str(a.quality), "-define", "webp:method=6", a.output]
|
|
78
|
+
return emit(cmd, a.run, _im_tool())
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def c_avif(a):
|
|
82
|
+
if shutil.which("avifenc") and not a.force_im:
|
|
83
|
+
return emit(["avifenc", "-s", "6", "--min", "20", "--max", "40", a.input, a.output], a.run, "avifenc")
|
|
84
|
+
cmd = _im() + [a.input, "-strip", "-quality", str(a.quality), a.output]
|
|
85
|
+
return emit(cmd, a.run, _im_tool())
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def c_favicon(a):
|
|
89
|
+
import os
|
|
90
|
+
os.makedirs(a.out_dir, exist_ok=True)
|
|
91
|
+
rc = 0
|
|
92
|
+
ico = os.path.join(a.out_dir, "favicon.ico")
|
|
93
|
+
rc |= emit(_im() + [a.input, "-define", "icon:auto-resize=64,48,32,16", ico], a.run, _im_tool())
|
|
94
|
+
for s in FAVICON_PNG:
|
|
95
|
+
name = "apple-touch-icon.png" if s == 180 else f"favicon-{s}.png"
|
|
96
|
+
out = os.path.join(a.out_dir, name)
|
|
97
|
+
rc |= emit(_im() + [a.input, "-strip", "-resize", f"{s}x{s}", out], a.run, _im_tool())
|
|
98
|
+
return rc
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def c_strip(a):
|
|
102
|
+
return emit(_im() + [a.input, "-strip", a.output], a.run, _im_tool())
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def c_compress(a):
|
|
106
|
+
out = a.output.lower()
|
|
107
|
+
if out.endswith((".jpg", ".jpeg")):
|
|
108
|
+
cmd = _im() + [a.input, "-strip", "-interlace", "Plane", "-quality", str(a.quality), a.output]
|
|
109
|
+
else: # png: palette-reduce + max zlib (pngquant is the better alt)
|
|
110
|
+
if shutil.which("pngquant") and not a.force_im:
|
|
111
|
+
return emit(["pngquant", "--quality", "60-82", "--strip", "--force",
|
|
112
|
+
"--output", a.output, a.input], a.run, "pngquant")
|
|
113
|
+
cmd = _im() + [a.input, "-strip", "-colors", "256",
|
|
114
|
+
"-define", "png:compression-level=9", a.output]
|
|
115
|
+
return emit(cmd, a.run, _im_tool())
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def c_svgo(a):
|
|
119
|
+
args = ["svgo", "--multipass"] if a.multipass else ["svgo"]
|
|
120
|
+
args += ["-i", a.input, "-o", a.output]
|
|
121
|
+
print("# svgo keeps viewBox and title by default (responsive + accessible).")
|
|
122
|
+
if not shutil.which("svgo"):
|
|
123
|
+
print("# svgo not installed (npm i -g svgo). Do NOT rasterize an SVG as a substitute.")
|
|
124
|
+
return emit(args, a.run, "svgo")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def c_svg2png(a):
|
|
128
|
+
if shutil.which("resvg") and not a.force_im:
|
|
129
|
+
args = ["resvg"]
|
|
130
|
+
if a.width:
|
|
131
|
+
args += ["-w", str(a.width)]
|
|
132
|
+
if a.background:
|
|
133
|
+
args += ["--background", a.background]
|
|
134
|
+
args += [a.input, a.output]
|
|
135
|
+
return emit(args, a.run, "resvg")
|
|
136
|
+
if shutil.which("rsvg-convert") and not a.force_im:
|
|
137
|
+
args = ["rsvg-convert"]
|
|
138
|
+
if a.width:
|
|
139
|
+
args += ["-w", str(a.width)]
|
|
140
|
+
return emit(args + [a.input, "-o", a.output], a.run, "rsvg-convert")
|
|
141
|
+
# ImageMagick fallback: drive size via -density (it rasterizes at DPI); lower fidelity
|
|
142
|
+
dens = 384
|
|
143
|
+
bg = ["-background", a.background] if a.background else ["-background", "none"]
|
|
144
|
+
size = ["-resize", f"{a.width}x"] if a.width else []
|
|
145
|
+
print("# ImageMagick SVG fallback is lower fidelity; install resvg for correct rendering.")
|
|
146
|
+
return emit(_im() + bg + ["-density", str(dens), a.input] + size + [a.output], a.run, _im_tool())
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def c_montage(a):
|
|
150
|
+
cmd = _montage() + list(a.inputs) + ["-tile", a.tile, "-geometry",
|
|
151
|
+
f"{a.cell}+{a.pad}+{a.pad}", "-background", a.background, a.output]
|
|
152
|
+
return emit(cmd, a.run, _montage()[0])
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def c_presets(a):
|
|
156
|
+
print("Social/OG size presets (use with `social --preset <name>`; cover-cropped):")
|
|
157
|
+
for name, (w, h) in SOCIAL.items():
|
|
158
|
+
print(f" {name:<10} {w}x{h}")
|
|
159
|
+
print("\nDefaults: strip metadata; JPEG/WebP quality 80, AVIF 50; favicon .ico "
|
|
160
|
+
"(64/48/32/16) + PNG set (16/32/48/180-apple/192/512).")
|
|
161
|
+
print(f"ImageMagick binary detected: {_im_tool()}")
|
|
162
|
+
return 0
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def main(argv=None):
|
|
166
|
+
ap = argparse.ArgumentParser(prog="maggie_image", description=__doc__,
|
|
167
|
+
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
168
|
+
ap.add_argument("--run", action="store_true", help="execute (needs the tool on PATH); default prints only")
|
|
169
|
+
ap.add_argument("--force-im", action="store_true", dest="force_im",
|
|
170
|
+
help="force the ImageMagick path even if a dedicated tool exists")
|
|
171
|
+
sub = ap.add_subparsers(dest="cmd", required=True)
|
|
172
|
+
|
|
173
|
+
def io(p, out=True):
|
|
174
|
+
p.add_argument("--input", required=True)
|
|
175
|
+
if out:
|
|
176
|
+
p.add_argument("--output", required=True)
|
|
177
|
+
|
|
178
|
+
r = sub.add_parser("resize", help="resize+fit to WxH")
|
|
179
|
+
io(r); r.add_argument("--size", required=True, help="WxH, e.g. 1200x630")
|
|
180
|
+
r.add_argument("--mode", choices=["cover", "contain", "fit", "shrink"], default="cover")
|
|
181
|
+
r.add_argument("--pad", default="#ffffff"); r.add_argument("--quality", type=int, default=82)
|
|
182
|
+
r.set_defaults(fn=c_resize)
|
|
183
|
+
|
|
184
|
+
s = sub.add_parser("social", help="resize to a channel/OG preset")
|
|
185
|
+
io(s); s.add_argument("--preset", choices=list(SOCIAL), required=True)
|
|
186
|
+
s.add_argument("--mode", choices=["cover", "contain", "fit", "shrink"], default="cover")
|
|
187
|
+
s.add_argument("--pad", default="#ffffff"); s.add_argument("--quality", type=int, default=82)
|
|
188
|
+
s.set_defaults(fn=c_social)
|
|
189
|
+
|
|
190
|
+
w = sub.add_parser("webp", help="encode WebP"); io(w)
|
|
191
|
+
w.add_argument("--quality", type=int, default=80); w.set_defaults(fn=c_webp)
|
|
192
|
+
av = sub.add_parser("avif", help="encode AVIF"); io(av)
|
|
193
|
+
av.add_argument("--quality", type=int, default=50); av.set_defaults(fn=c_avif)
|
|
194
|
+
|
|
195
|
+
fv = sub.add_parser("favicon", help="favicon .ico + PNG set")
|
|
196
|
+
fv.add_argument("--input", required=True); fv.add_argument("--out-dir", dest="out_dir", required=True)
|
|
197
|
+
fv.set_defaults(fn=c_favicon)
|
|
198
|
+
|
|
199
|
+
st = sub.add_parser("strip", help="strip metadata (EXIF/GPS/ICC)"); io(st); st.set_defaults(fn=c_strip)
|
|
200
|
+
co = sub.add_parser("compress", help="compress JPEG/PNG"); io(co)
|
|
201
|
+
co.add_argument("--quality", type=int, default=82); co.set_defaults(fn=c_compress)
|
|
202
|
+
|
|
203
|
+
so = sub.add_parser("svgo", help="optimize an SVG (svgo)"); io(so)
|
|
204
|
+
so.add_argument("--multipass", action="store_true"); so.set_defaults(fn=c_svgo)
|
|
205
|
+
sp = sub.add_parser("svg2png", help="render SVG -> PNG (resvg)"); io(sp)
|
|
206
|
+
sp.add_argument("--width", type=int); sp.add_argument("--background"); sp.set_defaults(fn=c_svg2png)
|
|
207
|
+
|
|
208
|
+
mo = sub.add_parser("montage", help="contact sheet / grid")
|
|
209
|
+
mo.add_argument("--inputs", nargs="+", required=True); mo.add_argument("--output", required=True)
|
|
210
|
+
mo.add_argument("--tile", default="3x"); mo.add_argument("--cell", default="400x400")
|
|
211
|
+
mo.add_argument("--pad", type=int, default=10); mo.add_argument("--background", default="#ffffff")
|
|
212
|
+
mo.set_defaults(fn=c_montage)
|
|
213
|
+
|
|
214
|
+
sub.add_parser("presets", help="list size presets").set_defaults(fn=c_presets)
|
|
215
|
+
|
|
216
|
+
a = ap.parse_args(argv)
|
|
217
|
+
raise SystemExit(a.fn(a))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
if __name__ == "__main__":
|
|
221
|
+
main()
|
package/package.json
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Captions and transcription
|
|
2
|
+
|
|
3
|
+
Local, offline speech-to-text for video captions and transcripts, used by
|
|
4
|
+
`maggie-video`'s `captions` subcommand. All engines run on the user's machine - **no
|
|
5
|
+
paid API** - so transcription has no per-minute cost, only local CPU/GPU time.
|
|
6
|
+
Distilled from the reference library's R-category projects.
|
|
7
|
+
|
|
8
|
+
## Engines
|
|
9
|
+
|
|
10
|
+
| Engine | What / how | License | Reach for it when |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| openai-whisper | The reference Python CLI: `whisper IN --model base --output_format srt --output_dir DIR` | MIT | the default; simplest install (`pip install openai-whisper`) |
|
|
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
|
+
| 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
|
+
|
|
16
|
+
Model size trades speed for accuracy: `tiny` / `base` (fast, rough) -> `small` /
|
|
17
|
+
`medium` -> `large-v3` (slow, best). Use `--lang` to skip auto-detect when known.
|
|
18
|
+
|
|
19
|
+
## Workflow (voiceover -> captions -> on-screen)
|
|
20
|
+
|
|
21
|
+
1. **Transcribe** the voiceover or the video's audio to SRT with a local engine
|
|
22
|
+
(`maggie_video.py captions --input vo.mp3 --output vo.srt --engine whisper
|
|
23
|
+
--model base`). A larger model is slower but more accurate.
|
|
24
|
+
2. **Review** the SRT - never ship an unreviewed transcript; whisper mishears names,
|
|
25
|
+
numbers, and brand terms. A human edits it.
|
|
26
|
+
3. **Put it on screen**, one of:
|
|
27
|
+
- burn in (`maggie_video.py subtitle --input video.mp4 --srt vo.srt --output out.mp4`),
|
|
28
|
+
- soft-mux a toggleable track (`subtitle --soft`), or
|
|
29
|
+
- a `captions` layer in a `maggie_video.py compile` timeline (see
|
|
30
|
+
[video timeline model](video-timeline-model.md)).
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
|
|
34
|
+
- Captions lift watch time and serve sound-off viewing - caption every social video.
|
|
35
|
+
- **Never fabricate a transcript**; generate it from the real audio and have a human
|
|
36
|
+
review before publishing (accuracy, names, and brand terms).
|
|
37
|
+
- Local/offline: no audio leaves the machine, no paid API. If a hosted transcription
|
|
38
|
+
API is ever wired in instead, the global spend-first rule applies - state the cost.
|
|
39
|
+
- Keep caption text inside the safe area (see `maggie-video` channel presets).
|
|
40
|
+
|
|
41
|
+
See `maggie-video` for the subcommands and the burn-in / soft-mux / compile options.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Generative visuals (creative coding)
|
|
2
|
+
|
|
3
|
+
Patterns for generating marketing visuals in code - hero backgrounds, textures, 3D
|
|
4
|
+
product shots, data-viz, and stylized images - distilled from the leading creative-
|
|
5
|
+
coding libraries. We adopt **patterns, not code**. Output becomes a deliverable as a
|
|
6
|
+
**still** (canvas/SVG export) or a **loop** (captured via
|
|
7
|
+
[design-motion production](design-motion-production.md) Part C or
|
|
8
|
+
[ffmpeg recipes](ffmpeg-recipes.md), then assembled in `maggie-video`). Determinism
|
|
9
|
+
by seeding matches `maggie-spirit`'s philosophy: same seed -> same pixels.
|
|
10
|
+
|
|
11
|
+
## Libraries
|
|
12
|
+
|
|
13
|
+
| Library | What / model | Lang | License | Marketing fit |
|
|
14
|
+
|---|---|---|---|---|
|
|
15
|
+
| three.js | WebGL 3D: Scene + Camera + WebGLRenderer; `renderer.render(scene,camera)` in a loop | JS | MIT | 3D product spins, logo stings, depth-y hero backgrounds |
|
|
16
|
+
| Babylon.js | Higher-level 3D engine (PBR, asset pipeline); heavier | JS/TS | Apache-2.0 | 3D product config; alt to three when its pipeline earns the weight |
|
|
17
|
+
| react-three-fiber | three.js as React JSX (`<mesh><boxGeometry/>…`), `useFrame` | JS/TS | MIT | 3D on a React site |
|
|
18
|
+
| p5.js | Canvas sketch: `setup()` once + `draw()` per frame; `random()/noise()` with `randomSeed()/noiseSeed()` | JS | **LGPL-2.1** | generative hero backgrounds, flow fields, noise art |
|
|
19
|
+
| paper.js | Vector scene graph (Path/Group), boolean ops, hit-testing | JS | MIT | editable vector hero art, print-quality SVG |
|
|
20
|
+
| two.js | One 2D API across SVG/Canvas/WebGL renderers | JS | MIT | vector art you want to export as SVG or capture from canvas |
|
|
21
|
+
| rough.js | Hand-drawn/sketchy shapes; `{seed}` = reproducible | JS/TS | MIT | approachable hand-made brand style, doodle accents |
|
|
22
|
+
| zdog | Pseudo-3D round/flat vector, designer-friendly | JS | MIT | cute 3D-ish icons, mascot/logo spins |
|
|
23
|
+
| pts | Computational geometry (Space + Form + Pt) | TS/JS | Apache-2.0 | geometric/particle hero art |
|
|
24
|
+
| hydra | Live-coded video synth (chained GLSL ops) | JS | **AGPL-3.0** | trippy animated backgrounds - **pattern only, do not ship its code** |
|
|
25
|
+
| regl | Functional WebGL (stateless draw commands) | JS | MIT | custom shader backgrounds/gradients when three is overkill |
|
|
26
|
+
| d3 | Data-driven SVG (scales + selections) | JS | ISC | bespoke infographics - but defer standard charts to the `dataviz` skill |
|
|
27
|
+
| fogleman/primitive | Reproduce an image with N geometric primitives (CLI) | Go | MIT | stylize a product photo into abstract art (still or GIF) |
|
|
28
|
+
| svg.js | Lightweight SVG DOM manipulation | JS | MIT | programmatic SVG icons/badges/dividers |
|
|
29
|
+
| nannou | Rust creative framework (desktop) | Rust | MIT/Apache | note only - high-perf generative art in Rust |
|
|
30
|
+
|
|
31
|
+
**License flags:** hydra is **AGPL-3.0**, p5 is **LGPL-2.1**, processing (non-core)
|
|
32
|
+
is GPL - fine as *idea* sources, but do not vendor their code into shipped product;
|
|
33
|
+
reimplement the pattern or use an MIT equivalent (two.js / pts / regl / svg.js).
|
|
34
|
+
|
|
35
|
+
## Patterns and the deliverable path
|
|
36
|
+
|
|
37
|
+
- **2D generative** (p5 / paper / two / rough / zdog / pts / svg.js): `setup()` once +
|
|
38
|
+
`draw()`/`update()` per frame. Use for brand-tinted hero/section backgrounds,
|
|
39
|
+
textures, doodle accents, geometric motifs. **Still:** SVG-capable libs serialize
|
|
40
|
+
their `<svg>` (crisp, editable, print-ready); canvas libs use `canvas.toDataURL()`
|
|
41
|
+
-> PNG. **Loop:** run the sketch headless and capture via design-motion Part C, or
|
|
42
|
+
in-browser with CCapture.js (MIT), then hand to `maggie-video`.
|
|
43
|
+
- **3D** (three / babylon / r3f): Scene + Camera + Renderer; animate by frame index.
|
|
44
|
+
Product spins, 3D logo stings, depth-y backgrounds. **Still:**
|
|
45
|
+
`renderer.domElement.toDataURL()` (set `preserveDrawingBuffer:true`); **loop:** drive
|
|
46
|
+
by frame, capture as above. Prefer three/r3f (MIT); babylon only when needed.
|
|
47
|
+
- **Data-viz** (d3): `d3-scale` + `d3-selection`; SVG is the native output. For
|
|
48
|
+
standard charts, **defer to the `dataviz` skill** (its palette/spec); pull in d3
|
|
49
|
+
only for bespoke marks (arc diagrams, force layouts, custom infographics).
|
|
50
|
+
- **Live visuals** (hydra): chained feedback-graph ops -> animated GLSL. Renders to a
|
|
51
|
+
canvas -> capture -> `maggie-video`. **AGPL: idea only**; for an MIT shader
|
|
52
|
+
background use regl.
|
|
53
|
+
- **Image -> primitives** (fogleman/primitive, MIT, Go CLI): stylize a photo into
|
|
54
|
+
abstract geometry.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
primitive -i input.png -o output.svg -n 100 -m 1
|
|
58
|
+
# -n shapes (50-200); -m mode (1 triangle,2 rect,3 ellipse,4 circle,6 beziers,8 polygon);
|
|
59
|
+
# output type by extension: PNG/JPG (raster), SVG (vector), GIF (animated, needs ImageMagick)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Still:** PNG/SVG directly; **loop:** `.gif` or `%d`-numbered PNG frames ->
|
|
63
|
+
`maggie-video`. It is randomized (no seed): generate once and **store the artifact**;
|
|
64
|
+
do not regenerate on every build.
|
|
65
|
+
|
|
66
|
+
## Determinism
|
|
67
|
+
|
|
68
|
+
p5 `randomSeed()/noiseSeed()`, rough.js `{seed}`, and a seeded PRNG in place of
|
|
69
|
+
`Math.random` give byte-reproducible stills; the frame-index/virtual-clock rule from
|
|
70
|
+
[programmatic video](programmatic-video.md) gives reproducible motion. `primitive`
|
|
71
|
+
and `hydra` are non-deterministic - capture and store their output as a fixed asset.
|
|
72
|
+
|
|
73
|
+
## Placement
|
|
74
|
+
|
|
75
|
+
- **maggie-spirit** owns seeded brand marks/characters; borrow the 2D-canvas sketch
|
|
76
|
+
model and seed discipline for flat-vector mark construction (zdog/two.js/rough).
|
|
77
|
+
Generative *backgrounds/scenes* do not live here.
|
|
78
|
+
- **maggie-design** owns generative hero backgrounds, section textures, 3D product
|
|
79
|
+
shots and image stylization as page/brand visuals; it points at this reference and
|
|
80
|
+
cross-links design-motion / `maggie-video` for capture-to-deliverable.
|
|
81
|
+
- **Reference-only:** d3 (defer to `dataviz`), hydra (AGPL, idea only), regl, babylon,
|
|
82
|
+
nannou/processing/openFrameworks (desktop notes), svg.js.
|
|
83
|
+
|
|
84
|
+
## Credits
|
|
85
|
+
|
|
86
|
+
Patterns adapted (not code) from three.js, p5.js, d3, paper.js, two.js, rough.js,
|
|
87
|
+
zdog, pts, hydra, regl, Babylon.js, react-three-fiber, fogleman/primitive, svg.js,
|
|
88
|
+
nannou - licenses in the table above. Capture pipeline: see
|
|
89
|
+
[programmatic video](programmatic-video.md), [design-motion production](design-motion-production.md),
|
|
90
|
+
[ffmpeg recipes](ffmpeg-recipes.md).
|