luckiest-co 1.0.39 → 1.0.41
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 +7 -0
- package/skills/ad-creative/SKILL.md +23 -4
- package/skills/ad-creative/references/generative-tools.md +6 -30
- package/skills/ads/CHANGELOG.md +9 -0
- package/skills/ads/SKILL.md +19 -9
- package/skills/ads/references/reading-google-ads-data.md +121 -0
- package/skills/ai-seo/CHANGELOG.md +11 -0
- package/skills/ai-seo/SKILL.md +21 -22
- package/skills/ai-seo/references/content-types.md +11 -0
- package/skills/ai-seo/references/linkedin-ai-citations.md +122 -0
- package/skills/ai-seo/references/platform-ranking-factors.md +32 -19
- package/skills/ai-seo/references/positioning-and-consensus.md +102 -0
- package/skills/coder/CHANGELOG.md +23 -0
- package/skills/coder/SKILL.md +16 -4
- package/skills/coder-brainstorming/CHANGELOG.md +9 -0
- package/skills/coder-brainstorming/SKILL.md +5 -3
- package/skills/coder-debugging/CHANGELOG.md +11 -0
- package/skills/coder-debugging/SKILL.md +15 -3
- package/skills/coder-executing-plans/CHANGELOG.md +9 -0
- package/skills/coder-executing-plans/SKILL.md +5 -3
- package/skills/coder-finishing-a-branch/CHANGELOG.md +9 -0
- package/skills/coder-finishing-a-branch/SKILL.md +7 -3
- package/skills/coder-guard/CHANGELOG.md +7 -0
- package/skills/coder-guard/SKILL.md +6 -6
- package/skills/coder-receiving-code-review/CHANGELOG.md +9 -0
- package/skills/coder-receiving-code-review/SKILL.md +5 -3
- package/skills/coder-shipping/CHANGELOG.md +9 -0
- package/skills/coder-shipping/SKILL.md +4 -4
- package/skills/coder-subagent-driven-development/CHANGELOG.md +9 -0
- package/skills/coder-subagent-driven-development/SKILL.md +5 -3
- package/skills/coder-writing-plans/CHANGELOG.md +9 -0
- package/skills/coder-writing-plans/SKILL.md +5 -3
- package/skills/cold-email/CHANGELOG.md +7 -0
- package/skills/cold-email/SKILL.md +15 -8
- package/skills/cold-email/references/follow-up-sequences.md +4 -4
- package/skills/cold-email/references/frameworks.md +5 -5
- package/skills/cold-email/references/personalization.md +10 -10
- package/skills/competitor-profiling/CHANGELOG.md +8 -0
- package/skills/competitor-profiling/SKILL.md +34 -9
- package/skills/competitor-profiling/references/tool-reference.md +141 -5
- package/skills/competitors/CHANGELOG.md +8 -0
- package/skills/competitors/SKILL.md +32 -5
- package/skills/competitors/references/content-architecture.md +6 -0
- package/skills/competitors/references/templates.md +3 -0
- package/skills/copy-editing/CHANGELOG.md +10 -0
- package/skills/copy-editing/SKILL.md +41 -9
- package/skills/copy-editing/references/checklist.md +11 -0
- package/skills/copywriting/CHANGELOG.md +11 -0
- package/skills/copywriting/SKILL.md +32 -4
- package/skills/copywriting/references/copy-frameworks.md +2 -3
- package/skills/copywriting/references/natural-transitions.md +4 -20
- package/skills/customer-research/CHANGELOG.md +8 -0
- package/skills/customer-research/SKILL.md +6 -3
- package/skills/directory-submissions/CHANGELOG.md +9 -0
- package/skills/directory-submissions/SKILL.md +21 -10
- package/skills/emails/CHANGELOG.md +8 -0
- package/skills/emails/SKILL.md +22 -3
- package/skills/emails/references/sequence-templates.md +3 -3
- package/skills/image/CHANGELOG.md +8 -0
- package/skills/image/SKILL.md +4 -4
- package/skills/image/references/ai-image-prompting.md +1 -1
- package/skills/marketing-plan/CHANGELOG.md +8 -0
- package/skills/marketing-plan/SKILL.md +8 -4
- package/skills/marketing-plan/references/market-sizing.md +166 -0
- package/skills/marketing-plan/references/methodology.md +2 -0
- package/skills/model-router/CHANGELOG.md +9 -0
- package/skills/model-router/SKILL.md +3 -3
- package/skills/model-router/references/weave-routing-notes.md +1 -0
- package/skills/model-router/scripts/route.py +3 -1
- package/skills/prospecting/CHANGELOG.md +7 -0
- package/skills/prospecting/SKILL.md +3 -3
- package/skills/prospecting/references/saas-prospecting.md +1 -1
- package/skills/public-relations/CHANGELOG.md +10 -0
- package/skills/public-relations/SKILL.md +16 -4
- package/skills/public-relations/references/crisis-communications.md +111 -0
- package/skills/public-relations/references/newsjacking.md +2 -0
- package/skills/public-relations/references/statement-templates.md +143 -0
- package/skills/sales-enablement/CHANGELOG.md +8 -0
- package/skills/sales-enablement/SKILL.md +72 -4
- package/skills/sales-enablement/references/win-loss-analysis.md +72 -0
- package/skills/skill-audit/ATTRIBUTION.md +5 -0
- package/skills/skill-audit/CHANGELOG.md +19 -0
- package/skills/skill-audit/SKILL.md +121 -0
- package/skills/skill-audit-security/ATTRIBUTION.md +14 -0
- package/skills/skill-audit-security/CHANGELOG.md +14 -0
- package/skills/skill-audit-security/LICENSE-APACHE-2.0 +190 -0
- package/skills/skill-audit-security/SKILL.md +99 -0
- package/skills/skill-audit-security/references/rule-ids.md +28 -0
- package/skills/skill-audit-security/references/source-review.md +58 -0
- package/skills/sms/CHANGELOG.md +8 -0
- package/skills/sms/SKILL.md +18 -4
- package/skills/sms/references/whatsapp.md +258 -0
- package/skills/social/CHANGELOG.md +11 -0
- package/skills/social/SKILL.md +31 -7
- package/skills/social/references/listening.md +2 -0
- package/skills/social/references/platforms.md +15 -9
- package/skills/social/references/post-templates.md +9 -9
- package/skills/social/references/short-form-video.md +5 -5
- package/skills/social/references/x-algorithm.md +69 -0
- package/skills/trends/CHANGELOG.md +3 -0
- package/skills/trends/SKILL.md +14 -4
- package/skills/video/CHANGELOG.md +8 -0
- package/skills/video/SKILL.md +11 -25
- package/skills/video-studio/ATTRIBUTION.md +3 -0
- package/skills/video-studio/CHANGELOG.md +25 -0
- package/skills/video-studio/LICENSE-motionmaxxing +202 -0
- package/skills/video-studio/SKILL.md +115 -25
- package/skills/video-studio/references/audio.md +15 -0
- package/skills/video-studio/references/interview.md +75 -0
- package/skills/video-studio/references/step-2-plan.md +39 -7
- package/skills/video-studio/references/storyboard.md +3 -1
- package/skills/video-studio/references/tones.md +5 -5
- package/skills/video-studio/scripts/pyproject.toml +4 -2
- package/skills/video-studio/scripts/qa.mjs +85 -1
- package/skills/video-studio/scripts/qa.test.mjs +37 -1
- package/skills/video-studio/scripts/render-scenes.mjs +1 -0
- package/skills/video-studio/scripts/storyboard.schema.json +6 -1
- package/skills/video-studio/scripts/uv.lock +8 -5
- package/skills/video-studio-art-director/ATTRIBUTION.md +3 -0
- package/skills/video-studio-art-director/CHANGELOG.md +7 -0
- package/skills/video-studio-art-director/LICENSE-motionmaxxing +202 -0
- package/skills/video-studio-art-director/SKILL.md +42 -7
- package/skills/video-studio-composition/ATTRIBUTION.md +3 -0
- package/skills/video-studio-composition/CHANGELOG.md +7 -0
- package/skills/video-studio-composition/LICENSE-motionmaxxing +202 -0
- package/skills/video-studio-composition/SKILL.md +17 -4
- package/skills/video-studio-director/ATTRIBUTION.md +3 -0
- package/skills/video-studio-director/CHANGELOG.md +15 -0
- package/skills/video-studio-director/LICENSE-motionmaxxing +202 -0
- package/skills/video-studio-director/SKILL.md +105 -10
- package/skills/video-studio-motion/ATTRIBUTION.md +3 -0
- package/skills/video-studio-motion/CHANGELOG.md +8 -0
- package/skills/video-studio-motion/LICENSE-motionmaxxing +202 -0
- package/skills/video-studio-motion/SKILL.md +98 -5
- package/skills/video-studio-motion/references/kinetic-type.md +89 -0
- package/skills/video-studio-motion/references/ui-demo.md +59 -0
- package/skills/video-studio-review/CHANGELOG.md +11 -0
- package/skills/video-studio-review/SKILL.md +31 -5
- package/skills/video-studio-review/editor/index.html +21 -3
- package/skills/video-studio-review/references/apply-feedback.md +19 -0
- package/skills/video-studio-review/scripts/build-reel.mjs +35 -10
- package/skills/video-studio-review/scripts/build-reel.test.mjs +15 -0
- package/skills/video-studio-script/ATTRIBUTION.md +6 -0
- package/skills/video-studio-script/CHANGELOG.md +12 -0
- package/skills/video-studio-script/LICENSE-motionmaxxing +202 -0
- package/skills/video-studio-script/SKILL.md +41 -10
- package/skills/video-studio-showreel/CHANGELOG.md +21 -0
- package/skills/video-studio-showreel/SKILL.md +231 -0
- package/skills/video-studio-showreel/references/motion-design-pack-notes.md +28 -0
- package/skills/video-studio-showreel/references/zingage-breakdown.md +47 -0
- package/skills/video-studio-showreel/scripts/build.py +10 -0
- package/skills/video-studio-showreel/templates/showreel.html +264 -0
- package/skills/video-watcher/CHANGELOG.md +6 -0
- package/skills/video-watcher/SKILL.md +3 -3
- package/skills/video-watcher/scripts/setup.py +9 -7
- package/skills/trends/agents/openai.yaml +0 -8
- package/skills/trends/scripts/build-skill.sh +0 -39
- package/skills/trends/scripts/compare.sh +0 -61
- package/skills/trends/scripts/evaluate_search_quality.py +0 -573
- package/skills/trends/scripts/test-v1-vs-v2.sh +0 -220
- package/skills/trends/scripts/test_device_auth.py +0 -128
- package/skills/trends/scripts/verify_v3.py +0 -195
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-resolution="landscape" data-look="default"><!-- data-look="papercut": handmade torn-paper stop-motion look -->
|
|
3
|
+
<head>
|
|
4
|
+
<!-- showreel recipe (luckiest-video-studio-showreel), Luckiest edition.
|
|
5
|
+
One motif: the coral dot (the i-dot of the wordmark, the period of every headline).
|
|
6
|
+
Chain: orb > mosaic center tile > i-dot > hero period > coral field > photo circle > i-dot.
|
|
7
|
+
Every time is B(n) beats at 120 BPM. Built by build.py from this source (injects the wordmark SVG). -->
|
|
8
|
+
<meta charset="UTF-8" />
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
@font-face{font-family:'DM Serif Display';font-style:normal;font-weight:400;font-display:block;src:url(assets/fonts/DMSerifDisplay-normal-400.woff2) format('woff2')}
|
|
12
|
+
@font-face{font-family:'DM Serif Display';font-style:italic;font-weight:400;font-display:block;src:url(assets/fonts/DMSerifDisplay-italic-400.woff2) format('woff2')}
|
|
13
|
+
@font-face{font-family:'Inter';font-style:normal;font-weight:400 600;font-display:block;src:url(assets/fonts/Inter-normal-500.woff2) format('woff2')}
|
|
14
|
+
:root{--paper:#FFFFFF;--ink:#0A0A0A;--muted:#737373;--c1:#FF532C;--c2:#FF3D59;--edge:#E5E5E5;
|
|
15
|
+
--coral:linear-gradient(90deg,#FF532C,#FF3D59)}
|
|
16
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
17
|
+
html,body{width:1920px;height:1080px;overflow:hidden;background:var(--paper)}
|
|
18
|
+
#root{position:relative;width:100%;height:100%;overflow:hidden;background:var(--paper);font-family:Inter,system-ui,sans-serif;color:var(--ink)}
|
|
19
|
+
.layer{position:absolute;inset:0}
|
|
20
|
+
.serif{font-family:'DM Serif Display',serif;font-weight:400}
|
|
21
|
+
.caps{font:600 18px/1 Inter,sans-serif;letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}
|
|
22
|
+
|
|
23
|
+
/* A: orb */
|
|
24
|
+
#orb{position:absolute;left:850px;top:430px;width:220px;height:220px;border-radius:50%;
|
|
25
|
+
background:radial-gradient(circle at 34% 28%,#fff 0 5%,#FFB0A0 11%,#FF6A4A 28%,#FF3D59 62%,#C9203D 100%);
|
|
26
|
+
box-shadow:0 0 90px 10px rgba(255,61,89,.35),inset -14px -18px 40px rgba(120,0,30,.35)}
|
|
27
|
+
#orb svg{position:absolute;left:55px;top:55px;width:110px;height:110px}
|
|
28
|
+
#halo{position:absolute;left:660px;top:240px;width:600px;height:600px;border-radius:50%;
|
|
29
|
+
background:radial-gradient(circle,rgba(255,61,89,.16) 1.5px,transparent 2px) 0 0/18px 18px;
|
|
30
|
+
-webkit-mask:radial-gradient(circle,#000 30%,transparent 70%);mask:radial-gradient(circle,#000 30%,transparent 70%)}
|
|
31
|
+
|
|
32
|
+
/* B: mosaic, guides, wordmark */
|
|
33
|
+
#mosaic i{position:absolute;width:120px;height:120px}
|
|
34
|
+
#ctile{position:absolute;left:840px;top:420px;width:240px;height:240px;background:var(--paper);display:grid;place-items:center}
|
|
35
|
+
#ctile svg{width:130px;height:130px}
|
|
36
|
+
.guide{position:absolute;background:repeating-linear-gradient(90deg,var(--c2) 0 10px,transparent 10px 20px);height:2px;opacity:.55;transform-origin:left center}
|
|
37
|
+
.guide.v{width:2px;height:auto;background:repeating-linear-gradient(180deg,var(--c2) 0 10px,transparent 10px 20px);transform-origin:center top}
|
|
38
|
+
.node{position:absolute;width:12px;height:12px;margin:-5px 0 0 -5px;background:var(--c2);opacity:.8}
|
|
39
|
+
#wm{position:absolute;left:410px;top:445px;width:1100px;height:190px;transform-origin:50% 50%}
|
|
40
|
+
#wm svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
|
|
41
|
+
#wmOutline path{fill:none;stroke:var(--c2);stroke-width:.35;stroke-dasharray:1.1 .9}
|
|
42
|
+
#wmFill path{fill:var(--ink)}
|
|
43
|
+
#idot{position:absolute;width:44px;height:44px;margin:-22px 0 0 -22px;border-radius:50%;background:var(--coral)}
|
|
44
|
+
|
|
45
|
+
/* C: dive */
|
|
46
|
+
#stage{position:absolute;inset:0;perspective:1900px;perspective-origin:50% 40%}
|
|
47
|
+
#plane{position:absolute;left:160px;top:80px;width:1600px;height:920px;transform-style:preserve-3d;transform-origin:50% 50%;
|
|
48
|
+
background:#fff;box-shadow:0 60px 120px rgba(10,10,10,.18),0 0 0 1px rgba(10,10,10,.06)}
|
|
49
|
+
#plane img{position:absolute;inset:0;width:100%;height:100%}
|
|
50
|
+
#plane .thick{position:absolute;left:0;right:0;bottom:-18px;height:18px;background:linear-gradient(#ececec,#d6d6d6);transform-origin:top;transform:rotateX(-90deg)}
|
|
51
|
+
#fog{position:absolute;left:0;right:0;top:0;height:420px;background:linear-gradient(var(--paper) 10%,rgba(255,255,255,0))}
|
|
52
|
+
#burst{position:absolute;left:1098.6px;top:724px;width:20px;height:20px;margin:-10px 0 0 -10px;border-radius:50%;background:var(--coral)}
|
|
53
|
+
|
|
54
|
+
/* D: coral field and slabs */
|
|
55
|
+
#field{background:linear-gradient(120deg,#FF532C,#FF3D59)}
|
|
56
|
+
.slab{position:absolute;transform-style:preserve-3d}
|
|
57
|
+
.slab .face{position:absolute;inset:0;background:#fff;border-radius:3px;padding:34px 40px;display:flex;flex-direction:column;justify-content:space-between;
|
|
58
|
+
box-shadow:inset 0 0 0 1px rgba(10,10,10,.05)}
|
|
59
|
+
.slab .edge{position:absolute;inset:0;border-radius:3px;background:#C9C9C9;transform:translateZ(-16px)}
|
|
60
|
+
.slab .shade{position:absolute;left:6%;right:6%;bottom:-40px;height:50px;border-radius:50%;background:rgba(90,0,20,.35);filter:blur(22px);transform:translateZ(-40px)}
|
|
61
|
+
.stat .num{font-size:150px;line-height:.9;letter-spacing:-.02em}
|
|
62
|
+
.chip .face{justify-content:center;align-items:center;padding:0}
|
|
63
|
+
.chip .num{font-size:66px;line-height:1}
|
|
64
|
+
.slab .caps{font-size:22px}
|
|
65
|
+
#dropLabel{font-size:26px}
|
|
66
|
+
#url{font-size:24px;letter-spacing:.32em}
|
|
67
|
+
|
|
68
|
+
/* E: people + line, F: lockup */
|
|
69
|
+
#pc{position:absolute;left:260px;top:240px;width:600px;height:600px;border-radius:50%;overflow:hidden;background:var(--coral)}
|
|
70
|
+
#pc img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0}
|
|
71
|
+
#line{position:absolute;left:980px;top:270px;font-size:150px;line-height:1.02;letter-spacing:-.015em}
|
|
72
|
+
#line .row{overflow:hidden;padding-bottom:14px}
|
|
73
|
+
#line .w{display:inline-block}
|
|
74
|
+
#line em{font-style:italic}
|
|
75
|
+
#line .dot{display:inline-block;width:.2em;height:.2em;border-radius:50%;background:var(--coral);margin-left:.03em}
|
|
76
|
+
#url{position:absolute;left:0;right:0;top:690px;text-align:center}
|
|
77
|
+
|
|
78
|
+
/* Paper-cut look: torn edges, fibre grain, hard shadows, white slivers, warm paper.
|
|
79
|
+
Same technique as the cards pack 01-paper-collage. Fixed seeds keep renders identical. */
|
|
80
|
+
#grain{display:none;position:absolute;inset:0;pointer-events:none;z-index:50;mix-blend-mode:multiply;opacity:.35;
|
|
81
|
+
background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
|
|
82
|
+
[data-look=papercut]{--paper:#efe9dc;--ink:#17130e}
|
|
83
|
+
[data-look=papercut] #grain{display:block}
|
|
84
|
+
[data-look=papercut] #orb{background:var(--c2);box-shadow:none}
|
|
85
|
+
[data-look=papercut] :is(#orb,#ctile,#mosaic i,.slab .face,#plane img,#pc,#idot,#ldot){filter:url(#torn) drop-shadow(5px 7px 0 rgba(23,19,14,.3))}
|
|
86
|
+
[data-look=papercut] #mosaic i{width:112px;height:112px;margin:4px}
|
|
87
|
+
[data-look=papercut] .slab .shade{display:none}
|
|
88
|
+
[data-look=papercut] #plane{box-shadow:10px 14px 0 rgba(23,19,14,.25)}
|
|
89
|
+
</style></head>
|
|
90
|
+
<body>
|
|
91
|
+
<svg width="0" height="0" style="position:absolute"><filter id="torn" x="-5%" y="-5%" width="110%" height="110%">
|
|
92
|
+
<feTurbulence type="fractalNoise" baseFrequency="0.06" numOctaves="3" seed="11"/>
|
|
93
|
+
<feDisplacementMap in="SourceGraphic" scale="7" xChannelSelector="R" yChannelSelector="G"/></filter></svg>
|
|
94
|
+
<div id="root" data-composition-id="main" data-start="0" data-duration="15" data-width="1920" data-height="1080">
|
|
95
|
+
<div id="sA" class="layer clip" data-start="0" data-duration="15" data-track-index="1"><div id="halo"></div><div id="orb">%%MARK_WHITE%%</div></div>
|
|
96
|
+
<div id="sB" class="layer clip" data-start="0" data-duration="15" data-track-index="2">
|
|
97
|
+
<div id="mosaic" class="layer"></div>
|
|
98
|
+
<div id="guides" class="layer">
|
|
99
|
+
<i class="guide" style="left:300px;top:445px;width:1320px"></i><i class="guide" style="left:300px;top:635px;width:1320px"></i>
|
|
100
|
+
<i class="guide v" style="left:410px;top:330px;height:420px"></i><i class="guide v" style="left:1510px;top:330px;height:420px"></i>
|
|
101
|
+
<i class="node" style="left:410px;top:445px"></i><i class="node" style="left:1510px;top:445px"></i>
|
|
102
|
+
<i class="node" style="left:410px;top:635px"></i><i class="node" style="left:1510px;top:635px"></i>
|
|
103
|
+
</div>
|
|
104
|
+
<div id="ctile">%%MARK_INK%%</div>
|
|
105
|
+
<div id="wm"><svg id="wmOutline" viewBox="0 0 191.5 33">%%WM_PATHS%%</svg><svg id="wmFill" viewBox="0 0 191.5 33">%%WM_PATHS%%</svg></div>
|
|
106
|
+
</div>
|
|
107
|
+
<div id="sC" class="layer clip" data-start="0" data-duration="15" data-track-index="3">
|
|
108
|
+
<div id="stage"><div id="plane"><img src="assets/ui/hero.png" alt=""><i class="thick"></i></div></div>
|
|
109
|
+
<div id="fog"></div>
|
|
110
|
+
</div>
|
|
111
|
+
<div id="sD" class="layer clip" data-start="0" data-duration="15" data-track-index="4">
|
|
112
|
+
<div id="field" class="layer"></div>
|
|
113
|
+
<div class="layer" style="perspective:1700px">
|
|
114
|
+
<div id="s1" class="slab stat" style="left:250px;top:230px;width:640px;height:330px"><i class="shade"></i><i class="edge"></i>
|
|
115
|
+
<div class="face"><div class="caps">Saved by startups</div><div class="num serif">$<span id="n1">0</span>k</div></div></div>
|
|
116
|
+
<div id="s2" class="slab stat" style="left:1010px;top:500px;width:640px;height:330px"><i class="shade"></i><i class="edge"></i>
|
|
117
|
+
<div class="face"><div class="caps">Trademark-screened</div><div class="num serif"><span id="n2">0</span>+</div></div></div>
|
|
118
|
+
<div id="chips"></div>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="caps" id="dropLabel" style="position:absolute;left:0;right:0;top:150px;text-align:center;color:#fff;opacity:.9">This week's drop</div>
|
|
121
|
+
</div>
|
|
122
|
+
<div id="sE" class="layer clip" data-start="0" data-duration="15" data-track-index="5">
|
|
123
|
+
<div id="pc"><img src="assets/broll/b1.jpg"><img src="assets/broll/b2.jpg"><img src="assets/broll/b3.jpg"><img src="assets/broll/b4.jpg"><img src="assets/broll/b5.jpg"><img src="assets/broll/b6.jpg"></div>
|
|
124
|
+
<div id="line" class="serif">
|
|
125
|
+
<div class="row"><span class="w">Rent it.</span></div>
|
|
126
|
+
<div class="row"><span class="w">Build it.</span></div>
|
|
127
|
+
<div class="row"><span class="w"><em>Launch it</em><i class="dot" id="ldot"></i></span></div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
<div id="sF" class="layer clip" data-start="0" data-duration="15" data-track-index="6">
|
|
131
|
+
<div id="url" class="caps" style="color:var(--ink)">luckiest.co</div>
|
|
132
|
+
</div>
|
|
133
|
+
<div id="sG" class="layer clip" data-start="0" data-duration="15" data-track-index="7"><i id="idot"></i><i id="burst"></i></div>
|
|
134
|
+
<i id="grain"></i>
|
|
135
|
+
<audio id="master" data-start="0" data-duration="15" data-track-index="9" data-volume="1" src="assets/reel-master.wav"></audio>
|
|
136
|
+
</div>
|
|
137
|
+
<script>
|
|
138
|
+
const DUR=15, PERIOD=0.5, B=(n)=>n*PERIOD;
|
|
139
|
+
const h=(n)=>{const x=Math.sin(n*127.1+311.7)*43758.5453;return x-Math.floor(x)}; // seeded, never Math.random()
|
|
140
|
+
const $=(s)=>document.querySelector(s), $$=(s)=>[...document.querySelectorAll(s)];
|
|
141
|
+
const tl=gsap.timeline({paused:true});
|
|
142
|
+
|
|
143
|
+
// Layout, built once.
|
|
144
|
+
const mosaic=$("#mosaic"), tiles=[];
|
|
145
|
+
for(let y=0;y<9;y++)for(let x=0;x<16;x++){
|
|
146
|
+
const i=document.createElement("i"); i.style.left=x*120+"px"; i.style.top=y*120+"px";
|
|
147
|
+
const d=Math.hypot(x-7.5,y-4), k=h(x*31+y*7);
|
|
148
|
+
i.style.background=(x+y)%2?"#FF3D59":(k>.5?"#FF532C":"#FF7C8E");
|
|
149
|
+
mosaic.appendChild(i); tiles.push({i,d});
|
|
150
|
+
}
|
|
151
|
+
const chips=$("#chips"), DOMAINS=["Quota.io","Puffy.net","Tryasap.com","Playbook.cc"];
|
|
152
|
+
DOMAINS.forEach((n,k)=>{const c=document.createElement("div");c.className="slab chip";c.id="c"+k;
|
|
153
|
+
Object.assign(c.style,{left:(110+k*435)+"px",top:"460px",width:"410px",height:"160px"});
|
|
154
|
+
c.innerHTML=`<i class="shade"></i><i class="edge"></i><div class="face"><div class="num serif">${n}</div></div>`;chips.appendChild(c)});
|
|
155
|
+
// i-dot of the wordmark on screen: viewBox (120.8,4.0) r3.8 at scale 1100/191.5.
|
|
156
|
+
const S=1100/191.5, IDOT={x:410+120.8*S, y:445+4.0*S, d:3.8*2*S};
|
|
157
|
+
|
|
158
|
+
// Initial state.
|
|
159
|
+
gsap.set(["#sB","#sC","#sD","#sE","#sF"],{opacity:0});
|
|
160
|
+
gsap.set("#orb",{scale:.8}); gsap.set("#halo",{scale:.6,opacity:0});
|
|
161
|
+
gsap.set(tiles.map(t=>t.i),{scale:0}); gsap.set("#ctile",{scale:0}); gsap.set("#guides",{opacity:0});
|
|
162
|
+
gsap.set(".guide",{scaleX:0}); gsap.set(".guide.v",{scaleX:1,scaleY:0}); gsap.set(".node",{scale:0});
|
|
163
|
+
gsap.set("#wmOutline",{clipPath:"inset(0 100% 0 0)"}); gsap.set("#wmFill",{clipPath:"inset(0 100% 0 0)"});
|
|
164
|
+
gsap.set("#idot",{left:960,top:540,scale:0}); gsap.set("#burst",{scale:0});
|
|
165
|
+
|
|
166
|
+
// A. Mark born: the orb breathes on each build beat, squashes, bursts on the drop (beat 4 = 2.0s).
|
|
167
|
+
tl.to("#halo",{opacity:1,scale:1,duration:B(3),ease:"power2.out"},0);
|
|
168
|
+
for(let k=0;k<4;k++){
|
|
169
|
+
tl.to("#orb",{scale:.88+k*.1,duration:.08,ease:"power2.out"},B(k));
|
|
170
|
+
tl.to("#orb",{scale:.84+k*.1,duration:B(1)-.1,ease:"sine.inOut"},B(k)+.08);
|
|
171
|
+
}
|
|
172
|
+
tl.to("#orb",{scaleX:1.22,scaleY:.82,duration:B(.5),ease:"power2.in"},B(3.5));
|
|
173
|
+
// beat-locked: 2.00s drop. Orb becomes the center tile, the mosaic bursts outward.
|
|
174
|
+
tl.set("#sB",{opacity:1},B(4));
|
|
175
|
+
tl.to("#orb",{scale:0,duration:.12,ease:"power2.in"},B(4));
|
|
176
|
+
tl.to("#halo",{scale:2.4,opacity:0,duration:B(1),ease:"expo.out"},B(4));
|
|
177
|
+
tl.fromTo("#ctile",{scale:.9},{scale:1,duration:B(.5),ease:"back.out(2)"},B(4));
|
|
178
|
+
tiles.forEach(t=>tl.to(t.i,{scale:1,duration:.32,ease:"expo.out"},B(4)+t.d*.022));
|
|
179
|
+
// B. Tiles flip away from the edges in; the center tile flies to the i-dot and becomes it.
|
|
180
|
+
tiles.forEach(t=>tl.to(t.i,{scale:0,rotate:90,duration:.3,ease:"power3.in"},B(5.5)+(9-t.d)*.06));
|
|
181
|
+
tl.set("#guides",{opacity:1},B(6));
|
|
182
|
+
tl.to(".guide",{scaleX:1,duration:B(1),ease:"expo.out",stagger:.05},B(6));
|
|
183
|
+
tl.to(".guide.v",{scaleY:1,duration:B(1),ease:"expo.out",stagger:.05},B(6.1));
|
|
184
|
+
tl.to(".node",{scale:1,duration:.25,ease:"back.out(3)",stagger:.04},B(6.5));
|
|
185
|
+
tl.to("#ctile",{scale:.18,x:IDOT.x-960,y:IDOT.y-540,borderRadius:"50%",backgroundColor:"#FF3D59",duration:B(1),ease:"power3.inOut"},B(6));
|
|
186
|
+
tl.to("#ctile svg",{opacity:0,duration:.15},B(6));
|
|
187
|
+
tl.set("#ctile",{opacity:0},B(7)); tl.set("#idot",{left:IDOT.x,top:IDOT.y,scale:IDOT.d/44},B(7));
|
|
188
|
+
tl.to("#wmOutline",{clipPath:"inset(0 0% 0 0)",duration:B(1.2),ease:"power2.inOut"},B(6.5));
|
|
189
|
+
tl.to("#wmFill",{clipPath:"inset(0 0% 0 0)",duration:B(1),ease:"power3.inOut"},B(7.25));
|
|
190
|
+
tl.to(["#guides","#wmOutline"],{opacity:0,duration:B(1),ease:"power1.out"},B(8));
|
|
191
|
+
tl.to("#idot",{scaleX:IDOT.d/44*1.35,scaleY:IDOT.d/44*.7,duration:.07,yoyo:true,repeat:1,ease:"none"},B(8)); // beat-locked 4.0s
|
|
192
|
+
|
|
193
|
+
// C. Dive: wordmark tips back into the page, the real hero rises under it, rack focus, push to the period, pull back flat.
|
|
194
|
+
gsap.set("#plane",{rotateX:62,rotateZ:-20,z:-300,x:420,y:900,filter:"blur(10px)"});
|
|
195
|
+
tl.set("#sC",{opacity:1},B(8.5));
|
|
196
|
+
tl.to("#wm",{transformPerspective:1600,rotateX:62,rotateZ:-20,y:-330,scale:.55,duration:B(2),ease:"power3.in"},B(8.5));
|
|
197
|
+
tl.to("#idot",{x:-80,y:-360,scale:.4,duration:B(2),ease:"power3.in"},B(8.5));
|
|
198
|
+
tl.set(["#sB","#idot"],{opacity:0},B(10.5));
|
|
199
|
+
tl.to("#plane",{y:120,x:520,z:-120,duration:B(2.5),ease:"power3.out"},B(8.5));
|
|
200
|
+
tl.to("#plane",{filter:"blur(0px)",duration:B(1.5),ease:"power2.out"},B(9.5)); // rack focus
|
|
201
|
+
tl.to("#plane",{x:-90,y:20,z:180,rotateX:48,rotateZ:-14,duration:B(3),ease:"power2.inOut"},B(11));
|
|
202
|
+
tl.to("#plane",{rotateX:0,rotateZ:0,x:0,y:0,z:0,duration:B(2),ease:"expo.inOut"},B(13.75)); // close to wide
|
|
203
|
+
tl.to("#fog",{opacity:0,duration:B(2),ease:"power2.inOut"},B(13.75));
|
|
204
|
+
// beat-locked 8.00s: the headline period swells into the coral field (motif wipe).
|
|
205
|
+
tl.set("#burst",{opacity:1,scale:1},B(15.5));
|
|
206
|
+
tl.to("#burst",{scale:260,duration:B(.75),ease:"expo.in"},B(15.5));
|
|
207
|
+
tl.set("#sD",{opacity:1},B(16)); tl.set(["#sC","#burst"],{opacity:0},B(16));
|
|
208
|
+
|
|
209
|
+
// D. Exploded data on the coral field: real numbers from luckiest.co (captured 2026-09-30).
|
|
210
|
+
const slabIn=(id,b,rot)=>tl.fromTo(id,{y:700,rotateX:55,rotateY:rot[0],rotateZ:rot[1]},{y:0,rotateX:16,rotateY:rot[0]*.5,rotateZ:rot[1]*.5,duration:B(1.5),ease:"expo.out"},B(b));
|
|
211
|
+
slabIn("#s1",16.25,[-26,6]); slabIn("#s2",17,[22,-5]);
|
|
212
|
+
const cnt={a:0,b:0};
|
|
213
|
+
tl.to(cnt,{a:450,duration:B(2),ease:"power3.out",onUpdate:()=>{$("#n1").textContent=Math.round(cnt.a)}},B(16.5)); // beat-grid
|
|
214
|
+
tl.to(cnt,{b:400,duration:B(2),ease:"power3.out",onUpdate:()=>{$("#n2").textContent=Math.round(cnt.b)}},B(17.25));
|
|
215
|
+
tl.to(["#s1","#s2"],{y:-1100,rotateX:-30,duration:B(1.5),ease:"power3.in",stagger:.08},B(19));
|
|
216
|
+
gsap.set("#dropLabel",{y:30,opacity:0});
|
|
217
|
+
tl.to("#dropLabel",{y:0,opacity:.9,duration:B(1),ease:"expo.out"},B(19.5));
|
|
218
|
+
DOMAINS.forEach((_,k)=>tl.fromTo("#c"+k,{y:800,rotateX:70,rotateZ:-8},{y:0,rotateX:22,rotateZ:-3,duration:B(1.25),ease:"expo.out"},B(19.5+k*.5))); // beat-grid 9.75..11.25
|
|
219
|
+
// E. The field closes into a circle: people inside the motif.
|
|
220
|
+
tl.to(["#chips","#dropLabel"],{y:-160,duration:B(1.5),ease:"power2.in"},B(22));
|
|
221
|
+
tl.fromTo("#sD",{clipPath:"circle(2100px at 560px 540px)"},{clipPath:"circle(300px at 560px 540px)",duration:B(1),ease:"expo.inOut"},B(22.5)-0.067);
|
|
222
|
+
tl.set("#sE",{opacity:1},B(23.5)); tl.set("#sD",{opacity:0},B(23.5));
|
|
223
|
+
const imgs=$$("#pc img");
|
|
224
|
+
imgs.forEach((im,k)=>{tl.set(im,{opacity:1},B(23.5+k*.5)); tl.fromTo(im,{scale:1.18},{scale:1,duration:B(1),ease:"power2.out"},B(23.5+k*.5))});
|
|
225
|
+
gsap.set("#line .w",{yPercent:110});
|
|
226
|
+
$$("#line .w").forEach((w,k)=>tl.to(w,{yPercent:0,duration:B(1),ease:"expo.out"},B(23.5+k))); // beat-grid 11.75/12.25/12.75
|
|
227
|
+
gsap.set("#ldot",{y:-300,opacity:0});
|
|
228
|
+
tl.to("#ldot",{y:0,opacity:1,duration:B(.5),ease:"power2.in"},B(25.75));
|
|
229
|
+
tl.to("#ldot",{scaleX:1.4,scaleY:.7,duration:.07,yoyo:true,repeat:1,ease:"none",transformOrigin:"50% 100%"},B(26.25));
|
|
230
|
+
|
|
231
|
+
// F. Bookend: the line exits, the people circle shrinks into the wordmark's i-dot on the final hit (14.0s).
|
|
232
|
+
tl.to("#line",{x:1100,duration:B(1),ease:"power3.in"},B(26.5)); tl.set("#line",{opacity:0},B(27.5));
|
|
233
|
+
tl.set("#sB",{opacity:1},B(27)); tl.set(["#tiles"],{},B(27));
|
|
234
|
+
tl.set("#wm",{rotateX:0,rotateZ:0,y:0,scale:1},B(27)); tl.set("#wmOutline",{opacity:0},B(27));
|
|
235
|
+
tl.fromTo("#wmFill",{clipPath:"inset(0 100% 0 0)"},{clipPath:"inset(0 0% 0 0)",duration:B(1),ease:"power3.out"},B(27));
|
|
236
|
+
tl.to("#pc",{x:IDOT.x-560,y:IDOT.y-540,scale:IDOT.d/600,duration:B(1),ease:"power3.in"},B(27));
|
|
237
|
+
tl.to(imgs,{opacity:0,duration:.12},B(27.75));
|
|
238
|
+
tl.set("#pc",{opacity:0},B(28)); tl.set("#idot",{opacity:1,x:0,y:0,left:IDOT.x,top:IDOT.y,scale:IDOT.d/44},B(28));
|
|
239
|
+
tl.to("#idot",{scaleX:IDOT.d/44*1.4,scaleY:IDOT.d/44*.68,duration:.08,yoyo:true,repeat:1,ease:"none"},B(28)); // beat-locked 14.0s final hit
|
|
240
|
+
tl.set("#sF",{opacity:1},B(28.25));
|
|
241
|
+
tl.fromTo("#url",{y:24,opacity:0},{y:0,opacity:1,duration:B(1),ease:"expo.out"},B(28.25));
|
|
242
|
+
|
|
243
|
+
tl.to({},{duration:DUR},0);
|
|
244
|
+
// Paper-cut look: shoot on twos. A stepped tween drives the master's time, so every frame
|
|
245
|
+
// holds for 1/12 s, and each piece sits a seeded fraction of a degree off level.
|
|
246
|
+
let out=tl;
|
|
247
|
+
if(document.documentElement.dataset.look==="papercut"){
|
|
248
|
+
$$("#mosaic i,.slab,#ctile,#pc,#line .w").forEach((el,k)=>{el.style.rotate=((h(k+50)-.5)*2.4).toFixed(2)+"deg";el.style.translate=`${((h(k+90)-.5)*6).toFixed(1)}px ${((h(k+130)-.5)*6).toFixed(1)}px`});
|
|
249
|
+
out=gsap.timeline({paused:true}).to(tl,{time:DUR,duration:DUR,ease:`steps(${DUR*12})`},0);
|
|
250
|
+
}
|
|
251
|
+
window.__timelines=window.__timelines||{}; window.__timelines["main"]=out; out.seek(0);
|
|
252
|
+
// Browser preview: in any window that is not exactly 1920x1080, scale the frame to fit, letterboxed
|
|
253
|
+
// and centered. At the render size this is a no-op, so renders are untouched.
|
|
254
|
+
// Add #play to the URL to also loop playback (the renderer never sets the hash).
|
|
255
|
+
const root=$("#root"), fit=()=>{
|
|
256
|
+
if(innerWidth===1920&&innerHeight===1080){root.style.transform="";return}
|
|
257
|
+
const k=Math.min(innerWidth/1920,innerHeight/1080);
|
|
258
|
+
for(const el of [document.documentElement,document.body]) Object.assign(el.style,{width:"100vw",height:"100vh",background:"#000"});
|
|
259
|
+
Object.assign(root.style,{position:"absolute",width:"1920px",height:"1080px",transformOrigin:"0 0",
|
|
260
|
+
transform:`translate(${(innerWidth-1920*k)/2}px,${(innerHeight-1080*k)/2}px) scale(${k})`})};
|
|
261
|
+
fit(); addEventListener("resize",fit);
|
|
262
|
+
if(location.hash==="#play"){out.eventCallback("onComplete",()=>out.restart()); out.play(0)}
|
|
263
|
+
</script>
|
|
264
|
+
</body></html>
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog: luckiest-video-watcher
|
|
2
2
|
|
|
3
|
+
## 1.1.1 (2026-10-10)
|
|
4
|
+
|
|
5
|
+
- Security: the WhisperX setup's uv installer is pinned to 0.11.16 and saved to a
|
|
6
|
+
file before it runs on Windows and Linux. It no longer pipes the moving
|
|
7
|
+
`install.ps1` URL straight into PowerShell (SkillSpector SC2).
|
|
8
|
+
|
|
3
9
|
## 1.1.0 (2026-10-08)
|
|
4
10
|
|
|
5
11
|
Skill-updater pass, plus the marketplace listing.
|
|
@@ -19,7 +19,7 @@ argument-hint: "<video-url | path/to/video.mp4> [question] [--study]"
|
|
|
19
19
|
license: MIT. See ATTRIBUTION.md
|
|
20
20
|
allowed-tools: Bash, Read, Write, AskUserQuestion
|
|
21
21
|
metadata:
|
|
22
|
-
version: "1.1.
|
|
22
|
+
version: "1.1.1"
|
|
23
23
|
listing_id: luckiest-video-watcher
|
|
24
24
|
author: luckiest
|
|
25
25
|
---
|
|
@@ -39,11 +39,11 @@ run of a session, when setup fails, or when a run needs a detail not covered her
|
|
|
39
39
|
## Staying current
|
|
40
40
|
|
|
41
41
|
On activation, call the Luckiest MCP `check_updates` tool with
|
|
42
|
-
`{ listingId: "luckiest-video-watcher", installedSemver: "1.1.
|
|
42
|
+
`{ listingId: "luckiest-video-watcher", installedSemver: "1.1.1" }`. If
|
|
43
43
|
`upToDate: false`, surface the `notice` once and continue. Never block on it.
|
|
44
44
|
|
|
45
45
|
When done, call `report_usage` once with
|
|
46
|
-
`{ listing_id: "luckiest-video-watcher", skill_version: "1.1.
|
|
46
|
+
`{ listing_id: "luckiest-video-watcher", skill_version: "1.1.1", matched: true, success: <true|false> }`.
|
|
47
47
|
Metadata only. Skip silently if unavailable.
|
|
48
48
|
|
|
49
49
|
## Standing rules
|
|
@@ -18,6 +18,7 @@ from runtime import configure_stdio, diagnostic, run_text
|
|
|
18
18
|
|
|
19
19
|
REQUIRED_BINARIES = ['ffmpeg', 'ffprobe', 'yt-dlp']
|
|
20
20
|
WHISPERX_VERSION = '3.8.6'
|
|
21
|
+
UV_VERSION = '0.11.16' # pinned installer; bump deliberately
|
|
21
22
|
_PERM_WARNED: set[str] = set()
|
|
22
23
|
ENV_TEMPLATE = '''# /watch configuration. No shell interpolation; last assignment wins.
|
|
23
24
|
# Native captions always come first. Optional fallback: auto|whisperx|groq|openai|none.
|
|
@@ -247,14 +248,15 @@ def _ensure_uv():
|
|
|
247
248
|
if not _which('brew'):
|
|
248
249
|
raise SystemExit('WhisperX setup needs uv. Install Homebrew from https://brew.sh, then rerun setup.')
|
|
249
250
|
_install_step(['brew', 'install', 'uv'], 'Install uv')
|
|
250
|
-
elif system
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
elif system in ('Windows', 'Linux'):
|
|
252
|
+
# Pinned version, fetched to a file first: never pipe a moving URL into a shell.
|
|
253
|
+
windows = system == 'Windows'
|
|
254
|
+
url = f'https://astral.sh/uv/{UV_VERSION}/install.{"ps1" if windows else "sh"}'
|
|
254
255
|
with tempfile.TemporaryDirectory(prefix='watch-uv-') as temporary:
|
|
255
|
-
script = Path(temporary) / 'install.sh'
|
|
256
|
-
_install_step(['curl', '-LsSf',
|
|
257
|
-
|
|
256
|
+
script = Path(temporary) / ('install.ps1' if windows else 'install.sh')
|
|
257
|
+
_install_step(['curl', '-LsSf', url, '-o', script], f'Download uv {UV_VERSION} installer')
|
|
258
|
+
run = ['powershell', '-NoProfile', '-ExecutionPolicy', 'ByPass', '-File', script] if windows else ['sh', script]
|
|
259
|
+
_install_step(run, f'Install uv {UV_VERSION}')
|
|
258
260
|
else:
|
|
259
261
|
raise SystemExit('Install uv from https://docs.astral.sh/uv/ before retrying WhisperX setup.')
|
|
260
262
|
installed = _which('uv')
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface:
|
|
2
|
-
display_name: "Luckiest Trends"
|
|
3
|
-
short_description: "Research any topic across Reddit, X, YouTube, TikTok, Hacker News, Polymarket, GitHub, and the web over a time window you choose. Returns synthesized community-voice answers with vote-ranked citations."
|
|
4
|
-
default_prompt: "Research this topic over the last 30 days across Reddit, X, YouTube, TikTok, and the web. Synthesize what people are actually saying, upvoting, and sharing right now."
|
|
5
|
-
brand_color: "#FF6B35"
|
|
6
|
-
|
|
7
|
-
policy:
|
|
8
|
-
allow_implicit_invocation: true
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# build-skill.sh - package this repo as a claude.ai-upload-ready .skill file
|
|
3
|
-
# Usage: bash skills/last30days/scripts/build-skill.sh (run from repo root)
|
|
4
|
-
#
|
|
5
|
-
# Produces dist/last30days.skill, a zip with a single top-level `last30days/`
|
|
6
|
-
# directory containing SKILL.md and the scripts/ runtime from skills/last30days.
|
|
7
|
-
# See
|
|
8
|
-
# docs/plans/2026-04-14-001-fix-skill-upload-200-file-limit-plan.md.
|
|
9
|
-
set -euo pipefail
|
|
10
|
-
|
|
11
|
-
REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
|
|
12
|
-
cd "$REPO_ROOT"
|
|
13
|
-
|
|
14
|
-
if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
15
|
-
echo "error: working tree is dirty; commit or stash before building" >&2
|
|
16
|
-
exit 1
|
|
17
|
-
fi
|
|
18
|
-
|
|
19
|
-
mkdir -p dist
|
|
20
|
-
OUT="dist/last30days.skill"
|
|
21
|
-
git archive --format=zip --prefix=last30days/ --output="$OUT" HEAD:skills/last30days
|
|
22
|
-
|
|
23
|
-
COUNT=$(unzip -l "$OUT" | tail -1 | awk '{print $2}')
|
|
24
|
-
SIZE=$(du -h "$OUT" | cut -f1)
|
|
25
|
-
|
|
26
|
-
if [ "$COUNT" -gt 200 ]; then
|
|
27
|
-
echo "error: $COUNT files in zip, claude.ai's cap is 200" >&2
|
|
28
|
-
echo " check .gitattributes export-ignore entries and this script's zip -d excludes" >&2
|
|
29
|
-
exit 1
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
SKILL_MD_COUNT=$(unzip -l "$OUT" | grep -c "SKILL.md" || true)
|
|
33
|
-
if [ "$SKILL_MD_COUNT" -ne 1 ]; then
|
|
34
|
-
echo "error: expected exactly one SKILL.md, found $SKILL_MD_COUNT" >&2
|
|
35
|
-
exit 1
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
|
-
echo "built $OUT ($COUNT files, $SIZE)"
|
|
39
|
-
echo "upload via the claude.ai skill UI"
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# A/B test runner: public release vs private beta
|
|
3
|
-
# Usage: bash skills/last30days/scripts/compare.sh "Kanye West"
|
|
4
|
-
#
|
|
5
|
-
# Runs /last30days (public release) and /last30days-beta (private beta)
|
|
6
|
-
# sequentially with a 30s gap, saves raw results with distinct suffixes,
|
|
7
|
-
# prints file paths for comparison.
|
|
8
|
-
|
|
9
|
-
set -e
|
|
10
|
-
|
|
11
|
-
if [ $# -eq 0 ]; then
|
|
12
|
-
echo "Usage: bash skills/last30days/scripts/compare.sh <topic>"
|
|
13
|
-
echo " Example: bash skills/last30days/scripts/compare.sh Kevin Rose"
|
|
14
|
-
exit 1
|
|
15
|
-
fi
|
|
16
|
-
TOPIC="$*"
|
|
17
|
-
SLUG=$(echo "$TOPIC" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//' | sed 's/-$//')
|
|
18
|
-
LAST30DAYS_MEMORY_DIR="${LAST30DAYS_MEMORY_DIR:-$HOME/Documents/Last30Days}"
|
|
19
|
-
DIR="$LAST30DAYS_MEMORY_DIR"
|
|
20
|
-
DATE=$(date +%Y-%m-%d)
|
|
21
|
-
|
|
22
|
-
echo "=============================================="
|
|
23
|
-
echo " A/B Test: $TOPIC"
|
|
24
|
-
echo " Date: $DATE"
|
|
25
|
-
echo "=============================================="
|
|
26
|
-
echo ""
|
|
27
|
-
|
|
28
|
-
# Run 1: public release
|
|
29
|
-
echo "[1/2] Running /last30days (public release)..."
|
|
30
|
-
echo " This takes 2-4 minutes..."
|
|
31
|
-
claude -p "/last30days $TOPIC" > /dev/null 2>&1 || true
|
|
32
|
-
RELEASE_FILE="$DIR/${SLUG}-raw.md"
|
|
33
|
-
[ -f "$RELEASE_FILE" ] && echo " Done: $RELEASE_FILE" || echo " FAILED: no output file"
|
|
34
|
-
echo ""
|
|
35
|
-
|
|
36
|
-
echo " Waiting 30s for API rate limits..."
|
|
37
|
-
sleep 30
|
|
38
|
-
|
|
39
|
-
# Run 2: private beta
|
|
40
|
-
echo "[2/2] Running /last30days-beta (private beta)..."
|
|
41
|
-
echo " This takes 2-4 minutes..."
|
|
42
|
-
claude -p "/last30days-beta $TOPIC" > /dev/null 2>&1 || true
|
|
43
|
-
BETA_FILE="$DIR/${SLUG}-raw-beta.md"
|
|
44
|
-
[ -f "$BETA_FILE" ] && echo " Done: $BETA_FILE" || echo " FAILED: no output file"
|
|
45
|
-
echo ""
|
|
46
|
-
|
|
47
|
-
echo "=============================================="
|
|
48
|
-
echo " Both complete. Raw files:"
|
|
49
|
-
echo "=============================================="
|
|
50
|
-
echo ""
|
|
51
|
-
ls -la "$DIR/${SLUG}-raw"*.md 2>/dev/null || echo " (no files found - check if skills saved correctly)"
|
|
52
|
-
echo ""
|
|
53
|
-
echo "To compare, run in Claude Code:"
|
|
54
|
-
echo " Read and compare these raw research files, produce a detailed report:"
|
|
55
|
-
echo " $RELEASE_FILE"
|
|
56
|
-
echo " $BETA_FILE"
|
|
57
|
-
echo ""
|
|
58
|
-
echo "Beta output should start with a line like:"
|
|
59
|
-
echo " 🧪 last30days-beta · branch <name> · synced $DATE"
|
|
60
|
-
echo "If that line is missing, the beta badge regressed. See docs/plans/2026-04-17-005-*-plan.md."
|
|
61
|
-
echo ""
|