@growthub/cli 0.3.33 → 0.3.35
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.md +21 -0
- package/assets/worker-kits/creative-strategist-v1/brands/_template/brand-kit.md +123 -0
- package/assets/worker-kits/creative-strategist-v1/brands/solawave/brand-kit.md +139 -0
- package/assets/worker-kits/creative-strategist-v1/bundles/creative-strategist-v1.json +46 -0
- package/assets/worker-kits/creative-strategist-v1/growthub-meta/README.md +14 -0
- package/assets/worker-kits/creative-strategist-v1/growthub-meta/kit-standard.md +47 -0
- package/assets/worker-kits/creative-strategist-v1/kit.json +72 -0
- package/assets/worker-kits/creative-strategist-v1/skills.md +341 -0
- package/assets/worker-kits/creative-strategist-v1/templates/ad-formats/INDEX.md +94 -0
- package/assets/worker-kits/creative-strategist-v1/templates/ad-formats/bedroom-minimic-talk.md +197 -0
- package/assets/worker-kits/creative-strategist-v1/templates/ad-formats/frame-analysis.md +209 -0
- package/assets/worker-kits/creative-strategist-v1/templates/ad-formats/process-specialist-medical.md +105 -0
- package/assets/worker-kits/creative-strategist-v1/templates/ad-formats/villain-animation.md +183 -0
- package/assets/worker-kits/creative-strategist-v1/templates/brief-template.js +470 -0
- package/assets/worker-kits/creative-strategist-v1/templates/hooks-library/500-winning-hooks.csv +539 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/INDEX.md +151 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/body/before-after-flatlay.md +143 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/body/minimic-problem.md +109 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/body/product-demo-glow.md +123 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/body/tiktok-skeptic-pivot.md +119 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/body/villain-agitation.md +156 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/cta/bogo-meme-bookend.md +144 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/cta/guarantee-close.md +143 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/hooks/dollar-amount.md +105 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/hooks/meme-overlay.md +104 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/hooks/pov-confession.md +92 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/hooks/tiktok-comment.md +116 -0
- package/assets/worker-kits/creative-strategist-v1/templates/scene-modules/hooks/villain-hook.md +134 -0
- package/assets/worker-kits/creative-strategist-v1/workers/creative-strategist/CLAUDE.md +440 -0
- package/dist/index.js +206 -0
- package/package.json +3 -2
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VIDEO CREATIVE BRIEF — BASE TEMPLATE
|
|
3
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
* HOW TO USE:
|
|
5
|
+
* 1. Copy this file: cp brief-template.js /tmp/docx_work/<slug>_brief_v1.js
|
|
6
|
+
* 2. Fill in every CONFIG value from the client's brand-kit.md
|
|
7
|
+
* 3. Replace all [PLACEHOLDER] values in CONTENT with real brief content
|
|
8
|
+
* 4. Run: cd /tmp/docx_work && node <slug>_brief_v1.js
|
|
9
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
|
|
14
|
+
AlignmentType, BorderStyle, WidthType, ShadingType, HeadingLevel,
|
|
15
|
+
VerticalAlign, PageNumber, Header, Footer, PageBreak, ExternalHyperlink
|
|
16
|
+
} = require('docx');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
|
|
19
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
20
|
+
// CONFIG — pull every value from brand-kit.md
|
|
21
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
22
|
+
const CONFIG = {
|
|
23
|
+
// Brand identity
|
|
24
|
+
client_name: "[CLIENT NAME]", // e.g. "Green Tree Wellness"
|
|
25
|
+
doctor_name: "[DR. NAME, CREDENTIALS]", // e.g. "Dr. Anthony Carabasi, DO"
|
|
26
|
+
campaign_name: "[CAMPAIGN NAME]", // e.g. "Regenerative Medicine — Spring 2026"
|
|
27
|
+
date: "[MONTH YEAR]", // e.g. "April 2026"
|
|
28
|
+
output_path: "/Users/antonio/Downloads/[ClientSlug]_Video_Creative_Brief_v1_[DATE].docx",
|
|
29
|
+
|
|
30
|
+
// Brief metadata
|
|
31
|
+
video_length: "[XX seconds]",
|
|
32
|
+
hook_count: 5, // number of hook variations (A–E by default)
|
|
33
|
+
primary_goal: "[Conversion / Awareness / Education / Trust-Building]",
|
|
34
|
+
|
|
35
|
+
// Colors (hex, no #) — from brand-kit.md
|
|
36
|
+
color_primary: "2D6A4F", // main brand color — used for section headers
|
|
37
|
+
color_secondary: "40916C", // accent — used for sub-heads, scene bars, hook stripe
|
|
38
|
+
color_light: "D8F3DC", // light tint — table shading, backgrounds
|
|
39
|
+
color_dark: "1B1B1B", // body text
|
|
40
|
+
color_mid_gray: "6B7280", // footer, secondary text
|
|
41
|
+
color_white: "FFFFFF",
|
|
42
|
+
color_warn_bg: "FFF8E1", // alert box background
|
|
43
|
+
color_warn_border: "E5A800", // alert box border
|
|
44
|
+
|
|
45
|
+
// Constraint / guardrail message (from brand-kit.md → messaging_guardrails)
|
|
46
|
+
brand_constraint: "[PASTE THE CRITICAL BRAND CONSTRAINT HERE — what this ad must NEVER say or do]",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
50
|
+
// CONTENT — fill in from brief inputs + brand kit
|
|
51
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
52
|
+
const BRIEF = {
|
|
53
|
+
// ── Brief Overview fields ────────────────────────────────────────────────
|
|
54
|
+
overview: [
|
|
55
|
+
["Length", CONFIG.video_length],
|
|
56
|
+
["Format", "[UGC + B-Roll / Doctor-Led / Explainer / Performance CTA]"],
|
|
57
|
+
["Primary Goal", CONFIG.primary_goal],
|
|
58
|
+
["Voiceover", "[Who speaks + what role — e.g. AI UGC on-camera + warm male VO]"],
|
|
59
|
+
["Tone", "[3–5 adjectives from brand kit — e.g. Warm, Credible, Science-informed]"],
|
|
60
|
+
["AI Avatar Required", "[Yes / No] → Type: [Photoreal / Talking Head / UGC]"],
|
|
61
|
+
["Voiceover Setup", "[VO only / VO + sync / UGC dialogue + VO / founder VO / AI VO]"],
|
|
62
|
+
["Voice Type", "[Male/Female/Neutral | Age | Tone | Accent]"],
|
|
63
|
+
["UGC Asset Requirements","[Yes / No] → Folder: [link or creator reference]"],
|
|
64
|
+
["Brand Image Availability","[Air.inc / Drive / Instagram / Website link]"],
|
|
65
|
+
["Video References", "[Inspiration links or 'None provided']"],
|
|
66
|
+
],
|
|
67
|
+
|
|
68
|
+
// ── Core Ad Concept ──────────────────────────────────────────────────────
|
|
69
|
+
concept_paragraph_1: "[High-level description of the ad concept, narrative, and intended emotional impact. Who is the main subject? What is their journey? How does the brand solve their problem?]",
|
|
70
|
+
concept_paragraph_2: "[Optional second paragraph — positioning, differentiation, or strategic context.]",
|
|
71
|
+
emotional_arc: "[Struggle → Recognition → Transformation → Action]", // customize per brand
|
|
72
|
+
concept_kv: [
|
|
73
|
+
["Target Audience", "[Age range + pain point + intent]"],
|
|
74
|
+
["Core Message", "[One sentence — the brand promise delivered through this video]"],
|
|
75
|
+
["B-Roll Cadence", "[e.g. Cut every ~3 seconds — never >3s of uninterrupted talking head]"],
|
|
76
|
+
["What to AVOID", "[Specific language, imagery, or patient types to exclude — from brand kit]"],
|
|
77
|
+
],
|
|
78
|
+
|
|
79
|
+
// ── Scene 1: Hook intro note ─────────────────────────────────────────────
|
|
80
|
+
hook_intro: "[N] hook variations are provided below. Test all [N] as separate ad sets. Scene 1 is the only section that changes between variations — Scenes 2, 3, and 4 remain identical across all.",
|
|
81
|
+
|
|
82
|
+
// ── Scene 1 block (shared across all hooks) ──────────────────────────────
|
|
83
|
+
scene1_rows: [
|
|
84
|
+
["On-Screen Text", "[None / specific text overlay]"],
|
|
85
|
+
["VO", "[None — AI UGC actor speaks directly / or specify VO line]"],
|
|
86
|
+
["Client Line", "[Opening hook dialogue — the scroll-stopping line]"],
|
|
87
|
+
["Purpose", "[Strategic role of this scene — what it must achieve in 0–3 seconds]"],
|
|
88
|
+
],
|
|
89
|
+
|
|
90
|
+
// ── Hook Variations — add/remove as needed ───────────────────────────────
|
|
91
|
+
hooks: [
|
|
92
|
+
{
|
|
93
|
+
letter: "A",
|
|
94
|
+
label: "[Hook A — Short Descriptive Label]",
|
|
95
|
+
content: "[Shot description, camera movement, lighting, mood, actor direction for Hook A]"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
letter: "B",
|
|
99
|
+
label: "[Hook B — Short Descriptive Label]",
|
|
100
|
+
content: "[Shot description, camera movement, lighting, mood, actor direction for Hook B]"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
letter: "C",
|
|
104
|
+
label: "[Hook C — Short Descriptive Label]",
|
|
105
|
+
content: "[Shot description, camera movement, lighting, mood, actor direction for Hook C]"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
letter: "D",
|
|
109
|
+
label: "[Hook D — Short Descriptive Label]",
|
|
110
|
+
content: "[Shot description, camera movement, lighting, mood, actor direction for Hook D]"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
letter: "E",
|
|
114
|
+
label: "[Hook E — Short Descriptive Label]",
|
|
115
|
+
content: "[Shot description, camera movement, lighting, mood, actor direction for Hook E]"
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
|
|
119
|
+
// ── Scene 2 ──────────────────────────────────────────────────────────────
|
|
120
|
+
scene2_title: "SCENE 2 — [Name: e.g. The Struggle & Recognition]",
|
|
121
|
+
scene2_timecode: "[8–16 seconds] | Consistent across all [N] variations",
|
|
122
|
+
scene2_rows: [
|
|
123
|
+
["Visual Direction", "[B-roll description — what we see, in what order, with what emotional purpose]"],
|
|
124
|
+
["VO", "[VO line — word for word]"],
|
|
125
|
+
["On-Screen Text", "[Text overlay or 'None']"],
|
|
126
|
+
["Purpose", "[Strategic role of this scene]"],
|
|
127
|
+
["Transition", "[How we move from this scene to the next]"],
|
|
128
|
+
],
|
|
129
|
+
|
|
130
|
+
// ── Scene 3 ──────────────────────────────────────────────────────────────
|
|
131
|
+
scene3_title: "SCENE 3 — [Name: e.g. Transformation & Results]",
|
|
132
|
+
scene3_timecode: "[16–24 seconds] | Consistent across all [N] variations",
|
|
133
|
+
scene3_rows: [
|
|
134
|
+
["Visual Direction", "[B-roll / on-camera description — the 'after' state]"],
|
|
135
|
+
["Client VO (on-camera)", "[On-camera dialogue line]"],
|
|
136
|
+
["On-Screen Text", "[Text overlay or 'None']"],
|
|
137
|
+
["Purpose", "[Strategic role — proof, transformation, emotion]"],
|
|
138
|
+
["Transition", "[Scene transition type]"],
|
|
139
|
+
],
|
|
140
|
+
|
|
141
|
+
// ── Scene 4: CTA ─────────────────────────────────────────────────────────
|
|
142
|
+
scene4_title: "SCENE 4 — CTA + Offer Close",
|
|
143
|
+
scene4_timecode: "[24–32 seconds] | Consistent across all [N] variations",
|
|
144
|
+
scene4_rows: [
|
|
145
|
+
["Visual Direction", "[Branded close — doctor/founder + logo + CTA graphics]"],
|
|
146
|
+
["Male VO (CTA)", "[CTA line — word for word. Include: doctor name, brand name, action, urgency]"],
|
|
147
|
+
["On-Screen Text", "[Brand Name]\n[Service Name]\n[Phone Number] | [Website]\n[CTA Offer Text]"],
|
|
148
|
+
["Purpose", "[Drive the one action: consultation booking / call / website visit]"],
|
|
149
|
+
],
|
|
150
|
+
|
|
151
|
+
// ── Editing Guidelines ───────────────────────────────────────────────────
|
|
152
|
+
editing_guidelines: [
|
|
153
|
+
"[B-roll cadence rule — e.g. cut every ~3 seconds]",
|
|
154
|
+
"[Color grade direction — e.g. warm golden tones / clinical cool / vibrant energetic]",
|
|
155
|
+
"[Music direction — e.g. warm emotional underscore / upbeat lifestyle / no music]",
|
|
156
|
+
"[Caption rule — always ON by default]",
|
|
157
|
+
"[On-screen text rule — when it appears and when it doesn't]",
|
|
158
|
+
"[Pacing note — measured/human vs fast-cut performance]",
|
|
159
|
+
"[End frame description — what the last 2 seconds look like]",
|
|
160
|
+
"[Specific NO list — imagery or language to never use]",
|
|
161
|
+
"[UGC actor age/look requirement]",
|
|
162
|
+
"[CTA readability note — phone number size for target audience]",
|
|
163
|
+
],
|
|
164
|
+
aspect_ratios: [
|
|
165
|
+
"9:16 (Instagram/TikTok Reels, Stories) — Primary",
|
|
166
|
+
"1:1 (Facebook / Instagram Feed) — Secondary",
|
|
167
|
+
"16:9 (YouTube Pre-Roll) — Optional",
|
|
168
|
+
],
|
|
169
|
+
|
|
170
|
+
// ── Appendix: AI Video Prompts (OPTIONAL) ────────────────────────────────
|
|
171
|
+
// One entry per hook + one per scene (2, 3, 4)
|
|
172
|
+
appendix_prompts: [
|
|
173
|
+
{ label: "HOOK A — [Label]", prompt: "[Full Veo 3.1 / Runway / Sora generation prompt for Hook A]" },
|
|
174
|
+
{ label: "HOOK B — [Label]", prompt: "[Full prompt for Hook B]" },
|
|
175
|
+
{ label: "HOOK C — [Label]", prompt: "[Full prompt for Hook C]" },
|
|
176
|
+
{ label: "HOOK D — [Label]", prompt: "[Full prompt for Hook D]" },
|
|
177
|
+
{ label: "HOOK E — [Label]", prompt: "[Full prompt for Hook E]" },
|
|
178
|
+
{ label: "SCENE 2 — B-Roll Prompt", prompt: "[Full prompt for Scene 2 B-roll generation]" },
|
|
179
|
+
{ label: "SCENE 3 — Transformation B-Roll", prompt: "[Full prompt for Scene 3 B-roll]" },
|
|
180
|
+
{ label: "SCENE 4 — CTA Close", prompt: "[Full prompt for Scene 4 branded close]" },
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
185
|
+
// DESIGN SYSTEM — do not edit below this line unless changing structure
|
|
186
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
187
|
+
const C = CONFIG; // shorthand
|
|
188
|
+
const bdr = { style: BorderStyle.SINGLE, size: 1, color: C.color_light };
|
|
189
|
+
const bdrs = { top: bdr, bottom: bdr, left: bdr, right: bdr };
|
|
190
|
+
const noBdr = { style: BorderStyle.NONE, size: 0, color: C.color_white };
|
|
191
|
+
const noBdrs= { top: noBdr, bottom: noBdr, left: noBdr, right: noBdr };
|
|
192
|
+
|
|
193
|
+
const sp = (pts=120) => new Paragraph({ spacing:{before:pts,after:0}, children:[] });
|
|
194
|
+
|
|
195
|
+
function run(text, opts={}) {
|
|
196
|
+
return new TextRun({ text, font:"Arial", size:20, color:C.color_dark, ...opts });
|
|
197
|
+
}
|
|
198
|
+
function para(children, opts={}) {
|
|
199
|
+
return new Paragraph({ spacing:{before:60,after:60}, children, ...opts });
|
|
200
|
+
}
|
|
201
|
+
function bullet(text) {
|
|
202
|
+
return new Paragraph({
|
|
203
|
+
spacing:{before:40,after:40}, indent:{left:400,hanging:280},
|
|
204
|
+
children:[
|
|
205
|
+
new TextRun({ text:"• ", bold:true, color:C.color_secondary, font:"Arial", size:20 }),
|
|
206
|
+
new TextRun({ text, font:"Arial", size:20, color:C.color_dark })
|
|
207
|
+
]
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
function h2(text) {
|
|
211
|
+
// Uses Heading2 style (defined in paragraphStyles above) inside a colored cell.
|
|
212
|
+
// This makes headings semantic and TOC-compatible while preserving the visual bar.
|
|
213
|
+
return new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[9360],
|
|
214
|
+
rows:[new TableRow({ children:[new TableCell({
|
|
215
|
+
borders:noBdrs, shading:{fill:C.color_primary,type:ShadingType.CLEAR},
|
|
216
|
+
margins:{top:100,bottom:100,left:200,right:200},
|
|
217
|
+
children:[new Paragraph({ heading:HeadingLevel.HEADING_2, spacing:{before:30,after:30},
|
|
218
|
+
children:[new TextRun({text,bold:true,size:24,font:"Arial",color:C.color_white})] })]
|
|
219
|
+
})]})]
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
function h3(text) {
|
|
223
|
+
// Uses Heading3 style with left-border accent. Standalone paragraph (no table).
|
|
224
|
+
return new Paragraph({
|
|
225
|
+
heading: HeadingLevel.HEADING_3,
|
|
226
|
+
spacing:{before:220,after:80},
|
|
227
|
+
border:{left:{style:BorderStyle.THICK,size:12,color:C.color_secondary}},
|
|
228
|
+
indent:{left:160},
|
|
229
|
+
children:[new TextRun({text,bold:true,size:22,font:"Arial",color:C.color_secondary})]
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
// External hyperlink — use for muse URLs, reference links, landing pages
|
|
233
|
+
function hyperlink(displayText, url) {
|
|
234
|
+
return new ExternalHyperlink({
|
|
235
|
+
link: url,
|
|
236
|
+
children:[new TextRun({text:displayText,style:"Hyperlink",font:"Arial",size:20})]
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function kvRow(label, value, shade) {
|
|
240
|
+
return new TableRow({ children:[
|
|
241
|
+
new TableCell({ borders:bdrs, width:{size:2800,type:WidthType.DXA},
|
|
242
|
+
shading:{fill:shade?C.color_light:"F4FCF6",type:ShadingType.CLEAR},
|
|
243
|
+
margins:{top:80,bottom:80,left:160,right:160},
|
|
244
|
+
children:[para([new TextRun({text:label,bold:true,size:19,font:"Arial",color:C.color_secondary})])]
|
|
245
|
+
}),
|
|
246
|
+
new TableCell({ borders:bdrs, width:{size:6560,type:WidthType.DXA},
|
|
247
|
+
margins:{top:80,bottom:80,left:160,right:160},
|
|
248
|
+
children:[para([run(value,{size:19})])]
|
|
249
|
+
})
|
|
250
|
+
]});
|
|
251
|
+
}
|
|
252
|
+
function kvTable(rows) {
|
|
253
|
+
return new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[2800,6560],
|
|
254
|
+
rows: rows.map(([l,v],i) => kvRow(l,v,i%2===0))
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function alertBox(text) {
|
|
258
|
+
return new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[9360],
|
|
259
|
+
rows:[new TableRow({ children:[new TableCell({
|
|
260
|
+
borders:{top:{style:BorderStyle.SINGLE,size:4,color:C.color_warn_border},bottom:{style:BorderStyle.SINGLE,size:4,color:C.color_warn_border},left:{style:BorderStyle.THICK,size:20,color:C.color_warn_border},right:bdr},
|
|
261
|
+
shading:{fill:C.color_warn_bg,type:ShadingType.CLEAR},
|
|
262
|
+
margins:{top:120,bottom:120,left:220,right:220},
|
|
263
|
+
children:[para([new TextRun({text:"⚠ "+text,bold:true,size:19,font:"Arial",color:"7D4E00"})])]
|
|
264
|
+
})]})]
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function sceneBlock(title, timecode, rows) {
|
|
268
|
+
const hRow = new TableRow({ children:[new TableCell({
|
|
269
|
+
columnSpan:2, borders:bdrs,
|
|
270
|
+
shading:{fill:C.color_secondary,type:ShadingType.CLEAR},
|
|
271
|
+
margins:{top:100,bottom:100,left:200,right:200},
|
|
272
|
+
children:[para([new TextRun({text:`${title} | ${timecode}`,bold:true,size:21,font:"Arial",color:C.color_white})])]
|
|
273
|
+
})]});
|
|
274
|
+
const dRows = rows.filter(Boolean).map(([lbl,content]) =>
|
|
275
|
+
new TableRow({ children:[
|
|
276
|
+
new TableCell({ borders:bdrs, width:{size:1800,type:WidthType.DXA},
|
|
277
|
+
shading:{fill:C.color_light,type:ShadingType.CLEAR},
|
|
278
|
+
margins:{top:70,bottom:70,left:160,right:160},
|
|
279
|
+
children:[para([new TextRun({text:lbl,bold:true,size:18,font:"Arial",color:C.color_secondary})])]
|
|
280
|
+
}),
|
|
281
|
+
new TableCell({ borders:bdrs, width:{size:7560,type:WidthType.DXA},
|
|
282
|
+
margins:{top:70,bottom:70,left:160,right:160},
|
|
283
|
+
children: content.split("\n\n").map(b=>new Paragraph({spacing:{before:40,after:40},children:[run(b,{size:19})]}))
|
|
284
|
+
})
|
|
285
|
+
]})
|
|
286
|
+
);
|
|
287
|
+
return new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[1800,7560], rows:[hRow,...dRows] });
|
|
288
|
+
}
|
|
289
|
+
function hookCard(letter, label, content) {
|
|
290
|
+
return new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[200,9160],
|
|
291
|
+
rows:[new TableRow({ children:[
|
|
292
|
+
new TableCell({ borders:noBdrs, width:{size:200,type:WidthType.DXA},
|
|
293
|
+
shading:{fill:C.color_secondary,type:ShadingType.CLEAR},
|
|
294
|
+
margins:{top:100,bottom:100,left:60,right:60}, verticalAlign:VerticalAlign.CENTER,
|
|
295
|
+
children:[para([new TextRun({text:letter,bold:true,size:22,font:"Arial",color:C.color_white})],{alignment:AlignmentType.CENTER})]
|
|
296
|
+
}),
|
|
297
|
+
new TableCell({ borders:{top:bdr,bottom:bdr,left:noBdr,right:bdr},
|
|
298
|
+
shading:{fill:"F4FCF6",type:ShadingType.CLEAR},
|
|
299
|
+
margins:{top:100,bottom:100,left:200,right:200},
|
|
300
|
+
children:[
|
|
301
|
+
para([new TextRun({text:`HOOK ${letter} — ${label}`,bold:true,size:20,font:"Arial",color:C.color_secondary})]),
|
|
302
|
+
...content.split("\n\n").map(b=>new Paragraph({spacing:{before:40,after:40},children:[run(b,{size:19})]}))
|
|
303
|
+
]
|
|
304
|
+
})
|
|
305
|
+
]})]
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
310
|
+
// DOCUMENT ASSEMBLY
|
|
311
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
312
|
+
const doc = new Document({
|
|
313
|
+
styles:{
|
|
314
|
+
default:{ document:{ run:{ font:"Arial", size:20, color:C.color_dark } } },
|
|
315
|
+
paragraphStyles:[
|
|
316
|
+
// Heading2: used for colored section bars (white text, rendered inside colored table cells)
|
|
317
|
+
{ id:"Heading2", name:"Heading 2", basedOn:"Normal", next:"Normal", quickFormat:true,
|
|
318
|
+
run:{ bold:true, size:21, font:"Arial", color:"FFFFFF" },
|
|
319
|
+
paragraph:{ spacing:{ before:30, after:30 }, outlineLevel:1 } },
|
|
320
|
+
// Heading3: used for sub-section labels (blue accent, standalone paragraph with left border)
|
|
321
|
+
{ id:"Heading3", name:"Heading 3", basedOn:"Normal", next:"Normal", quickFormat:true,
|
|
322
|
+
run:{ bold:true, size:22, font:"Arial", color:C.color_secondary },
|
|
323
|
+
paragraph:{ spacing:{ before:220, after:80 }, outlineLevel:2 } },
|
|
324
|
+
]
|
|
325
|
+
},
|
|
326
|
+
sections:[{
|
|
327
|
+
properties:{
|
|
328
|
+
page:{
|
|
329
|
+
size:{ width:12240, height:15840 },
|
|
330
|
+
margin:{ top:1440, right:1440, bottom:1440, left:1440 } // 1 inch — matches 9360 table widths
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
headers:{
|
|
334
|
+
default: new Header({ children:[
|
|
335
|
+
new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[5820,3540],
|
|
336
|
+
rows:[new TableRow({ children:[
|
|
337
|
+
new TableCell({ borders:noBdrs, shading:{fill:C.color_primary,type:ShadingType.CLEAR}, margins:{top:80,bottom:80,left:200,right:200},
|
|
338
|
+
children:[para([new TextRun({text:`${C.client_name} | Video Creative Brief`,bold:true,size:20,font:"Arial",color:C.color_white})])]
|
|
339
|
+
}),
|
|
340
|
+
new TableCell({ borders:noBdrs, shading:{fill:C.color_secondary,type:ShadingType.CLEAR}, verticalAlign:VerticalAlign.CENTER, margins:{top:80,bottom:80,left:160,right:160},
|
|
341
|
+
children:[para([new TextRun({text:`${C.campaign_name} | ${C.date}`,size:18,font:"Arial",color:C.color_white})],{alignment:AlignmentType.RIGHT})]
|
|
342
|
+
})
|
|
343
|
+
]})]
|
|
344
|
+
})
|
|
345
|
+
]})
|
|
346
|
+
},
|
|
347
|
+
footers:{
|
|
348
|
+
default: new Footer({ children:[
|
|
349
|
+
para([
|
|
350
|
+
run(`${C.client_name} — Confidential | Page `,{size:17,color:C.color_mid_gray}),
|
|
351
|
+
new TextRun({children:[PageNumber.CURRENT],size:17,font:"Arial",color:C.color_mid_gray})
|
|
352
|
+
])
|
|
353
|
+
]})
|
|
354
|
+
},
|
|
355
|
+
children:[
|
|
356
|
+
// TITLE BLOCK
|
|
357
|
+
sp(40),
|
|
358
|
+
new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[9360],
|
|
359
|
+
rows:[new TableRow({ children:[new TableCell({
|
|
360
|
+
borders:noBdrs, shading:{fill:C.color_primary,type:ShadingType.CLEAR},
|
|
361
|
+
margins:{top:280,bottom:280,left:360,right:360},
|
|
362
|
+
children:[
|
|
363
|
+
new Paragraph({alignment:AlignmentType.CENTER, children:[new TextRun({text:C.client_name.toUpperCase(),bold:true,size:56,font:"Arial",color:C.color_white})]}),
|
|
364
|
+
new Paragraph({alignment:AlignmentType.CENTER, spacing:{before:80}, children:[new TextRun({text:`Video Creative Brief — ${C.campaign_name}`,size:26,font:"Arial",color:C.color_light})]}),
|
|
365
|
+
new Paragraph({alignment:AlignmentType.CENTER, spacing:{before:60}, children:[new TextRun({text:`1 Video Creative | ${C.hook_count} Hook Variations | ${C.date}`,size:20,font:"Arial",color:C.color_light})]}),
|
|
366
|
+
]
|
|
367
|
+
})]})]
|
|
368
|
+
}),
|
|
369
|
+
sp(160),
|
|
370
|
+
|
|
371
|
+
// BRAND CONSTRAINT ALERT
|
|
372
|
+
alertBox(C.brand_constraint),
|
|
373
|
+
sp(160),
|
|
374
|
+
|
|
375
|
+
// BRIEF OVERVIEW
|
|
376
|
+
h2("BRIEF OVERVIEW"),
|
|
377
|
+
sp(80),
|
|
378
|
+
kvTable(BRIEF.overview),
|
|
379
|
+
sp(180),
|
|
380
|
+
|
|
381
|
+
// 1. CORE AD CONCEPT
|
|
382
|
+
h2("1. CORE AD CONCEPT"),
|
|
383
|
+
sp(80),
|
|
384
|
+
para([run(BRIEF.concept_paragraph_1)]),
|
|
385
|
+
...(BRIEF.concept_paragraph_2 ? [sp(60), para([run(BRIEF.concept_paragraph_2)])] : []),
|
|
386
|
+
sp(60),
|
|
387
|
+
para([new TextRun({text:`Emotional arc: ${BRIEF.emotional_arc}`,bold:true,color:C.color_secondary,size:20,font:"Arial"})]),
|
|
388
|
+
sp(80),
|
|
389
|
+
kvTable(BRIEF.concept_kv),
|
|
390
|
+
sp(180),
|
|
391
|
+
|
|
392
|
+
// 2. STRUCTURE & VO
|
|
393
|
+
h2("2. STRUCTURE & VOICEOVER BREAKDOWN"),
|
|
394
|
+
sp(120),
|
|
395
|
+
|
|
396
|
+
// Scene 1
|
|
397
|
+
h3(`A. SCENE 1 — Opening Hook (0–${Math.round(32/4)} seconds)`),
|
|
398
|
+
sp(60),
|
|
399
|
+
para([new TextRun({text:BRIEF.hook_intro,italics:true,size:19,font:"Arial",color:C.color_mid_gray})]),
|
|
400
|
+
sp(80),
|
|
401
|
+
sceneBlock("SCENE 1 — HOOK WINDOW","0–3 seconds | MUST stop the scroll",BRIEF.scene1_rows),
|
|
402
|
+
sp(100),
|
|
403
|
+
para([new TextRun({text:`${C.hook_count} HOOK VARIATIONS — Scene 1 Only`,bold:true,size:22,font:"Arial",color:C.color_primary})]),
|
|
404
|
+
sp(60),
|
|
405
|
+
...BRIEF.hooks.flatMap(h => [hookCard(h.letter, h.label, h.content), sp(80)]),
|
|
406
|
+
sp(60),
|
|
407
|
+
|
|
408
|
+
// Scene 2
|
|
409
|
+
h3(`B. ${BRIEF.scene2_title}`),
|
|
410
|
+
sp(80),
|
|
411
|
+
sceneBlock(BRIEF.scene2_title, BRIEF.scene2_timecode, BRIEF.scene2_rows),
|
|
412
|
+
sp(140),
|
|
413
|
+
|
|
414
|
+
// Scene 3
|
|
415
|
+
h3(`C. ${BRIEF.scene3_title}`),
|
|
416
|
+
sp(80),
|
|
417
|
+
sceneBlock(BRIEF.scene3_title, BRIEF.scene3_timecode, BRIEF.scene3_rows),
|
|
418
|
+
sp(140),
|
|
419
|
+
|
|
420
|
+
// Scene 4
|
|
421
|
+
h3(`D. ${BRIEF.scene4_title}`),
|
|
422
|
+
sp(80),
|
|
423
|
+
sceneBlock(BRIEF.scene4_title, BRIEF.scene4_timecode, BRIEF.scene4_rows),
|
|
424
|
+
sp(180),
|
|
425
|
+
|
|
426
|
+
// 3. EDITING GUIDELINES
|
|
427
|
+
h2("3. EDITING GUIDELINES"),
|
|
428
|
+
sp(100),
|
|
429
|
+
...BRIEF.editing_guidelines.map(g => bullet(g)),
|
|
430
|
+
sp(80),
|
|
431
|
+
para([new TextRun({text:"Aspect Ratio Deliverables:",bold:true,size:20,font:"Arial",color:C.color_secondary})]),
|
|
432
|
+
...BRIEF.aspect_ratios.map(r => bullet(r)),
|
|
433
|
+
sp(180),
|
|
434
|
+
|
|
435
|
+
// PAGE BREAK → APPENDIX
|
|
436
|
+
new Paragraph({children:[new PageBreak()]}),
|
|
437
|
+
new Table({ width:{size:9360,type:WidthType.DXA}, columnWidths:[9360],
|
|
438
|
+
rows:[new TableRow({ children:[new TableCell({
|
|
439
|
+
borders:noBdrs, shading:{fill:C.color_mid_gray,type:ShadingType.CLEAR},
|
|
440
|
+
margins:{top:160,bottom:160,left:280,right:280},
|
|
441
|
+
children:[
|
|
442
|
+
new Paragraph({alignment:AlignmentType.CENTER, children:[new TextRun({text:"APPENDIX — AI VIDEO GENERATION PROMPTS",bold:true,size:28,font:"Arial",color:C.color_white})]}),
|
|
443
|
+
new Paragraph({alignment:AlignmentType.CENTER, spacing:{before:60}, children:[new TextRun({text:"Optional reference | Veo 3.1 / Runway / Sora | Use only if generating AI video synthetically",size:19,font:"Arial",color:"E5E7EB"})]}),
|
|
444
|
+
]
|
|
445
|
+
})]})]
|
|
446
|
+
}),
|
|
447
|
+
sp(80),
|
|
448
|
+
para([new TextRun({text:"These prompts are provided as optional references. They are NOT required to execute this creative.",italics:true,size:19,font:"Arial",color:C.color_mid_gray})]),
|
|
449
|
+
sp(120),
|
|
450
|
+
...BRIEF.appendix_prompts.flatMap(p => [
|
|
451
|
+
h3(p.label),
|
|
452
|
+
para([run(p.prompt,{size:19})]),
|
|
453
|
+
sp(80),
|
|
454
|
+
]),
|
|
455
|
+
sp(120),
|
|
456
|
+
new Paragraph({
|
|
457
|
+
alignment:AlignmentType.CENTER,
|
|
458
|
+
children:[new TextRun({text:`${C.client_name} — Video Creative Brief — Confidential — ${C.date}`,size:18,font:"Arial",color:C.color_mid_gray,italics:true})]
|
|
459
|
+
}),
|
|
460
|
+
]
|
|
461
|
+
}]
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
465
|
+
// OUTPUT
|
|
466
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
467
|
+
Packer.toBuffer(doc).then(buf => {
|
|
468
|
+
fs.writeFileSync(CONFIG.output_path, buf);
|
|
469
|
+
console.log("DONE: " + CONFIG.output_path);
|
|
470
|
+
});
|