← back to Dw Marketing Reels
Route 9:16 catalog reels through build-reel.mjs ($0, IG-publishable, gallery-visible)
d385b43830005297369fdef6a15760e4e8faff20 · 2026-07-22 07:48:24 -0700 · Steve
Running a real render exposed that new-arrivals-reel via claude -p was slow
(~8min), cost API, produced a SILENT reel, and orphaned it in output/ (invisible
to the gallery). The repo's own build-reel.mjs renders the same reel in ~20s, $0
(local ffmpeg/Chrome), with an IG-publishable AAC track, straight into reels/.
- video-runner: new-arrivals-reel@9:16 → build-reel.mjs (no arming needed);
1:1 + url/newsletter keep the gated claude -p skill path; retry wraps both
- server: /api/videos gallery now also scans output/ (+ serve guard) so the
HyperFrames url/newsletter renders that land there are visible + playable
Files touched
M data/reels.jsonM data/video-jobs.jsonM data/video-suggestions.jsonD output/reel-20260722-073452/meta.tsvD output/reel-20260722-073452/poster.pngD output/reel-20260722-073452/prep/base_01.pngD output/reel-20260722-073452/prep/base_02.pngD output/reel-20260722-073452/prep/base_03.pngD output/reel-20260722-073452/prep/base_04.pngD output/reel-20260722-073452/prep/base_05.pngD output/reel-20260722-073452/prep/base_06.pngD output/reel-20260722-073452/prep/base_07.pngD output/reel-20260722-073452/prep/frame_00.pngD output/reel-20260722-073452/prep/frame_01.pngD output/reel-20260722-073452/prep/frame_02.pngD output/reel-20260722-073452/prep/frame_03.pngD output/reel-20260722-073452/prep/frame_04.pngD output/reel-20260722-073452/prep/frame_05.pngD output/reel-20260722-073452/prep/frame_06.pngD output/reel-20260722-073452/prep/frame_07.pngD output/reel-20260722-073452/prep/frame_zz.pngD output/reel-20260722-073452/prep/scrim2_01.pngD output/reel-20260722-073452/prep/scrim2_02.pngD output/reel-20260722-073452/prep/scrim2_03.pngD output/reel-20260722-073452/prep/scrim2_04.pngD output/reel-20260722-073452/prep/scrim2_05.pngD output/reel-20260722-073452/prep/scrim2_06.pngD output/reel-20260722-073452/prep/scrim2_07.pngD output/reel-20260722-073452/prep/scrim_01.pngD output/reel-20260722-073452/prep/scrim_02.pngD output/reel-20260722-073452/prep/scrim_03.pngD output/reel-20260722-073452/prep/scrim_04.pngD output/reel-20260722-073452/prep/scrim_05.pngD output/reel-20260722-073452/prep/scrim_06.pngD output/reel-20260722-073452/prep/scrim_07.pngD output/reel-20260722-073452/prep/scrimmed_01.pngD output/reel-20260722-073452/prep/scrimmed_02.pngD output/reel-20260722-073452/prep/scrimmed_03.pngD output/reel-20260722-073452/prep/scrimmed_04.pngD output/reel-20260722-073452/prep/scrimmed_05.pngD output/reel-20260722-073452/prep/scrimmed_06.pngD output/reel-20260722-073452/prep/scrimmed_07.pngD output/reel-20260722-073452/prep/topscrim_01.pngD output/reel-20260722-073452/prep/topscrim_02.pngD output/reel-20260722-073452/prep/topscrim_03.pngD output/reel-20260722-073452/prep/topscrim_04.pngD output/reel-20260722-073452/prep/topscrim_05.pngD output/reel-20260722-073452/prep/topscrim_06.pngD output/reel-20260722-073452/prep/topscrim_07.pngD output/reel-20260722-073452/reel-9x16.mp4D output/reel-20260722-073452/selection.jsonD output/reel-20260722-073452/src/01.jpgD output/reel-20260722-073452/src/02.jpgD output/reel-20260722-073452/src/03.jpgD output/reel-20260722-073452/src/04.jpgD output/reel-20260722-073452/src/05.jpgD output/reel-20260722-073452/src/06.jpgD output/reel-20260722-073452/src/07.jpgD output/reel-20260722-073452/urls.tsvD output/reel-20260722-073452/verify_mid.pngD output/reel-20260722-073452/verify_out.pngM scripts/video-runner.mjsM server.js
Diff
commit d385b43830005297369fdef6a15760e4e8faff20
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 22 07:48:24 2026 -0700
Route 9:16 catalog reels through build-reel.mjs ($0, IG-publishable, gallery-visible)
Running a real render exposed that new-arrivals-reel via claude -p was slow
(~8min), cost API, produced a SILENT reel, and orphaned it in output/ (invisible
to the gallery). The repo's own build-reel.mjs renders the same reel in ~20s, $0
(local ffmpeg/Chrome), with an IG-publishable AAC track, straight into reels/.
- video-runner: new-arrivals-reel@9:16 → build-reel.mjs (no arming needed);
1:1 + url/newsletter keep the gated claude -p skill path; retry wraps both
- server: /api/videos gallery now also scans output/ (+ serve guard) so the
HyperFrames url/newsletter renders that land there are visible + playable
---
data/reels.json | 35 ++++++++
data/video-jobs.json | 13 +--
data/video-suggestions.json | 4 +-
output/reel-20260722-073452/meta.tsv | 7 --
output/reel-20260722-073452/poster.png | Bin 1953541 -> 0 bytes
output/reel-20260722-073452/prep/base_01.png | Bin 1877750 -> 0 bytes
output/reel-20260722-073452/prep/base_02.png | Bin 2148348 -> 0 bytes
output/reel-20260722-073452/prep/base_03.png | Bin 1899435 -> 0 bytes
output/reel-20260722-073452/prep/base_04.png | Bin 2618742 -> 0 bytes
output/reel-20260722-073452/prep/base_05.png | Bin 2226041 -> 0 bytes
output/reel-20260722-073452/prep/base_06.png | Bin 2752933 -> 0 bytes
output/reel-20260722-073452/prep/base_07.png | Bin 2879244 -> 0 bytes
output/reel-20260722-073452/prep/frame_00.png | Bin 117257 -> 0 bytes
output/reel-20260722-073452/prep/frame_01.png | Bin 1953541 -> 0 bytes
output/reel-20260722-073452/prep/frame_02.png | Bin 2257550 -> 0 bytes
output/reel-20260722-073452/prep/frame_03.png | Bin 1850205 -> 0 bytes
output/reel-20260722-073452/prep/frame_04.png | Bin 2834742 -> 0 bytes
output/reel-20260722-073452/prep/frame_05.png | Bin 2318635 -> 0 bytes
output/reel-20260722-073452/prep/frame_06.png | Bin 2685420 -> 0 bytes
output/reel-20260722-073452/prep/frame_07.png | Bin 2806367 -> 0 bytes
output/reel-20260722-073452/prep/frame_zz.png | Bin 106301 -> 0 bytes
output/reel-20260722-073452/prep/scrim2_01.png | Bin 1773820 -> 0 bytes
output/reel-20260722-073452/prep/scrim2_02.png | Bin 2039313 -> 0 bytes
output/reel-20260722-073452/prep/scrim2_03.png | Bin 1654996 -> 0 bytes
output/reel-20260722-073452/prep/scrim2_04.png | Bin 2488067 -> 0 bytes
output/reel-20260722-073452/prep/scrim2_05.png | Bin 2088377 -> 0 bytes
output/reel-20260722-073452/prep/scrim2_06.png | Bin 2515396 -> 0 bytes
output/reel-20260722-073452/prep/scrim2_07.png | Bin 2571942 -> 0 bytes
output/reel-20260722-073452/prep/scrim_01.png | Bin 3707 -> 0 bytes
output/reel-20260722-073452/prep/scrim_02.png | Bin 3707 -> 0 bytes
output/reel-20260722-073452/prep/scrim_03.png | Bin 3707 -> 0 bytes
output/reel-20260722-073452/prep/scrim_04.png | Bin 3707 -> 0 bytes
output/reel-20260722-073452/prep/scrim_05.png | Bin 3707 -> 0 bytes
output/reel-20260722-073452/prep/scrim_06.png | Bin 3707 -> 0 bytes
output/reel-20260722-073452/prep/scrim_07.png | Bin 3707 -> 0 bytes
output/reel-20260722-073452/prep/scrimmed_01.png | Bin 1768813 -> 0 bytes
output/reel-20260722-073452/prep/scrimmed_02.png | Bin 1949509 -> 0 bytes
output/reel-20260722-073452/prep/scrimmed_03.png | Bin 1617527 -> 0 bytes
output/reel-20260722-073452/prep/scrimmed_04.png | Bin 2472643 -> 0 bytes
output/reel-20260722-073452/prep/scrimmed_05.png | Bin 1995370 -> 0 bytes
output/reel-20260722-073452/prep/scrimmed_06.png | Bin 2414603 -> 0 bytes
output/reel-20260722-073452/prep/scrimmed_07.png | Bin 2452324 -> 0 bytes
output/reel-20260722-073452/prep/topscrim_01.png | Bin 1629 -> 0 bytes
output/reel-20260722-073452/prep/topscrim_02.png | Bin 1629 -> 0 bytes
output/reel-20260722-073452/prep/topscrim_03.png | Bin 1629 -> 0 bytes
output/reel-20260722-073452/prep/topscrim_04.png | Bin 1629 -> 0 bytes
output/reel-20260722-073452/prep/topscrim_05.png | Bin 1629 -> 0 bytes
output/reel-20260722-073452/prep/topscrim_06.png | Bin 1629 -> 0 bytes
output/reel-20260722-073452/prep/topscrim_07.png | Bin 1629 -> 0 bytes
output/reel-20260722-073452/reel-9x16.mp4 | Bin 7561778 -> 0 bytes
output/reel-20260722-073452/selection.json | 107 -----------------------
output/reel-20260722-073452/src/01.jpg | Bin 317316 -> 0 bytes
output/reel-20260722-073452/src/02.jpg | Bin 266907 -> 0 bytes
output/reel-20260722-073452/src/03.jpg | Bin 306028 -> 0 bytes
output/reel-20260722-073452/src/04.jpg | Bin 320473 -> 0 bytes
output/reel-20260722-073452/src/05.jpg | Bin 256010 -> 0 bytes
output/reel-20260722-073452/src/06.jpg | Bin 376765 -> 0 bytes
output/reel-20260722-073452/src/07.jpg | Bin 383204 -> 0 bytes
output/reel-20260722-073452/urls.tsv | 7 --
output/reel-20260722-073452/verify_mid.png | Bin 2488266 -> 0 bytes
output/reel-20260722-073452/verify_out.png | Bin 170117 -> 0 bytes
scripts/video-runner.mjs | 60 +++++++++----
server.js | 3 +-
63 files changed, 81 insertions(+), 155 deletions(-)
diff --git a/data/reels.json b/data/reels.json
index bf85bf6..891ecf1 100644
--- a/data/reels.json
+++ b/data/reels.json
@@ -1,4 +1,39 @@
[
+ {
+ "file": "new-arrivals-2026-07-22-14-47.mp4",
+ "created_at": "2026-07-22T14:47:43.327Z",
+ "products": 6,
+ "seconds": 19,
+ "titles": [
+ "Flower Fall / Pearl",
+ "Flower Art / Pastel",
+ "Flower Art / Green",
+ "Flower Art / Blue",
+ "Flow Mini Shallow Grey / ",
+ "Flow Mini Deep Blue / "
+ ],
+ "caption": "New arrivals just landed ✨ Flower Fall, Flower Art, Flow Mini Shallow Grey & more from Rebel Walls. Discover the latest wallcoverings — shop the collection at designerwallcoverings.com 🔗\n\n#DesignerWallcoverings #NewArrivals #Wallcovering #Wallcoverings #InteriorDesign #InteriorDecor #HomeDesign #LuxuryInteriors #DesignInspo #RebelWalls",
+ "hashtags": [
+ "#DesignerWallcoverings",
+ "#NewArrivals",
+ "#Wallcovering",
+ "#Wallcoverings",
+ "#InteriorDesign",
+ "#InteriorDecor",
+ "#HomeDesign",
+ "#LuxuryInteriors",
+ "#DesignInspo",
+ "#RebelWalls"
+ ],
+ "publish": {
+ "instagram": {
+ "status": "pending"
+ },
+ "tiktok": {
+ "status": "pending"
+ }
+ }
+ },
{
"file": "new-arrivals-2026-07-22-14-10.mp4",
"created_at": "2026-07-22T14:10:32.853Z",
diff --git a/data/video-jobs.json b/data/video-jobs.json
index 145a8a4..fe51488 100644
--- a/data/video-jobs.json
+++ b/data/video-jobs.json
@@ -1,12 +1 @@
-[
- {
- "id": "vj-mrw6o29f",
- "kind": "new-arrivals-reel",
- "url": "",
- "eml": "",
- "format": "9:16",
- "status": "running",
- "created_at": "2026-07-22T14:34:11.187Z",
- "started_at": "2026-07-22T14:34:11.248Z"
- }
-]
\ No newline at end of file
+[]
diff --git a/data/video-suggestions.json b/data/video-suggestions.json
index 59f0402..e66e495 100644
--- a/data/video-suggestions.json
+++ b/data/video-suggestions.json
@@ -43,9 +43,9 @@
}
],
"used": true,
- "used_at": "2026-07-22T14:34:11.191Z",
+ "used_at": "2026-07-22T14:47:18.973Z",
"used_where": {
- "jobId": "vj-mrw6o29f",
+ "jobId": "vj-mrw74y4a",
"kind": "new-arrivals-reel",
"format": "9:16",
"surface": "video-studio-queue"
diff --git a/output/reel-20260722-073452/meta.tsv b/output/reel-20260722-073452/meta.tsv
deleted file mode 100644
index 0923448..0000000
--- a/output/reel-20260722-073452/meta.tsv
+++ /dev/null
@@ -1,7 +0,0 @@
-Flower Fall Pearl Rebel Walls 191.00
-Flower Art Green Rebel Walls 191.00
-Florida Blue Rebel Walls 220.75
-Floral Opulence Red Rebel Walls 191.00
-Floral Meadow Multi Rebel Walls 191.00
-Inverness Wide Width Teal and Clay Thibaut 58.64
-Luta Sisal Wide Width Flax and Metallic Gold Thibaut 58.64
diff --git a/output/reel-20260722-073452/poster.png b/output/reel-20260722-073452/poster.png
deleted file mode 100644
index d1f827c..0000000
Binary files a/output/reel-20260722-073452/poster.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/base_01.png b/output/reel-20260722-073452/prep/base_01.png
deleted file mode 100644
index c91b326..0000000
Binary files a/output/reel-20260722-073452/prep/base_01.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/base_02.png b/output/reel-20260722-073452/prep/base_02.png
deleted file mode 100644
index 016e098..0000000
Binary files a/output/reel-20260722-073452/prep/base_02.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/base_03.png b/output/reel-20260722-073452/prep/base_03.png
deleted file mode 100644
index 69e33e0..0000000
Binary files a/output/reel-20260722-073452/prep/base_03.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/base_04.png b/output/reel-20260722-073452/prep/base_04.png
deleted file mode 100644
index 2e62b6d..0000000
Binary files a/output/reel-20260722-073452/prep/base_04.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/base_05.png b/output/reel-20260722-073452/prep/base_05.png
deleted file mode 100644
index f6a0ff1..0000000
Binary files a/output/reel-20260722-073452/prep/base_05.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/base_06.png b/output/reel-20260722-073452/prep/base_06.png
deleted file mode 100644
index 87a0e88..0000000
Binary files a/output/reel-20260722-073452/prep/base_06.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/base_07.png b/output/reel-20260722-073452/prep/base_07.png
deleted file mode 100644
index 7a47352..0000000
Binary files a/output/reel-20260722-073452/prep/base_07.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_00.png b/output/reel-20260722-073452/prep/frame_00.png
deleted file mode 100644
index a414f86..0000000
Binary files a/output/reel-20260722-073452/prep/frame_00.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_01.png b/output/reel-20260722-073452/prep/frame_01.png
deleted file mode 100644
index d1f827c..0000000
Binary files a/output/reel-20260722-073452/prep/frame_01.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_02.png b/output/reel-20260722-073452/prep/frame_02.png
deleted file mode 100644
index 2c8e061..0000000
Binary files a/output/reel-20260722-073452/prep/frame_02.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_03.png b/output/reel-20260722-073452/prep/frame_03.png
deleted file mode 100644
index 2996207..0000000
Binary files a/output/reel-20260722-073452/prep/frame_03.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_04.png b/output/reel-20260722-073452/prep/frame_04.png
deleted file mode 100644
index 812bb0e..0000000
Binary files a/output/reel-20260722-073452/prep/frame_04.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_05.png b/output/reel-20260722-073452/prep/frame_05.png
deleted file mode 100644
index 7a581e5..0000000
Binary files a/output/reel-20260722-073452/prep/frame_05.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_06.png b/output/reel-20260722-073452/prep/frame_06.png
deleted file mode 100644
index 264c2c5..0000000
Binary files a/output/reel-20260722-073452/prep/frame_06.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_07.png b/output/reel-20260722-073452/prep/frame_07.png
deleted file mode 100644
index c87c958..0000000
Binary files a/output/reel-20260722-073452/prep/frame_07.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/frame_zz.png b/output/reel-20260722-073452/prep/frame_zz.png
deleted file mode 100644
index 49a08d0..0000000
Binary files a/output/reel-20260722-073452/prep/frame_zz.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim2_01.png b/output/reel-20260722-073452/prep/scrim2_01.png
deleted file mode 100644
index 20a362d..0000000
Binary files a/output/reel-20260722-073452/prep/scrim2_01.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim2_02.png b/output/reel-20260722-073452/prep/scrim2_02.png
deleted file mode 100644
index 94e7bec..0000000
Binary files a/output/reel-20260722-073452/prep/scrim2_02.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim2_03.png b/output/reel-20260722-073452/prep/scrim2_03.png
deleted file mode 100644
index 31677ed..0000000
Binary files a/output/reel-20260722-073452/prep/scrim2_03.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim2_04.png b/output/reel-20260722-073452/prep/scrim2_04.png
deleted file mode 100644
index 0cea1e9..0000000
Binary files a/output/reel-20260722-073452/prep/scrim2_04.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim2_05.png b/output/reel-20260722-073452/prep/scrim2_05.png
deleted file mode 100644
index f2a335e..0000000
Binary files a/output/reel-20260722-073452/prep/scrim2_05.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim2_06.png b/output/reel-20260722-073452/prep/scrim2_06.png
deleted file mode 100644
index cc12715..0000000
Binary files a/output/reel-20260722-073452/prep/scrim2_06.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim2_07.png b/output/reel-20260722-073452/prep/scrim2_07.png
deleted file mode 100644
index 9d16838..0000000
Binary files a/output/reel-20260722-073452/prep/scrim2_07.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim_01.png b/output/reel-20260722-073452/prep/scrim_01.png
deleted file mode 100644
index 1b76265..0000000
Binary files a/output/reel-20260722-073452/prep/scrim_01.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim_02.png b/output/reel-20260722-073452/prep/scrim_02.png
deleted file mode 100644
index b8d7348..0000000
Binary files a/output/reel-20260722-073452/prep/scrim_02.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim_03.png b/output/reel-20260722-073452/prep/scrim_03.png
deleted file mode 100644
index 8a3bd86..0000000
Binary files a/output/reel-20260722-073452/prep/scrim_03.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim_04.png b/output/reel-20260722-073452/prep/scrim_04.png
deleted file mode 100644
index 0b37f5e..0000000
Binary files a/output/reel-20260722-073452/prep/scrim_04.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim_05.png b/output/reel-20260722-073452/prep/scrim_05.png
deleted file mode 100644
index d2f2cf2..0000000
Binary files a/output/reel-20260722-073452/prep/scrim_05.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim_06.png b/output/reel-20260722-073452/prep/scrim_06.png
deleted file mode 100644
index 9f2bd21..0000000
Binary files a/output/reel-20260722-073452/prep/scrim_06.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrim_07.png b/output/reel-20260722-073452/prep/scrim_07.png
deleted file mode 100644
index 8fefe3a..0000000
Binary files a/output/reel-20260722-073452/prep/scrim_07.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrimmed_01.png b/output/reel-20260722-073452/prep/scrimmed_01.png
deleted file mode 100644
index c4c88ca..0000000
Binary files a/output/reel-20260722-073452/prep/scrimmed_01.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrimmed_02.png b/output/reel-20260722-073452/prep/scrimmed_02.png
deleted file mode 100644
index 13609c5..0000000
Binary files a/output/reel-20260722-073452/prep/scrimmed_02.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrimmed_03.png b/output/reel-20260722-073452/prep/scrimmed_03.png
deleted file mode 100644
index 0f868d1..0000000
Binary files a/output/reel-20260722-073452/prep/scrimmed_03.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrimmed_04.png b/output/reel-20260722-073452/prep/scrimmed_04.png
deleted file mode 100644
index 4a13ed4..0000000
Binary files a/output/reel-20260722-073452/prep/scrimmed_04.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrimmed_05.png b/output/reel-20260722-073452/prep/scrimmed_05.png
deleted file mode 100644
index 5d72563..0000000
Binary files a/output/reel-20260722-073452/prep/scrimmed_05.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrimmed_06.png b/output/reel-20260722-073452/prep/scrimmed_06.png
deleted file mode 100644
index 4cf8999..0000000
Binary files a/output/reel-20260722-073452/prep/scrimmed_06.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/scrimmed_07.png b/output/reel-20260722-073452/prep/scrimmed_07.png
deleted file mode 100644
index 027064c..0000000
Binary files a/output/reel-20260722-073452/prep/scrimmed_07.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/topscrim_01.png b/output/reel-20260722-073452/prep/topscrim_01.png
deleted file mode 100644
index e5b1825..0000000
Binary files a/output/reel-20260722-073452/prep/topscrim_01.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/topscrim_02.png b/output/reel-20260722-073452/prep/topscrim_02.png
deleted file mode 100644
index 17f7551..0000000
Binary files a/output/reel-20260722-073452/prep/topscrim_02.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/topscrim_03.png b/output/reel-20260722-073452/prep/topscrim_03.png
deleted file mode 100644
index 6192395..0000000
Binary files a/output/reel-20260722-073452/prep/topscrim_03.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/topscrim_04.png b/output/reel-20260722-073452/prep/topscrim_04.png
deleted file mode 100644
index 5fce68f..0000000
Binary files a/output/reel-20260722-073452/prep/topscrim_04.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/topscrim_05.png b/output/reel-20260722-073452/prep/topscrim_05.png
deleted file mode 100644
index 5ac1b0a..0000000
Binary files a/output/reel-20260722-073452/prep/topscrim_05.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/topscrim_06.png b/output/reel-20260722-073452/prep/topscrim_06.png
deleted file mode 100644
index 119a485..0000000
Binary files a/output/reel-20260722-073452/prep/topscrim_06.png and /dev/null differ
diff --git a/output/reel-20260722-073452/prep/topscrim_07.png b/output/reel-20260722-073452/prep/topscrim_07.png
deleted file mode 100644
index a480847..0000000
Binary files a/output/reel-20260722-073452/prep/topscrim_07.png and /dev/null differ
diff --git a/output/reel-20260722-073452/reel-9x16.mp4 b/output/reel-20260722-073452/reel-9x16.mp4
deleted file mode 100644
index bf3cf68..0000000
Binary files a/output/reel-20260722-073452/reel-9x16.mp4 and /dev/null differ
diff --git a/output/reel-20260722-073452/selection.json b/output/reel-20260722-073452/selection.json
deleted file mode 100644
index 0cbb36a..0000000
--- a/output/reel-20260722-073452/selection.json
+++ /dev/null
@@ -1,107 +0,0 @@
-[
- {
- "id": 7895904583731,
- "handle": "flower-fall-pearl-wallcoverings-dwrw-361341",
- "title": "Flower Fall, Pearl Wallcoverings | Rebel Walls",
- "pattern": "Flower Fall",
- "color": "Pearl",
- "vendor": "Rebel Walls",
- "product_type": "Mural",
- "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R19251_interior1.jpg?v=1784706015",
- "image_hi": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R19251_interior1_1200x.jpg?v=1784706015",
- "price": "191.00",
- "url": "https://designerwallcoverings.com/products/flower-fall-pearl-wallcoverings-dwrw-361341",
- "created_at": "2026-07-22T00:40:09-07:00",
- "published_at": "2026-07-22T01:25:47-07:00"
- },
- {
- "id": 7895904518195,
- "handle": "flower-art-green-wallcoverings-dwrw-361337",
- "title": "Flower Art, Green Wallcoverings | Rebel Walls",
- "pattern": "Flower Art",
- "color": "Green",
- "vendor": "Rebel Walls",
- "product_type": "Mural",
- "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R20397_interior1.webp?v=1784706010",
- "image_hi": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R20397_interior1_1200x.webp?v=1784706010",
- "price": "191.00",
- "url": "https://designerwallcoverings.com/products/flower-art-green-wallcoverings-dwrw-361337",
- "created_at": "2026-07-22T00:40:06-07:00",
- "published_at": "2026-07-22T01:25:32-07:00"
- },
- {
- "id": 7894970597427,
- "handle": "florida-blue-wallcoverings-dwrw-361328",
- "title": "Florida, Blue Wallcoverings | Rebel Walls",
- "pattern": "Florida",
- "color": "Blue",
- "vendor": "Rebel Walls",
- "product_type": "Mural",
- "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R20038_interior1.webp?v=1784619613",
- "image_hi": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R20038_interior1_1200x.webp?v=1784619613",
- "price": "220.75",
- "url": "https://designerwallcoverings.com/products/florida-blue-wallcoverings-dwrw-361328",
- "created_at": "2026-07-21T00:40:10-07:00",
- "published_at": "2026-07-21T00:40:11-07:00"
- },
- {
- "id": 7893129789491,
- "handle": "floral-opulence-red-wallcoverings-dwrw-361322",
- "title": "Floral Opulence, Red Wallcoverings | Rebel Walls",
- "pattern": "Floral Opulence",
- "color": "Red",
- "vendor": "Rebel Walls",
- "product_type": "Mural",
- "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R21399_interior1.jpg?v=1784533215",
- "image_hi": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R21399_interior1_1200x.jpg?v=1784533215",
- "price": "191.00",
- "url": "https://designerwallcoverings.com/products/floral-opulence-red-wallcoverings-dwrw-361322",
- "created_at": "2026-07-20T00:40:12-07:00",
- "published_at": "2026-07-20T00:40:13-07:00"
- },
- {
- "id": 7890539610163,
- "handle": "floral-meadow-multi-wallcoverings-dwrw-361318",
- "title": "Floral Meadow, Multi Wallcoverings | Rebel Walls",
- "pattern": "Floral Meadow",
- "color": "Multi",
- "vendor": "Rebel Walls",
- "product_type": "Mural",
- "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R22391_interior1.jpg?v=1784446816",
- "image_hi": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R22391_interior1_1200x.jpg?v=1784446816",
- "price": "191.00",
- "url": "https://designerwallcoverings.com/products/floral-meadow-multi-wallcoverings-dwrw-361318",
- "created_at": "2026-07-19T00:40:12-07:00",
- "published_at": "2026-07-19T00:40:13-07:00"
- },
- {
- "id": 7891284426803,
- "handle": "inverness-wide-width-teal-and-clay-dwtt-74388",
- "title": "Inverness Wide Width, Teal and Clay Wallcoverings | Thibaut",
- "pattern": "Inverness Wide Width",
- "color": "Teal and Clay",
- "vendor": "Thibaut",
- "product_type": "Wallcovering",
- "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/TWW10976_7c00ae0c-31e7-40c0-80d1-6f8416defc66.jpg?v=1784472010",
- "image_hi": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/TWW10976_7c00ae0c-31e7-40c0-80d1-6f8416defc66_1200x.jpg?v=1784472010",
- "price": "58.64",
- "url": "https://designerwallcoverings.com/products/inverness-wide-width-teal-and-clay-dwtt-74388",
- "created_at": "2026-07-19T07:40:06-07:00",
- "published_at": "2026-07-19T07:40:09-07:00"
- },
- {
- "id": 7891385188403,
- "handle": "luta-sisal-wide-width-flax-and-metallic-gold-dwtt-74391",
- "title": "Luta Sisal Wide Width, Flax and Metallic Gold Wallcoverings | Thibaut",
- "pattern": "Luta Sisal Wide Width",
- "color": "Flax and Metallic Gold",
- "vendor": "Thibaut",
- "product_type": "Wallcovering",
- "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/TWW14524_9aaf6990-b346-4b4f-b671-cf05791d9cd3.jpg?v=1784475608",
- "image_hi": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/TWW14524_9aaf6990-b346-4b4f-b671-cf05791d9cd3_1200x.jpg?v=1784475608",
- "price": "58.64",
- "url": "https://designerwallcoverings.com/products/luta-sisal-wide-width-flax-and-metallic-gold-dwtt-74391",
- "created_at": "2026-07-19T08:40:05-07:00",
- "published_at": "2026-07-19T08:40:08-07:00"
- }
-]
\ No newline at end of file
diff --git a/output/reel-20260722-073452/src/01.jpg b/output/reel-20260722-073452/src/01.jpg
deleted file mode 100644
index 20a5b88..0000000
Binary files a/output/reel-20260722-073452/src/01.jpg and /dev/null differ
diff --git a/output/reel-20260722-073452/src/02.jpg b/output/reel-20260722-073452/src/02.jpg
deleted file mode 100644
index ae224be..0000000
Binary files a/output/reel-20260722-073452/src/02.jpg and /dev/null differ
diff --git a/output/reel-20260722-073452/src/03.jpg b/output/reel-20260722-073452/src/03.jpg
deleted file mode 100644
index 266497d..0000000
Binary files a/output/reel-20260722-073452/src/03.jpg and /dev/null differ
diff --git a/output/reel-20260722-073452/src/04.jpg b/output/reel-20260722-073452/src/04.jpg
deleted file mode 100644
index c5014a9..0000000
Binary files a/output/reel-20260722-073452/src/04.jpg and /dev/null differ
diff --git a/output/reel-20260722-073452/src/05.jpg b/output/reel-20260722-073452/src/05.jpg
deleted file mode 100644
index 096c3d8..0000000
Binary files a/output/reel-20260722-073452/src/05.jpg and /dev/null differ
diff --git a/output/reel-20260722-073452/src/06.jpg b/output/reel-20260722-073452/src/06.jpg
deleted file mode 100644
index 1eb3287..0000000
Binary files a/output/reel-20260722-073452/src/06.jpg and /dev/null differ
diff --git a/output/reel-20260722-073452/src/07.jpg b/output/reel-20260722-073452/src/07.jpg
deleted file mode 100644
index 704692d..0000000
Binary files a/output/reel-20260722-073452/src/07.jpg and /dev/null differ
diff --git a/output/reel-20260722-073452/urls.tsv b/output/reel-20260722-073452/urls.tsv
deleted file mode 100644
index 6013f4a..0000000
--- a/output/reel-20260722-073452/urls.tsv
+++ /dev/null
@@ -1,7 +0,0 @@
-1 https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R19251_interior1_1200x.jpg?v=1784706015
-2 https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R20397_interior1_1200x.webp?v=1784706010
-3 https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R20038_interior1_1200x.webp?v=1784619613
-4 https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R21399_interior1_1200x.jpg?v=1784533215
-5 https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R22391_interior1_1200x.jpg?v=1784446816
-6 https://cdn.shopify.com/s/files/1/0015/4117/7456/files/TWW10976_7c00ae0c-31e7-40c0-80d1-6f8416defc66_1200x.jpg?v=1784472010
-7 https://cdn.shopify.com/s/files/1/0015/4117/7456/files/TWW14524_9aaf6990-b346-4b4f-b671-cf05791d9cd3_1200x.jpg?v=1784475608
diff --git a/output/reel-20260722-073452/verify_mid.png b/output/reel-20260722-073452/verify_mid.png
deleted file mode 100644
index 0d94e61..0000000
Binary files a/output/reel-20260722-073452/verify_mid.png and /dev/null differ
diff --git a/output/reel-20260722-073452/verify_out.png b/output/reel-20260722-073452/verify_out.png
deleted file mode 100644
index 6e6f59c..0000000
Binary files a/output/reel-20260722-073452/verify_out.png and /dev/null differ
diff --git a/scripts/video-runner.mjs b/scripts/video-runner.mjs
index fdc4fef..35ce4f6 100644
--- a/scripts/video-runner.mjs
+++ b/scripts/video-runner.mjs
@@ -6,10 +6,14 @@
// Steve-gated action (see ~/.claude/yolo-queue). Unarmed (default), the runner simply
// reports that jobs are waiting for a live studio session to run them — nothing fires.
//
-// Each job maps to a video skill:
-// new-arrivals-reel → reels-producer (9:16 IG reel from data/new-arrivals.json)
-// url-reel → product-launch-video (promo/tour reel from a URL)
-// newsletter-video → newsletter-to-video (.eml → promo video)
+// Each job maps to a renderer:
+// new-arrivals-reel (9:16) → scripts/build-reel.mjs ($0 local, no API/arming,
+// IG-publishable silent-AAC track, writes to reels/)
+// new-arrivals-reel (1:1) → reels-producer skill (claude -p, square)
+// url-reel → product-launch-video skill (promo/tour reel from a URL)
+// newsletter-video → newsletter-to-video skill (.eml → promo video)
+// Only the claude -p (skill) paths need VIDEO_AUTORUN=1 + CLAUDE_BIN; the local
+// build-reel.mjs path renders even unarmed (same $0 script the /api/build button uses).
import { readFile, writeFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { spawn } from 'node:child_process';
@@ -46,6 +50,23 @@ function runClaude(CLAUDE_BIN, pr) {
});
}
+// A catalog reel in 9:16 is rendered by the deterministic local builder — no agent.
+const isLocalReel = j => j.kind === 'new-arrivals-reel' && j.format !== '1:1';
+
+// Deterministic $0 render via scripts/build-reel.mjs (portrait New Arrivals reel with an
+// IG-publishable audio track, written to reels/). No claude, no API, no arming needed.
+function runLocalBuild() {
+ return new Promise(resolve => {
+ let err = '';
+ const env = { ...process.env, PATH: `/opt/homebrew/bin:/usr/local/bin:${process.env.PATH || ''}`,
+ HYPERFRAMES_SKIP_SKILLS: '1', REEL_COUNT: String(process.env.REEL_COUNT || 6) };
+ const ch = spawn(process.execPath, [join(ROOT, 'scripts', 'build-reel.mjs')], { cwd: ROOT, env, stdio: ['ignore', 'inherit', 'pipe'] });
+ ch.stderr.on('data', d => { err += d; process.stderr.write(d); });
+ ch.on('close', code => resolve({ ok: code === 0, code, err }));
+ ch.on('error', e => resolve({ ok: false, code: -1, err: String(e.message) }));
+ });
+}
+
const prompt = (j) => {
const fmt = j.format === '1:1' ? '1:1 (1080×1080)' : '9:16 Instagram Reels (1080×1920)';
if (j.kind === 'new-arrivals-reel')
@@ -61,25 +82,26 @@ const prompt = (j) => {
const jobs = existsSync(JOBS) ? JSON.parse(await readFile(JOBS, 'utf8')) : [];
const queued = jobs.filter(j => j.status === 'queued');
if (!queued.length) { console.log('video-runner: no queued jobs.'); return; }
- if (!ARMED) {
- console.log(`video-runner: ${queued.length} job(s) queued, waiting for a live studio session (VIDEO_AUTORUN not set).`);
- return; // GATE: never auto-runs claude unarmed.
- }
- // `claude` is a shell function on this host, NOT a binary — spawn() can't run it.
- // Require an explicit binary path and fail LOUD (not a silent detached ENOENT).
+
+ // Agent (claude -p) jobs are gated behind VIDEO_AUTORUN=1 + a real CLAUDE_BIN.
+ // Local build-reel.mjs jobs (9:16 catalog reels) are $0 and always run.
const CLAUDE_BIN = process.env.CLAUDE_BIN || '';
- if (!CLAUDE_BIN || !existsSync(CLAUDE_BIN)) {
- console.error('video-runner: VIDEO_AUTORUN=1 but CLAUDE_BIN is unset / not a real file. Set CLAUDE_BIN=/abs/path/to/claude to enable autonomous rendering; jobs left queued.');
- process.exit(1);
- }
- for (const j of queued) {
- const pr = prompt(j); if (!pr) { j.status = 'error'; j.note = 'unknown kind'; continue; }
- j.status = 'running'; j.started_at = new Date().toISOString();
+ const canAgent = ARMED && CLAUDE_BIN && existsSync(CLAUDE_BIN);
+ const agentWaiting = queued.filter(j => !isLocalReel(j));
+ if (agentWaiting.length && !canAgent)
+ console.log(`video-runner: ${agentWaiting.length} agent job(s) waiting for a live/armed studio session (VIDEO_AUTORUN + CLAUDE_BIN).`);
+ const toRun = queued.filter(j => isLocalReel(j) || canAgent);
+ if (!toRun.length) { console.log('video-runner: nothing runnable right now.'); return; }
+
+ for (const j of toRun) {
+ const local = isLocalReel(j);
+ if (!local) { const pr0 = prompt(j); if (!pr0) { j.status = 'error'; j.note = 'unknown kind'; await writeFile(JOBS, JSON.stringify(jobs, null, 2)); continue; } }
+ j.status = 'running'; j.started_at = new Date().toISOString(); j.renderer = local ? 'build-reel' : 'claude-skill';
await writeFile(JOBS, JSON.stringify(jobs, null, 2));
let res, tries = 0;
for (;;) {
tries++;
- res = await runClaude(CLAUDE_BIN, pr);
+ res = local ? await runLocalBuild() : await runClaude(CLAUDE_BIN, prompt(j));
j.attempts = tries;
if (res.ok) break;
// Only retry self-healing API throttles — a real skill/code failure fails fast.
@@ -96,7 +118,7 @@ const prompt = (j) => {
if (res.ok) { j.status = 'done'; j.finished_at = new Date().toISOString(); delete j.note; }
else {
j.status = 'error'; j.finished_at = new Date().toISOString();
- j.note = (isTransient(res.err) ? `rate-limited after ${tries} tr${tries===1?'y':'ies'} — safe to requeue` : ('claude exit ' + res.code))
+ j.note = (isTransient(res.err) ? `rate-limited after ${tries} tr${tries===1?'y':'ies'} — safe to requeue` : (`${local ? 'build-reel' : 'claude'} exit ${res.code}`))
+ (res.err ? (' · ' + res.err.replace(/\s+/g, ' ').trim().slice(0, 140)) : '');
}
await writeFile(JOBS, JSON.stringify(jobs, null, 2));
diff --git a/server.js b/server.js
index 1bb0408..b7e8dcd 100644
--- a/server.js
+++ b/server.js
@@ -249,6 +249,7 @@ const server = http.createServer(async (req, res) => {
}
await walk(join(ROOT, 'videos'), 'videos');
await walk(join(ROOT, 'reels'), 'reels');
+ await walk(join(ROOT, 'output'), 'output'); // HyperFrames skill renders (url/newsletter) land here
out.sort((a, b) => b.mtime - a.mtime);
return res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify(out));
}
@@ -259,7 +260,7 @@ const server = http.createServer(async (req, res) => {
// realpathSync dereferences symlinks (normalize does NOT) — a .mp4 symlink
// pointing at server.js/secrets must not escape videos/ or reels/.
try { fp = realpathSync(fp); } catch { return res.writeHead(404).end('not found'); }
- const okRoot = fp.startsWith(join(ROOT, 'videos') + sep) || fp.startsWith(join(ROOT, 'reels') + sep);
+ const okRoot = fp.startsWith(join(ROOT, 'videos') + sep) || fp.startsWith(join(ROOT, 'reels') + sep) || fp.startsWith(join(ROOT, 'output') + sep);
if (okRoot && extname(fp) === '.mp4' && existsSync(fp)) return await serveFile(fp, req, res);
return res.writeHead(404).end('not found');
}
← f9fdb8f auto-save: 2026-07-22T07:42:20 (3 files) — data/video-jobs.j
·
back to Dw Marketing Reels
·
chore: lint, refactor, v0.8.0 (session close) ce006d6 →