luckiest-co 1.0.65 → 1.0.66
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/ad-creative/CHANGELOG.md +3 -0
- package/skills/ad-creative/SKILL.md +13 -3
- package/skills/beauty-photography/.skillignore +2 -0
- package/skills/beauty-photography/ATTRIBUTION.md +17 -0
- package/skills/beauty-photography/CHANGELOG.md +80 -0
- package/skills/beauty-photography/LICENSE +176 -0
- package/skills/beauty-photography/SKILL.md +213 -0
- package/skills/beauty-photography/evals/evals.json +153 -0
- package/skills/beauty-photography/references/photography-styles.md +532 -0
- package/skills/beauty-photography/references/video-generation.md +98 -0
- package/skills/beauty-photography/scripts/compress_product_img.py +84 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Phase 5: Video Ad Generation
|
|
2
|
+
|
|
3
|
+
After the user is satisfied with the campaign image set, offer to create a short cinematic video ad.
|
|
4
|
+
|
|
5
|
+
Ask:
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
Generate a short video ad from the selected campaign images?
|
|
9
|
+
|
|
10
|
+
- Yes, generate video
|
|
11
|
+
- No, skip
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
If yes, let the user pick which campaign image should be used as the video's first frame:
|
|
15
|
+
|
|
16
|
+
```markdown
|
|
17
|
+
Which campaign image should become the video's first frame?
|
|
18
|
+
|
|
19
|
+
- Shot 1: Hero
|
|
20
|
+
- Shot 2: Detail
|
|
21
|
+
- Shot 3: Environment
|
|
22
|
+
- Other selected campaign image
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Video Motion Prompt
|
|
26
|
+
|
|
27
|
+
Construct a motion-focused prompt that describes camera movement, lighting animation, environmental motion, and product fidelity.
|
|
28
|
+
|
|
29
|
+
```markdown
|
|
30
|
+
{camera movement} shot of the selected product campaign image.
|
|
31
|
+
Preserve the product's exact silhouette, closure geometry, material, label placement, and luxury set design from the first frame.
|
|
32
|
+
{lighting animation}. {environmental motion}.
|
|
33
|
+
Cinematic beauty commercial, luxury fragrance advertisement, smooth motion, professional color grading, premium campaign finish.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Camera Movement Options
|
|
37
|
+
|
|
38
|
+
- **Slow dolly zoom in**: slow push-in that emphasizes product detail
|
|
39
|
+
- **Gentle orbit around**: subtle camera arc that reveals dimensionality
|
|
40
|
+
- **Slow pull-back reveal**: starts close, then reveals the full set
|
|
41
|
+
- **Static with subtle parallax**: premium stillness with micro-depth movement
|
|
42
|
+
- **Crane down**: downward reveal that feels dramatic and editorial
|
|
43
|
+
|
|
44
|
+
## Lighting Animation
|
|
45
|
+
|
|
46
|
+
- Golden light slowly shifting across the glass or packaging surface
|
|
47
|
+
- Soft caustics dancing on nearby marble, water, or reflective surfaces
|
|
48
|
+
- Light gradually transitioning from cool to warm
|
|
49
|
+
- Rim light subtly tracing the bottle or container edge
|
|
50
|
+
- Highlight line gliding across the cap, label, or curved body
|
|
51
|
+
|
|
52
|
+
Match the lighting physics to the product material. Do not describe caustics or transmission for frosted, matte, ceramic, or opaque packaging.
|
|
53
|
+
|
|
54
|
+
## Environmental Motion
|
|
55
|
+
|
|
56
|
+
- Particles floating gently in the air
|
|
57
|
+
- Petals drifting slowly through the frame
|
|
58
|
+
- Water ripples expanding outward
|
|
59
|
+
- Silk fabric undulating in a gentle breeze
|
|
60
|
+
- Mist swirling around the base
|
|
61
|
+
- Subtle shadow movement from leaves, curtains, or sculptural props
|
|
62
|
+
|
|
63
|
+
## Generation Guidance
|
|
64
|
+
|
|
65
|
+
Use whichever image-to-video tool this session has (for example a connected
|
|
66
|
+
image-to-video MCP tool). If the user wants more than a single 3-5 second clip
|
|
67
|
+
(a cut with several shots, captions, music, or end card), hand off to
|
|
68
|
+
`luckiest-video-studio` with the chosen stills as references instead.
|
|
69
|
+
|
|
70
|
+
Generate a short video from the selected campaign image as the first frame. Keep motion elegant and restrained; the product should remain stable, recognizable, and premium.
|
|
71
|
+
|
|
72
|
+
Recommended defaults:
|
|
73
|
+
|
|
74
|
+
| Setting | Recommendation |
|
|
75
|
+
|---------|----------------|
|
|
76
|
+
| Duration | 3-5 seconds |
|
|
77
|
+
| Aspect ratio | Match the selected campaign image |
|
|
78
|
+
| Variants | 1-2 options unless the user asks for more |
|
|
79
|
+
| Motion intensity | Low to medium; avoid chaotic movement |
|
|
80
|
+
|
|
81
|
+
## QA Before Presenting
|
|
82
|
+
|
|
83
|
+
Review the video before showing it:
|
|
84
|
+
|
|
85
|
+
| Check | What to verify |
|
|
86
|
+
|-------|----------------|
|
|
87
|
+
| Product identity | Product remains recognizable throughout |
|
|
88
|
+
| Shape stability | Bottle/container does not melt, stretch, or morph |
|
|
89
|
+
| Closure fidelity | Cap, pump, stopper, or lid remains consistent |
|
|
90
|
+
| Label stability | Label does not drift unnaturally; minor AI text changes may be acceptable |
|
|
91
|
+
| Motion quality | Camera movement is smooth and premium |
|
|
92
|
+
| Material truth | Light behavior matches the product material |
|
|
93
|
+
|
|
94
|
+
If the product shape changes significantly, regenerate with stronger fidelity language and calmer motion.
|
|
95
|
+
|
|
96
|
+
## Presentation
|
|
97
|
+
|
|
98
|
+
Show the final video result as playable media or a link, plus a one-sentence creative description. Keep logs and request payloads out of the main reply, but answer plainly if the user asks which model, settings, or prompt made it.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Shrink local product photos so an agent can read them as images.
|
|
4
|
+
|
|
5
|
+
Fits each image inside 1024x1024, converts it to JPEG (quality 85), then lowers
|
|
6
|
+
quality and scale until the file is at most 145 KB. Reads local files only and
|
|
7
|
+
makes no network calls. Needs Pillow (pip install pillow).
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python3 compress_product_img.py --images photo.jpg [more.jpg ...] [--out-dir DIR]
|
|
11
|
+
|
|
12
|
+
Prints one line per image:
|
|
13
|
+
[COMPRESSED] <out path> (1200KB -> 140KB, 1024x768)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import io
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
import tempfile
|
|
21
|
+
import uuid
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from PIL import Image, ImageOps
|
|
25
|
+
except ImportError:
|
|
26
|
+
sys.exit("[ERROR] Pillow is not installed. Run: pip install pillow")
|
|
27
|
+
|
|
28
|
+
MAX_DIM = 1024
|
|
29
|
+
MAX_BYTES = 148_480 # 145 KB, under the agent Read tool's image size limit
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _open_rgb(raw: bytes) -> Image.Image:
|
|
33
|
+
img = Image.open(io.BytesIO(raw))
|
|
34
|
+
img = ImageOps.exif_transpose(img) or img
|
|
35
|
+
return img.convert("RGB") if img.mode != "RGB" else img
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def compress(raw: bytes) -> tuple[bytes, int, int]:
|
|
39
|
+
"""Return (jpeg_bytes, width, height), at most MAX_BYTES when reachable."""
|
|
40
|
+
img = _open_rgb(raw)
|
|
41
|
+
img.thumbnail((MAX_DIM, MAX_DIM), Image.Resampling.LANCZOS)
|
|
42
|
+
base_w, base_h = img.size
|
|
43
|
+
|
|
44
|
+
quality, scale = 85, 1.0
|
|
45
|
+
while True:
|
|
46
|
+
size = (max(1, round(base_w * scale)), max(1, round(base_h * scale)))
|
|
47
|
+
frame = img if scale == 1.0 else img.resize(size, Image.Resampling.LANCZOS)
|
|
48
|
+
buf = io.BytesIO()
|
|
49
|
+
frame.save(buf, format="JPEG", quality=quality)
|
|
50
|
+
out = buf.getvalue()
|
|
51
|
+
if len(out) <= MAX_BYTES or (quality <= 30 and scale <= 0.3):
|
|
52
|
+
return out, frame.width, frame.height
|
|
53
|
+
if quality > 30:
|
|
54
|
+
quality -= 10
|
|
55
|
+
else:
|
|
56
|
+
scale -= 0.1
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def main():
|
|
60
|
+
parser = argparse.ArgumentParser(description="Shrink product photos for agent vision")
|
|
61
|
+
parser.add_argument("--images", nargs="+", required=True, help="Local image paths")
|
|
62
|
+
parser.add_argument("--out-dir", default=tempfile.gettempdir(), help="Where to write JPEGs")
|
|
63
|
+
args = parser.parse_args()
|
|
64
|
+
os.makedirs(args.out_dir, exist_ok=True)
|
|
65
|
+
|
|
66
|
+
for src in args.images:
|
|
67
|
+
if not os.path.isfile(src):
|
|
68
|
+
print(f"[ERROR] Not a local file: {src}")
|
|
69
|
+
continue
|
|
70
|
+
with open(src, "rb") as f:
|
|
71
|
+
raw = f.read()
|
|
72
|
+
try:
|
|
73
|
+
data, w, h = compress(raw)
|
|
74
|
+
except Exception as e: # bad or unsupported image
|
|
75
|
+
print(f"[ERROR] Could not compress {src}: {e}")
|
|
76
|
+
continue
|
|
77
|
+
out = os.path.join(args.out_dir, f"product_{uuid.uuid4().hex[:12]}.jpg")
|
|
78
|
+
with open(out, "wb") as f:
|
|
79
|
+
f.write(data)
|
|
80
|
+
print(f"[COMPRESSED] {out} ({len(raw) // 1024}KB -> {len(data) // 1024}KB, {w}x{h})")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__":
|
|
84
|
+
main()
|