[object Object]

← back to Dw Marketing Reels

auto-save: 2026-07-30T09:16:33 (3 files) — data/graduate-collection.json flipbooks/ scripts/build-collection-flipbook.mjs

a22d0df20783713b6aaa740ca42380a133070236 · 2026-07-30 09:16:40 -0700 · Steve Abrams

Files touched

Diff

commit a22d0df20783713b6aaa740ca42380a133070236
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 30 09:16:40 2026 -0700

    auto-save: 2026-07-30T09:16:33 (3 files) — data/graduate-collection.json flipbooks/ scripts/build-collection-flipbook.mjs
---
 data/graduate-collection.json                    | 212 +++++++++
 flipbooks/graduate-collection/assets/img/p0.jpg  | Bin 0 -> 1748666 bytes
 flipbooks/graduate-collection/assets/img/p1.jpg  | Bin 0 -> 356988 bytes
 flipbooks/graduate-collection/assets/img/p10.jpg | Bin 0 -> 81837 bytes
 flipbooks/graduate-collection/assets/img/p11.jpg | Bin 0 -> 88884 bytes
 flipbooks/graduate-collection/assets/img/p12.jpg | Bin 0 -> 78876 bytes
 flipbooks/graduate-collection/assets/img/p13.jpg | Bin 0 -> 215346 bytes
 flipbooks/graduate-collection/assets/img/p14.jpg | Bin 0 -> 373780 bytes
 flipbooks/graduate-collection/assets/img/p15.jpg | Bin 0 -> 1582411 bytes
 flipbooks/graduate-collection/assets/img/p16.jpg | Bin 0 -> 452547 bytes
 flipbooks/graduate-collection/assets/img/p17.jpg | Bin 0 -> 396508 bytes
 flipbooks/graduate-collection/assets/img/p18.jpg | Bin 0 -> 1826613 bytes
 flipbooks/graduate-collection/assets/img/p19.jpg | Bin 0 -> 1883410 bytes
 flipbooks/graduate-collection/assets/img/p2.jpg  | Bin 0 -> 182278 bytes
 flipbooks/graduate-collection/assets/img/p20.jpg | Bin 0 -> 1163592 bytes
 flipbooks/graduate-collection/assets/img/p21.jpg | Bin 0 -> 2336498 bytes
 flipbooks/graduate-collection/assets/img/p22.jpg | Bin 0 -> 1822055 bytes
 flipbooks/graduate-collection/assets/img/p23.jpg | Bin 0 -> 741667 bytes
 flipbooks/graduate-collection/assets/img/p24.jpg | Bin 0 -> 756109 bytes
 flipbooks/graduate-collection/assets/img/p25.jpg | Bin 0 -> 649446 bytes
 flipbooks/graduate-collection/assets/img/p26.jpg | Bin 0 -> 145231 bytes
 flipbooks/graduate-collection/assets/img/p27.jpg | Bin 0 -> 1067696 bytes
 flipbooks/graduate-collection/assets/img/p28.jpg | Bin 0 -> 1264201 bytes
 flipbooks/graduate-collection/assets/img/p29.jpg | Bin 0 -> 1075119 bytes
 flipbooks/graduate-collection/assets/img/p3.jpg  | Bin 0 -> 131271 bytes
 flipbooks/graduate-collection/assets/img/p30.jpg | Bin 0 -> 337804 bytes
 flipbooks/graduate-collection/assets/img/p31.jpg | Bin 0 -> 436099 bytes
 flipbooks/graduate-collection/assets/img/p32.jpg | Bin 0 -> 414857 bytes
 flipbooks/graduate-collection/assets/img/p33.jpg | Bin 0 -> 409759 bytes
 flipbooks/graduate-collection/assets/img/p34.jpg | Bin 0 -> 409759 bytes
 flipbooks/graduate-collection/assets/img/p4.jpg  | Bin 0 -> 157428 bytes
 flipbooks/graduate-collection/assets/img/p5.jpg  | Bin 0 -> 135898 bytes
 flipbooks/graduate-collection/assets/img/p6.jpg  | Bin 0 -> 131322 bytes
 flipbooks/graduate-collection/assets/img/p7.jpg  | Bin 0 -> 1622487 bytes
 flipbooks/graduate-collection/assets/img/p8.jpg  | Bin 0 -> 160181 bytes
 flipbooks/graduate-collection/assets/img/p9.jpg  | Bin 0 -> 173284 bytes
 flipbooks/graduate-collection/hyperframes.json   |   9 +
 flipbooks/graduate-collection/index.html         | 576 +++++++++++++++++++++++
 flipbooks/graduate-collection/meta.json          |   1 +
 flipbooks/graduate-collection/package.json       |  10 +
 scripts/build-collection-flipbook.mjs            | 260 ++++++++++
 41 files changed, 1068 insertions(+)

diff --git a/data/graduate-collection.json b/data/graduate-collection.json
new file mode 100644
index 0000000..b0d60d0
--- /dev/null
+++ b/data/graduate-collection.json
@@ -0,0 +1,212 @@
+[
+  {
+    "title": "Savannah Cheetah - Mustard",
+    "handle": "savannah-cheetah-cream",
+    "url": "https://www.designerwallcoverings.com/products/savannah-cheetah-cream",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/ScreenShot2021-10-08at2.38.34PM.png?v=1709589603"
+  },
+  {
+    "title": "Tiger Tiger - In the Jungle - Cream",
+    "handle": "tigers-tigers-tigers-in-the-jungle",
+    "url": "https://www.designerwallcoverings.com/products/tigers-tigers-tigers-in-the-jungle",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/HOOT-EXPORT-IMAGE-1.jpg?v=1689805112"
+  },
+  {
+    "title": "Tiger Tiger - In the Jungle - Green",
+    "handle": "tigers-tigers-tigers-in-the-jungle-1",
+    "url": "https://www.designerwallcoverings.com/products/tigers-tigers-tigers-in-the-jungle-1",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_02_Image_0006.jpg?v=1570091053"
+  },
+  {
+    "title": "Visitorian - Taupe",
+    "handle": "visitorian-wallpaper",
+    "url": "https://www.designerwallcoverings.com/products/visitorian-wallpaper",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_06_Image_0001.jpg?v=1570091053"
+  },
+  {
+    "title": "Visitorian Navy",
+    "handle": "visitorian-wallpaper-1",
+    "url": "https://www.designerwallcoverings.com/products/visitorian-wallpaper-1",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_06_Image_0002.jpg?v=1570091053"
+  },
+  {
+    "title": "Visitorian Mauve",
+    "handle": "visitorian-wallpaper-2",
+    "url": "https://www.designerwallcoverings.com/products/visitorian-wallpaper-2",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_06_Image_0003.jpg?v=1570091053"
+  },
+  {
+    "title": "Visitorian Blue",
+    "handle": "visitorian-wallpaper-3",
+    "url": "https://www.designerwallcoverings.com/products/visitorian-wallpaper-3",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_06_Image_0004.jpg?v=1570091053"
+  },
+  {
+    "title": "Jolly Boy Dog & Friends",
+    "handle": "jolly-boy-friends-wallpaper",
+    "url": "https://www.designerwallcoverings.com/products/jolly-boy-friends-wallpaper",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Screenshot2025-05-12at7.30.51AM.png?v=1747060405"
+  },
+  {
+    "title": "Steampunk Notice Board",
+    "handle": "steampunk-notice-board-wallpaper",
+    "url": "https://www.designerwallcoverings.com/products/steampunk-notice-board-wallpaper",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_07_Image_0002.jpg?v=1612388486"
+  },
+  {
+    "title": "Toucan And Bee Catcher",
+    "handle": "toucan-and-bee-catcher-wallpaper-1",
+    "url": "https://www.designerwallcoverings.com/products/toucan-and-bee-catcher-wallpaper-1",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_11_Image_0001.jpg?v=1747080307"
+  },
+  {
+    "title": "Stag Grande - Plum",
+    "handle": "stag-wallpaper",
+    "url": "https://www.designerwallcoverings.com/products/stag-wallpaper",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_17_Image_0002.jpg?v=1570091054"
+  },
+  {
+    "title": "Stag Grande Teal",
+    "handle": "stag-grande-wallpaper",
+    "url": "https://www.designerwallcoverings.com/products/stag-grande-wallpaper",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_17_Image_0006.jpg?v=1570091054"
+  },
+  {
+    "title": "Stag Grande Grey",
+    "handle": "stag-grande-wallpaper-1",
+    "url": "https://www.designerwallcoverings.com/products/stag-grande-wallpaper-1",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Graduate_Collection_wallpaper_trade_book_Page_17_Image_0007.jpg?v=1570091054"
+  },
+  {
+    "title": "Portarait Gallery Taupe | The Graduate Collection",
+    "handle": "dwc-1001302",
+    "url": "https://www.designerwallcoverings.com/products/dwc-1001302",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Portarait_Gallery_Taupe_1.jpg?v=1602006843"
+  },
+  {
+    "title": "Tiger Cream Bathroom | The Graduate Collection",
+    "handle": "dwc-1001316",
+    "url": "https://www.designerwallcoverings.com/products/dwc-1001316",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/Tiger_Cream_Bathroom_WEB.jpg?v=1602006869"
+  },
+  {
+    "title": "Savannah Cheetah - Charcoal",
+    "handle": "savannah-cheetah-charcoal",
+    "url": "https://www.designerwallcoverings.com/products/savannah-cheetah-charcoal",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/ScreenShot2021-10-08at2.55.41PM.png?v=1633730364"
+  },
+  {
+    "title": "Small Stag Teal",
+    "handle": "small-stag-wallpaper-teal",
+    "url": "https://www.designerwallcoverings.com/products/small-stag-wallpaper-teal",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/ScreenShot2021-10-08at3.36.54PM.png?v=1633732668"
+  },
+  {
+    "title": "Tiger And Temple Green",
+    "handle": "tiger-and-temple-green",
+    "url": "https://www.designerwallcoverings.com/products/tiger-and-temple-green",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/tigertemple.jpg?v=1647024988"
+  },
+  {
+    "title": "Botanical Print - Multi",
+    "handle": "jungle-print-wallpaper-multi",
+    "url": "https://www.designerwallcoverings.com/products/jungle-print-wallpaper-multi",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/ScreenShot2022-12-07at9.30.07AM.png?v=1670434232"
+  },
+  {
+    "title": "Savannah Cheetah - Green",
+    "handle": "savannah-cheetah-green",
+    "url": "https://www.designerwallcoverings.com/products/savannah-cheetah-green",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/ScreenShot2024-03-04at1.58.23PM.png?v=1709589538"
+  },
+  {
+    "title": "All Over Leopard - Blue",
+    "handle": "copy-of-exotic-tiger-wallpaper-charcoal",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-exotic-tiger-wallpaper-charcoal",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/AlloverLeopardCharcoal.png?v=1709835248"
+  },
+  {
+    "title": "All Over Leopard Blue",
+    "handle": "copy-of-all-over-leopard-blue",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-all-over-leopard-blue",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Screenshot2025-06-24at12.37.36PM.png?v=1750793883"
+  },
+  {
+    "title": "All Over Leopard Charcoal",
+    "handle": "copy-of-all-over-leopard-charcoal",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-all-over-leopard-charcoal",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Screenshot2025-06-24at12.36.31PM.png?v=1750793823"
+  },
+  {
+    "title": "Dipped In Moonlight Charcoal",
+    "handle": "copy-of-dipped-in-moonlight-charcoal",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-dipped-in-moonlight-charcoal",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/DippedinMoonlightMetalllicGold_Teal_c272519f-6ae8-4897-b33d-f518c24008df.png?v=1730484627"
+  },
+  {
+    "title": "Dipped In Moonlight Cream",
+    "handle": "copy-of-dipped-in-moonlight-cream",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-dipped-in-moonlight-cream",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/DippedinMoonlightMetalllic_Cream_4c873c3d-77ee-4fcf-8900-ad39cdbdfe1c.png?v=1730484621"
+  },
+  {
+    "title": "Dipped In Moonlight Teal",
+    "handle": "copy-of-dipped-in-moonlight-teal",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-dipped-in-moonlight-teal",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/DippedinMoonlightMetalllic_Teal_fc6a1852-7e7d-472b-a075-06ef92f14c8a.png?v=1730484615"
+  },
+  {
+    "title": "Dachshund Dog",
+    "handle": "copy-of-dachshund-natural",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-dachshund-natural",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/NEWDachshund_NATURAL.jpg?v=1750792583"
+  },
+  {
+    "title": "Monkey Biz Black",
+    "handle": "copy-of-monkey-biz-black",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-monkey-biz-black",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/MonkeyBusiness_0b1e2f1a-e83e-4f96-b1c3-33bce1010512.png?v=1730484572"
+  },
+  {
+    "title": "Monkey Biz Pink",
+    "handle": "copy-of-monkey-biz-pink",
+    "url": "https://www.designerwallcoverings.com/products/copy-of-monkey-biz-pink",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/MonkeyBusinessPink_00e8571a-3065-4a60-a714-02ab08fb557e.png?v=1730484563"
+  },
+  {
+    "title": "On Safari Cream",
+    "handle": "on-safari-cream-wallpaper-the-graduate-collection",
+    "url": "https://www.designerwallcoverings.com/products/on-safari-cream-wallpaper-the-graduate-collection",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/OnSafariCream_45b24b2f-3605-4ab2-9408-b9be2a5f43e9.png?v=1730484553"
+  },
+  {
+    "title": "Colonel Fox at the Gentleman's Club - Mustard",
+    "handle": "grd-8900-designerwallcoverings-com",
+    "url": "https://www.designerwallcoverings.com/products/grd-8900-designerwallcoverings-com",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/GRD-8900-DesignerWallcoverings-Los-Angeles-1_e3102e92-3911-4763-8ffd-1bb3d218d57e.jpg?v=1730485220"
+  },
+  {
+    "title": "All Over Leopard - Aubergine",
+    "handle": "all-over-leopard-aubergine-graduate-collection",
+    "url": "https://www.designerwallcoverings.com/products/all-over-leopard-aubergine-graduate-collection",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/B48C9B51-6F0D-4973-985F-992BBF14F800.jpg?v=1772164893"
+  },
+  {
+    "title": "All Over Leopard - Brown",
+    "handle": "all-over-leopard-brown-graduate-collection",
+    "url": "https://www.designerwallcoverings.com/products/all-over-leopard-brown-graduate-collection",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/80F7ADF4-D400-4D78-89E2-E8024E0C12EB.jpg?v=1772164915"
+  },
+  {
+    "title": "Cheetah - Brown",
+    "handle": "cheetah-brown-graduate-collection",
+    "url": "https://www.designerwallcoverings.com/products/cheetah-brown-graduate-collection",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/IMG-1501.jpg?v=1772164931"
+  },
+  {
+    "title": "Cheetah Brown",
+    "handle": "cheetah-brown-wallpaper-graduate-collection",
+    "url": "https://www.designerwallcoverings.com/products/cheetah-brown-wallpaper-graduate-collection",
+    "image": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/IMG-1501_1eec4f1c-a048-47e3-9ff5-cb5966b054b7.jpg?v=1773663602"
+  }
+]
\ No newline at end of file
diff --git a/flipbooks/graduate-collection/assets/img/p0.jpg b/flipbooks/graduate-collection/assets/img/p0.jpg
new file mode 100644
index 0000000..e717c21
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p0.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p1.jpg b/flipbooks/graduate-collection/assets/img/p1.jpg
new file mode 100644
index 0000000..39eab6a
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p1.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p10.jpg b/flipbooks/graduate-collection/assets/img/p10.jpg
new file mode 100644
index 0000000..254a6a3
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p10.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p11.jpg b/flipbooks/graduate-collection/assets/img/p11.jpg
new file mode 100644
index 0000000..bc3c304
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p11.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p12.jpg b/flipbooks/graduate-collection/assets/img/p12.jpg
new file mode 100644
index 0000000..d007fd4
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p12.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p13.jpg b/flipbooks/graduate-collection/assets/img/p13.jpg
new file mode 100644
index 0000000..0a00b68
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p13.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p14.jpg b/flipbooks/graduate-collection/assets/img/p14.jpg
new file mode 100644
index 0000000..944902d
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p14.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p15.jpg b/flipbooks/graduate-collection/assets/img/p15.jpg
new file mode 100644
index 0000000..b7342a2
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p15.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p16.jpg b/flipbooks/graduate-collection/assets/img/p16.jpg
new file mode 100644
index 0000000..6f3befb
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p16.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p17.jpg b/flipbooks/graduate-collection/assets/img/p17.jpg
new file mode 100644
index 0000000..1bbe14a
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p17.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p18.jpg b/flipbooks/graduate-collection/assets/img/p18.jpg
new file mode 100644
index 0000000..d39f7ac
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p18.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p19.jpg b/flipbooks/graduate-collection/assets/img/p19.jpg
new file mode 100644
index 0000000..5b8730e
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p19.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p2.jpg b/flipbooks/graduate-collection/assets/img/p2.jpg
new file mode 100644
index 0000000..25e5dee
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p2.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p20.jpg b/flipbooks/graduate-collection/assets/img/p20.jpg
new file mode 100644
index 0000000..6b33150
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p20.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p21.jpg b/flipbooks/graduate-collection/assets/img/p21.jpg
new file mode 100644
index 0000000..8f87bb5
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p21.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p22.jpg b/flipbooks/graduate-collection/assets/img/p22.jpg
new file mode 100644
index 0000000..9080355
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p22.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p23.jpg b/flipbooks/graduate-collection/assets/img/p23.jpg
new file mode 100644
index 0000000..22fac9a
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p23.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p24.jpg b/flipbooks/graduate-collection/assets/img/p24.jpg
new file mode 100644
index 0000000..80438d8
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p24.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p25.jpg b/flipbooks/graduate-collection/assets/img/p25.jpg
new file mode 100644
index 0000000..63d445a
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p25.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p26.jpg b/flipbooks/graduate-collection/assets/img/p26.jpg
new file mode 100644
index 0000000..c2c4c2e
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p26.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p27.jpg b/flipbooks/graduate-collection/assets/img/p27.jpg
new file mode 100644
index 0000000..44fe323
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p27.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p28.jpg b/flipbooks/graduate-collection/assets/img/p28.jpg
new file mode 100644
index 0000000..46b2a84
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p28.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p29.jpg b/flipbooks/graduate-collection/assets/img/p29.jpg
new file mode 100644
index 0000000..9e77505
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p29.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p3.jpg b/flipbooks/graduate-collection/assets/img/p3.jpg
new file mode 100644
index 0000000..d72fa05
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p3.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p30.jpg b/flipbooks/graduate-collection/assets/img/p30.jpg
new file mode 100644
index 0000000..ee596b9
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p30.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p31.jpg b/flipbooks/graduate-collection/assets/img/p31.jpg
new file mode 100644
index 0000000..63317d5
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p31.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p32.jpg b/flipbooks/graduate-collection/assets/img/p32.jpg
new file mode 100644
index 0000000..be215ea
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p32.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p33.jpg b/flipbooks/graduate-collection/assets/img/p33.jpg
new file mode 100644
index 0000000..ff746c6
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p33.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p34.jpg b/flipbooks/graduate-collection/assets/img/p34.jpg
new file mode 100644
index 0000000..ff746c6
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p34.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p4.jpg b/flipbooks/graduate-collection/assets/img/p4.jpg
new file mode 100644
index 0000000..76613bd
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p4.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p5.jpg b/flipbooks/graduate-collection/assets/img/p5.jpg
new file mode 100644
index 0000000..e0c4bdb
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p5.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p6.jpg b/flipbooks/graduate-collection/assets/img/p6.jpg
new file mode 100644
index 0000000..f9d0416
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p6.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p7.jpg b/flipbooks/graduate-collection/assets/img/p7.jpg
new file mode 100644
index 0000000..d3e7400
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p7.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p8.jpg b/flipbooks/graduate-collection/assets/img/p8.jpg
new file mode 100644
index 0000000..74d668d
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p8.jpg differ
diff --git a/flipbooks/graduate-collection/assets/img/p9.jpg b/flipbooks/graduate-collection/assets/img/p9.jpg
new file mode 100644
index 0000000..a483959
Binary files /dev/null and b/flipbooks/graduate-collection/assets/img/p9.jpg differ
diff --git a/flipbooks/graduate-collection/hyperframes.json b/flipbooks/graduate-collection/hyperframes.json
new file mode 100644
index 0000000..5fb1d6d
--- /dev/null
+++ b/flipbooks/graduate-collection/hyperframes.json
@@ -0,0 +1,9 @@
+{
+  "$schema": "https://hyperframes.heygen.com/schema/hyperframes.json",
+  "registry": "https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry",
+  "paths": {
+    "blocks": "compositions",
+    "components": "compositions/components",
+    "assets": "assets"
+  }
+}
diff --git a/flipbooks/graduate-collection/index.html b/flipbooks/graduate-collection/index.html
new file mode 100644
index 0000000..e5a22e0
--- /dev/null
+++ b/flipbooks/graduate-collection/index.html
@@ -0,0 +1,576 @@
+<!doctype html>
+<html lang="en" data-resolution="landscape">
+<head>
+<meta charset="UTF-8" />
+<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
+<style>
+  :root { --ink:#1c1a17; --cream:#f4efe6; --paper:#fbf8f1; --gold:#b08d57; }
+  html,body { margin:0; padding:0; width:1920px; height:1080px; overflow:hidden;
+    background:radial-gradient(120% 120% at 50% 0%, #2a2622 0%, #14110e 70%);
+    font-family:"Helvetica Neue",system-ui,sans-serif; }
+  #main-composition { position:relative; width:1920px; height:1080px; overflow:hidden; }
+  .stage { position:absolute; inset:0; perspective:2600px; perspective-origin:50% 46%; }
+
+  /* left static page (the book's verso) */
+  .verso { position:absolute; top:97px; left:290px; width:670px; height:886px;
+    background:var(--paper); border-radius:6px 2px 2px 6px;
+    box-shadow: inset -28px 0 44px rgba(0,0,0,.10), 0 30px 60px rgba(0,0,0,.45);
+    display:flex; align-items:center; justify-content:center; }
+  .verso .spinemark { font-family:Georgia, serif; color:#cbb48f;
+    writing-mode:vertical-rl; font-size:34px; letter-spacing:.28em; text-transform:uppercase; opacity:.6; }
+
+  /* stacked flipping leaves — pinned at the spine */
+  .leaf { position:absolute; top:97px; left:960px; width:670px; height:886px;
+    transform-origin:left center; transform-style:preserve-3d; will-change:transform;
+    border-radius:2px 6px 6px 2px; }
+  .leaf .face { position:absolute; inset:0; backface-visibility:hidden; overflow:hidden;
+    border-radius:2px 6px 6px 2px; background:var(--paper);
+    box-shadow: 20px 26px 50px rgba(0,0,0,.40), inset 22px 0 40px rgba(0,0,0,.08); }
+  .leaf .front { }
+  .leaf .back { transform:rotateY(180deg); background:
+    linear-gradient(90deg,#efe9dc, #fbf8f1 22%);
+    box-shadow: -20px 26px 50px rgba(0,0,0,.35), inset -22px 0 40px rgba(0,0,0,.08); }
+  .leaf .art { position:absolute; left:0; top:0; width:100%; height:78%; object-fit:cover; }
+  .leaf .cap { position:absolute; left:0; right:0; bottom:0; height:22%; padding:0 34px;
+    display:flex; flex-direction:column; justify-content:center; background:var(--paper); }
+  .leaf .cap .pat { font-family:Georgia, serif; font-size:42px;
+    line-height:1.04; color:var(--ink); }
+  .leaf .cap .col { margin-top:8px; font-size:19px; letter-spacing:.22em;
+    text-transform:uppercase; color:var(--gold); }
+  .leaf .shade { position:absolute; inset:0; opacity:0; pointer-events:none;
+    background:linear-gradient(90deg, rgba(0,0,0,.42), rgba(0,0,0,0) 60%); }
+
+  /* cover + outro cards */
+  .card { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center;
+    text-align:center; color:var(--cream); }
+  .card .kicker { font-size:33px; letter-spacing:.44em; text-transform:uppercase; color:var(--gold); }
+  .card .big { font-family:Georgia, serif; font-size:138px; line-height:1.0; margin:22px 60px; }
+  .card .sub { font-size:36px; letter-spacing:.18em; text-transform:uppercase; color:#c9bfae; }
+  .card .rule { width:120px; height:2px; background:var(--gold); margin:34px 0; }
+  .card .url { margin-top:30px; font-size:33px; letter-spacing:.24em; text-transform:uppercase; color:var(--cream); }
+</style>
+</head>
+<body>
+  <div id="main-composition" data-composition-id="flipbook"
+       data-width="1920" data-height="1080" data-start="0" data-duration="28.7">
+
+    <!-- cover -->
+    <div class="card" id="cover">
+      <div class="kicker">Designer Wallcoverings presents</div>
+      <div class="big">Graduate Collection</div>
+      <div class="rule"></div>
+      <div class="sub">London · Maximalist British Wallpaper</div>
+    </div>
+
+    <div class="stage" id="stage">
+      <div class="verso"><div class="spinemark">Graduate Collection</div></div>
+      
+    <div class="leaf" id="leaf0">
+      <div class="face front">
+        <img class="art" src="assets/img/p0.jpg" alt="Savannah Cheetah - Mustard" />
+        <div class="cap"><div class="pat">Savannah Cheetah - Mustard</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf1">
+      <div class="face front">
+        <img class="art" src="assets/img/p1.jpg" alt="Tiger Tiger - In the Jungle - Cream" />
+        <div class="cap"><div class="pat">Tiger Tiger - In the Jungle - Cream</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf2">
+      <div class="face front">
+        <img class="art" src="assets/img/p2.jpg" alt="Tiger Tiger - In the Jungle - Green" />
+        <div class="cap"><div class="pat">Tiger Tiger - In the Jungle - Green</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf3">
+      <div class="face front">
+        <img class="art" src="assets/img/p3.jpg" alt="Visitorian - Taupe" />
+        <div class="cap"><div class="pat">Visitorian - Taupe</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf4">
+      <div class="face front">
+        <img class="art" src="assets/img/p4.jpg" alt="Visitorian Navy" />
+        <div class="cap"><div class="pat">Visitorian Navy</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf5">
+      <div class="face front">
+        <img class="art" src="assets/img/p5.jpg" alt="Visitorian Mauve" />
+        <div class="cap"><div class="pat">Visitorian Mauve</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf6">
+      <div class="face front">
+        <img class="art" src="assets/img/p6.jpg" alt="Visitorian Blue" />
+        <div class="cap"><div class="pat">Visitorian Blue</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf7">
+      <div class="face front">
+        <img class="art" src="assets/img/p7.jpg" alt="Jolly Boy Dog &amp; Friends" />
+        <div class="cap"><div class="pat">Jolly Boy Dog &amp; Friends</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf8">
+      <div class="face front">
+        <img class="art" src="assets/img/p8.jpg" alt="Steampunk Notice Board" />
+        <div class="cap"><div class="pat">Steampunk Notice Board</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf9">
+      <div class="face front">
+        <img class="art" src="assets/img/p9.jpg" alt="Toucan And Bee Catcher" />
+        <div class="cap"><div class="pat">Toucan And Bee Catcher</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf10">
+      <div class="face front">
+        <img class="art" src="assets/img/p10.jpg" alt="Stag Grande - Plum" />
+        <div class="cap"><div class="pat">Stag Grande - Plum</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf11">
+      <div class="face front">
+        <img class="art" src="assets/img/p11.jpg" alt="Stag Grande Teal" />
+        <div class="cap"><div class="pat">Stag Grande Teal</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf12">
+      <div class="face front">
+        <img class="art" src="assets/img/p12.jpg" alt="Stag Grande Grey" />
+        <div class="cap"><div class="pat">Stag Grande Grey</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf13">
+      <div class="face front">
+        <img class="art" src="assets/img/p13.jpg" alt="Portarait Gallery Taupe | The Graduate Collection" />
+        <div class="cap"><div class="pat">Portarait Gallery Taupe | The Graduate Collection</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf14">
+      <div class="face front">
+        <img class="art" src="assets/img/p14.jpg" alt="Tiger Cream Bathroom | The Graduate Collection" />
+        <div class="cap"><div class="pat">Tiger Cream Bathroom | The Graduate Collection</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf15">
+      <div class="face front">
+        <img class="art" src="assets/img/p15.jpg" alt="Savannah Cheetah - Charcoal" />
+        <div class="cap"><div class="pat">Savannah Cheetah - Charcoal</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf16">
+      <div class="face front">
+        <img class="art" src="assets/img/p16.jpg" alt="Small Stag Teal" />
+        <div class="cap"><div class="pat">Small Stag Teal</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf17">
+      <div class="face front">
+        <img class="art" src="assets/img/p17.jpg" alt="Tiger And Temple Green" />
+        <div class="cap"><div class="pat">Tiger And Temple Green</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf18">
+      <div class="face front">
+        <img class="art" src="assets/img/p18.jpg" alt="Botanical Print - Multi" />
+        <div class="cap"><div class="pat">Botanical Print - Multi</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf19">
+      <div class="face front">
+        <img class="art" src="assets/img/p19.jpg" alt="Savannah Cheetah - Green" />
+        <div class="cap"><div class="pat">Savannah Cheetah - Green</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf20">
+      <div class="face front">
+        <img class="art" src="assets/img/p20.jpg" alt="All Over Leopard - Blue" />
+        <div class="cap"><div class="pat">All Over Leopard - Blue</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf21">
+      <div class="face front">
+        <img class="art" src="assets/img/p21.jpg" alt="All Over Leopard Blue" />
+        <div class="cap"><div class="pat">All Over Leopard Blue</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf22">
+      <div class="face front">
+        <img class="art" src="assets/img/p22.jpg" alt="All Over Leopard Charcoal" />
+        <div class="cap"><div class="pat">All Over Leopard Charcoal</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf23">
+      <div class="face front">
+        <img class="art" src="assets/img/p23.jpg" alt="Dipped In Moonlight Charcoal" />
+        <div class="cap"><div class="pat">Dipped In Moonlight Charcoal</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf24">
+      <div class="face front">
+        <img class="art" src="assets/img/p24.jpg" alt="Dipped In Moonlight Cream" />
+        <div class="cap"><div class="pat">Dipped In Moonlight Cream</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf25">
+      <div class="face front">
+        <img class="art" src="assets/img/p25.jpg" alt="Dipped In Moonlight Teal" />
+        <div class="cap"><div class="pat">Dipped In Moonlight Teal</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf26">
+      <div class="face front">
+        <img class="art" src="assets/img/p26.jpg" alt="Dachshund Dog" />
+        <div class="cap"><div class="pat">Dachshund Dog</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf27">
+      <div class="face front">
+        <img class="art" src="assets/img/p27.jpg" alt="Monkey Biz Black" />
+        <div class="cap"><div class="pat">Monkey Biz Black</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf28">
+      <div class="face front">
+        <img class="art" src="assets/img/p28.jpg" alt="Monkey Biz Pink" />
+        <div class="cap"><div class="pat">Monkey Biz Pink</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf29">
+      <div class="face front">
+        <img class="art" src="assets/img/p29.jpg" alt="On Safari Cream" />
+        <div class="cap"><div class="pat">On Safari Cream</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf30">
+      <div class="face front">
+        <img class="art" src="assets/img/p30.jpg" alt="Colonel Fox at the Gentleman's Club - Mustard" />
+        <div class="cap"><div class="pat">Colonel Fox at the Gentleman's Club - Mustard</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf31">
+      <div class="face front">
+        <img class="art" src="assets/img/p31.jpg" alt="All Over Leopard - Aubergine" />
+        <div class="cap"><div class="pat">All Over Leopard - Aubergine</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf32">
+      <div class="face front">
+        <img class="art" src="assets/img/p32.jpg" alt="All Over Leopard - Brown" />
+        <div class="cap"><div class="pat">All Over Leopard - Brown</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf33">
+      <div class="face front">
+        <img class="art" src="assets/img/p33.jpg" alt="Cheetah - Brown" />
+        <div class="cap"><div class="pat">Cheetah - Brown</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    <div class="leaf" id="leaf34">
+      <div class="face front">
+        <img class="art" src="assets/img/p34.jpg" alt="Cheetah Brown" />
+        <div class="cap"><div class="pat">Cheetah Brown</div><div class="col">Graduate Collection</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>
+    </div>
+
+    <!-- outro -->
+    <div class="card" id="outro">
+      <div class="kicker">Shop the collection</div>
+      <div class="big">Graduate Collection</div>
+      <div class="url">designerwallcoverings.com</div>
+    </div>
+
+    <script>
+      window.__timelines = window.__timelines || {};
+      const tl = gsap.timeline({ paused: true });
+
+      // initial state — leaves stacked, page 0 on top of the right stack
+      gsap.set("#leaf0", { rotateY: 0, zIndex: 35 });
+      gsap.set("#leaf1", { rotateY: 0, zIndex: 34 });
+      gsap.set("#leaf2", { rotateY: 0, zIndex: 33 });
+      gsap.set("#leaf3", { rotateY: 0, zIndex: 32 });
+      gsap.set("#leaf4", { rotateY: 0, zIndex: 31 });
+      gsap.set("#leaf5", { rotateY: 0, zIndex: 30 });
+      gsap.set("#leaf6", { rotateY: 0, zIndex: 29 });
+      gsap.set("#leaf7", { rotateY: 0, zIndex: 28 });
+      gsap.set("#leaf8", { rotateY: 0, zIndex: 27 });
+      gsap.set("#leaf9", { rotateY: 0, zIndex: 26 });
+      gsap.set("#leaf10", { rotateY: 0, zIndex: 25 });
+      gsap.set("#leaf11", { rotateY: 0, zIndex: 24 });
+      gsap.set("#leaf12", { rotateY: 0, zIndex: 23 });
+      gsap.set("#leaf13", { rotateY: 0, zIndex: 22 });
+      gsap.set("#leaf14", { rotateY: 0, zIndex: 21 });
+      gsap.set("#leaf15", { rotateY: 0, zIndex: 20 });
+      gsap.set("#leaf16", { rotateY: 0, zIndex: 19 });
+      gsap.set("#leaf17", { rotateY: 0, zIndex: 18 });
+      gsap.set("#leaf18", { rotateY: 0, zIndex: 17 });
+      gsap.set("#leaf19", { rotateY: 0, zIndex: 16 });
+      gsap.set("#leaf20", { rotateY: 0, zIndex: 15 });
+      gsap.set("#leaf21", { rotateY: 0, zIndex: 14 });
+      gsap.set("#leaf22", { rotateY: 0, zIndex: 13 });
+      gsap.set("#leaf23", { rotateY: 0, zIndex: 12 });
+      gsap.set("#leaf24", { rotateY: 0, zIndex: 11 });
+      gsap.set("#leaf25", { rotateY: 0, zIndex: 10 });
+      gsap.set("#leaf26", { rotateY: 0, zIndex: 9 });
+      gsap.set("#leaf27", { rotateY: 0, zIndex: 8 });
+      gsap.set("#leaf28", { rotateY: 0, zIndex: 7 });
+      gsap.set("#leaf29", { rotateY: 0, zIndex: 6 });
+      gsap.set("#leaf30", { rotateY: 0, zIndex: 5 });
+      gsap.set("#leaf31", { rotateY: 0, zIndex: 4 });
+      gsap.set("#leaf32", { rotateY: 0, zIndex: 3 });
+      gsap.set("#leaf33", { rotateY: 0, zIndex: 2 });
+      gsap.set("#leaf34", { rotateY: 0, zIndex: 1 });
+      gsap.set("#stage", { opacity: 0 });
+      gsap.set("#outro", { opacity: 0 });
+      gsap.set("#outro .big", { y: 36, opacity: 0 });
+      gsap.set("#outro .url", { opacity: 0 });
+      gsap.set("#cover .big", { y: 40, opacity: 0 });
+      gsap.set("#cover .kicker,#cover .sub,#cover .rule", { opacity: 0 });
+
+      // cover in
+      tl.to("#cover .kicker", { opacity: 1, duration: 0.5 }, 0.15);
+      tl.to("#cover .big", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 0.35);
+      tl.to("#cover .rule,#cover .sub", { opacity: 1, duration: 0.5 }, 0.95);
+      tl.to("#cover", { opacity: 0, duration: 0.5, ease: "power1.in" }, 1.15);
+      tl.to("#stage", { opacity: 1, duration: 0.5, ease: "power1.out" }, 1.20);
+
+      // page turns
+      
+    tl.to("#leaf0", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 1.700);
+    tl.to("#leaf0 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 1.700);
+    tl.to("#leaf0 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 1.95);
+    tl.set("#leaf0", { zIndex: 1000 }, 1.95);
+    tl.to("#leaf1 .art", { scale: 1.04, duration: 0.5, ease:"power2.out" }, 2.200);
+    tl.to("#leaf1 .art", { scale: 1.0, duration: 0.4, ease:"power2.in" }, 2.700);
+    tl.to("#leaf1", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 2.740);
+    tl.to("#leaf1 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 2.740);
+    tl.to("#leaf1 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 2.99);
+    tl.set("#leaf1", { zIndex: 1001 }, 2.99);
+    tl.to("#leaf2", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 3.380);
+    tl.to("#leaf2 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 3.380);
+    tl.to("#leaf2 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 3.63);
+    tl.set("#leaf2", { zIndex: 1002 }, 3.63);
+    tl.to("#leaf3", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 4.020);
+    tl.to("#leaf3 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 4.020);
+    tl.to("#leaf3 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 4.27);
+    tl.set("#leaf3", { zIndex: 1003 }, 4.27);
+    tl.to("#leaf4", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 4.660);
+    tl.to("#leaf4 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 4.660);
+    tl.to("#leaf4 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 4.91);
+    tl.set("#leaf4", { zIndex: 1004 }, 4.91);
+    tl.to("#leaf5", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 5.300);
+    tl.to("#leaf5 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 5.300);
+    tl.to("#leaf5 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 5.55);
+    tl.set("#leaf5", { zIndex: 1005 }, 5.55);
+    tl.to("#leaf6", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 5.940);
+    tl.to("#leaf6 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 5.940);
+    tl.to("#leaf6 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 6.19);
+    tl.set("#leaf6", { zIndex: 1006 }, 6.19);
+    tl.to("#leaf7 .art", { scale: 1.04, duration: 0.5, ease:"power2.out" }, 6.440);
+    tl.to("#leaf7 .art", { scale: 1.0, duration: 0.4, ease:"power2.in" }, 6.940);
+    tl.to("#leaf7", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 6.980);
+    tl.to("#leaf7 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 6.980);
+    tl.to("#leaf7 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 7.23);
+    tl.set("#leaf7", { zIndex: 1007 }, 7.23);
+    tl.to("#leaf8", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 7.620);
+    tl.to("#leaf8 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 7.620);
+    tl.to("#leaf8 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 7.87);
+    tl.set("#leaf8", { zIndex: 1008 }, 7.87);
+    tl.to("#leaf9", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 8.260);
+    tl.to("#leaf9 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 8.260);
+    tl.to("#leaf9 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 8.51);
+    tl.set("#leaf9", { zIndex: 1009 }, 8.51);
+    tl.to("#leaf10", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 8.900);
+    tl.to("#leaf10 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 8.900);
+    tl.to("#leaf10 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 9.15);
+    tl.set("#leaf10", { zIndex: 1010 }, 9.15);
+    tl.to("#leaf11", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 9.540);
+    tl.to("#leaf11 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 9.540);
+    tl.to("#leaf11 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 9.79);
+    tl.set("#leaf11", { zIndex: 1011 }, 9.79);
+    tl.to("#leaf12", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 10.180);
+    tl.to("#leaf12 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 10.180);
+    tl.to("#leaf12 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 10.43);
+    tl.set("#leaf12", { zIndex: 1012 }, 10.43);
+    tl.to("#leaf13 .art", { scale: 1.04, duration: 0.5, ease:"power2.out" }, 10.680);
+    tl.to("#leaf13 .art", { scale: 1.0, duration: 0.4, ease:"power2.in" }, 11.180);
+    tl.to("#leaf13", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 11.220);
+    tl.to("#leaf13 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 11.220);
+    tl.to("#leaf13 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 11.47);
+    tl.set("#leaf13", { zIndex: 1013 }, 11.47);
+    tl.to("#leaf14", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 11.860);
+    tl.to("#leaf14 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 11.860);
+    tl.to("#leaf14 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 12.11);
+    tl.set("#leaf14", { zIndex: 1014 }, 12.11);
+    tl.to("#leaf15", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 12.500);
+    tl.to("#leaf15 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 12.500);
+    tl.to("#leaf15 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 12.75);
+    tl.set("#leaf15", { zIndex: 1015 }, 12.75);
+    tl.to("#leaf16", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 13.140);
+    tl.to("#leaf16 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 13.140);
+    tl.to("#leaf16 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 13.39);
+    tl.set("#leaf16", { zIndex: 1016 }, 13.39);
+    tl.to("#leaf17", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 13.780);
+    tl.to("#leaf17 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 13.780);
+    tl.to("#leaf17 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 14.03);
+    tl.set("#leaf17", { zIndex: 1017 }, 14.03);
+    tl.to("#leaf18", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 14.420);
+    tl.to("#leaf18 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 14.420);
+    tl.to("#leaf18 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 14.67);
+    tl.set("#leaf18", { zIndex: 1018 }, 14.67);
+    tl.to("#leaf19 .art", { scale: 1.04, duration: 0.5, ease:"power2.out" }, 14.920);
+    tl.to("#leaf19 .art", { scale: 1.0, duration: 0.4, ease:"power2.in" }, 15.420);
+    tl.to("#leaf19", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 15.460);
+    tl.to("#leaf19 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 15.460);
+    tl.to("#leaf19 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 15.71);
+    tl.set("#leaf19", { zIndex: 1019 }, 15.71);
+    tl.to("#leaf20", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 16.100);
+    tl.to("#leaf20 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 16.100);
+    tl.to("#leaf20 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 16.35);
+    tl.set("#leaf20", { zIndex: 1020 }, 16.35);
+    tl.to("#leaf21", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 16.740);
+    tl.to("#leaf21 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 16.740);
+    tl.to("#leaf21 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 16.99);
+    tl.set("#leaf21", { zIndex: 1021 }, 16.99);
+    tl.to("#leaf22", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 17.380);
+    tl.to("#leaf22 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 17.380);
+    tl.to("#leaf22 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 17.63);
+    tl.set("#leaf22", { zIndex: 1022 }, 17.63);
+    tl.to("#leaf23", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 18.020);
+    tl.to("#leaf23 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 18.020);
+    tl.to("#leaf23 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 18.27);
+    tl.set("#leaf23", { zIndex: 1023 }, 18.27);
+    tl.to("#leaf24", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 18.660);
+    tl.to("#leaf24 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 18.660);
+    tl.to("#leaf24 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 18.91);
+    tl.set("#leaf24", { zIndex: 1024 }, 18.91);
+    tl.to("#leaf25 .art", { scale: 1.04, duration: 0.5, ease:"power2.out" }, 19.160);
+    tl.to("#leaf25 .art", { scale: 1.0, duration: 0.4, ease:"power2.in" }, 19.660);
+    tl.to("#leaf25", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 19.700);
+    tl.to("#leaf25 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 19.700);
+    tl.to("#leaf25 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 19.95);
+    tl.set("#leaf25", { zIndex: 1025 }, 19.95);
+    tl.to("#leaf26", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 20.340);
+    tl.to("#leaf26 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 20.340);
+    tl.to("#leaf26 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 20.59);
+    tl.set("#leaf26", { zIndex: 1026 }, 20.59);
+    tl.to("#leaf27", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 20.980);
+    tl.to("#leaf27 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 20.980);
+    tl.to("#leaf27 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 21.23);
+    tl.set("#leaf27", { zIndex: 1027 }, 21.23);
+    tl.to("#leaf28", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 21.620);
+    tl.to("#leaf28 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 21.620);
+    tl.to("#leaf28 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 21.87);
+    tl.set("#leaf28", { zIndex: 1028 }, 21.87);
+    tl.to("#leaf29", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 22.260);
+    tl.to("#leaf29 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 22.260);
+    tl.to("#leaf29 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 22.51);
+    tl.set("#leaf29", { zIndex: 1029 }, 22.51);
+    tl.to("#leaf30", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 22.900);
+    tl.to("#leaf30 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 22.900);
+    tl.to("#leaf30 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 23.15);
+    tl.set("#leaf30", { zIndex: 1030 }, 23.15);
+    tl.to("#leaf31 .art", { scale: 1.04, duration: 0.5, ease:"power2.out" }, 23.400);
+    tl.to("#leaf31 .art", { scale: 1.0, duration: 0.4, ease:"power2.in" }, 23.900);
+    tl.to("#leaf31", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 23.940);
+    tl.to("#leaf31 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 23.940);
+    tl.to("#leaf31 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 24.19);
+    tl.set("#leaf31", { zIndex: 1031 }, 24.19);
+    tl.to("#leaf32", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 24.580);
+    tl.to("#leaf32 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 24.580);
+    tl.to("#leaf32 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 24.83);
+    tl.set("#leaf32", { zIndex: 1032 }, 24.83);
+    tl.to("#leaf33", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 25.220);
+    tl.to("#leaf33 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 25.220);
+    tl.to("#leaf33 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 25.47);
+    tl.set("#leaf33", { zIndex: 1033 }, 25.47);
+    tl.to("#leaf34", { rotateY: -180, duration: 0.5, ease: "power2.inOut" }, 25.860);
+    tl.to("#leaf34 .shade", { opacity: 0.55, duration: 0.250, ease:"power1.in" }, 25.860);
+    tl.to("#leaf34 .shade", { opacity: 0, duration: 0.250, ease:"power1.out" }, 26.11);
+    tl.set("#leaf34", { zIndex: 1034 }, 26.11);
+
+      // outro
+      tl.to("#stage", { opacity: 0, duration: 0.5, ease: "power1.in" }, 26.50);
+      tl.to("#outro", { opacity: 1, duration: 0.5 }, 26.60);
+      tl.to("#outro .big", { opacity: 1, y: 0, duration: 0.7, ease: "power2.out" }, 26.80);
+      tl.to("#outro .url", { opacity: 1, duration: 0.5 }, 27.30);
+
+      window.__timelines["flipbook"] = tl;
+    </script>
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/flipbooks/graduate-collection/meta.json b/flipbooks/graduate-collection/meta.json
new file mode 100644
index 0000000..8e313dc
--- /dev/null
+++ b/flipbooks/graduate-collection/meta.json
@@ -0,0 +1 @@
+{"id":"flipbook-graduate-collection","name":"Graduate Collection Flipbook"}
diff --git a/flipbooks/graduate-collection/package.json b/flipbooks/graduate-collection/package.json
new file mode 100644
index 0000000..c98981d
--- /dev/null
+++ b/flipbooks/graduate-collection/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "flipbook-graduate-collection",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "npx --yes hyperframes@0.7.84 preview",
+    "check": "npx --yes hyperframes@0.7.84 check",
+    "render": "npx --yes hyperframes@0.7.84 render"
+  }
+}
diff --git a/scripts/build-collection-flipbook.mjs b/scripts/build-collection-flipbook.mjs
new file mode 100644
index 0000000..8988411
--- /dev/null
+++ b/scripts/build-collection-flipbook.mjs
@@ -0,0 +1,260 @@
+#!/usr/bin/env node
+/**
+ * build-collection-flipbook.mjs — turn any DW collection/vendor into a 3D
+ * page-turn "flip book" HyperFrames composition, then (optionally) render MP4.
+ *
+ * Reusable engine behind the /collection-flipbook skill.
+ *
+ * Usage:
+ *   node scripts/build-collection-flipbook.mjs \
+ *     --data data/graduate-collection.json \
+ *     --slug graduate-collection \
+ *     --title "Graduate Collection" \
+ *     --subtitle "London · Maximalist British Wallpaper" \
+ *     [--ratio landscape|portrait|square] [--no-images]
+ *
+ * Data JSON: [{ title, image, url?, handle? }, ...]  (image = remote URL or local path)
+ *
+ * Everything is deterministic (HyperFrames rule: no Date.now/Math.random/network
+ * inside the composition). Images are downloaded + resized LOCALLY at build time.
+ */
+import fs from 'node:fs';
+import path from 'node:path';
+import os from 'node:os';
+import { execSync } from 'node:child_process';
+import https from 'node:https';
+
+// ---------- args ----------
+const args = Object.fromEntries(process.argv.slice(2).reduce((a, cur, i, arr) => {
+  if (cur.startsWith('--')) {
+    const k = cur.slice(2);
+    const v = (arr[i + 1] && !arr[i + 1].startsWith('--')) ? arr[i + 1] : true;
+    a.push([k, v]);
+  }
+  return a;
+}, []));
+
+const PROJ = path.resolve(path.join(path.dirname(new URL(import.meta.url).pathname), '..'));
+const dataPath = path.resolve(args.data || `${PROJ}/data/graduate-collection.json`);
+const slug = args.slug || 'collection-flipbook';
+const title = args.title || 'Collection';
+const subtitle = args.subtitle || 'Designer Wallcoverings';
+const ratio = args.ratio || 'landscape';
+const doImages = !args['no-images'];
+
+const RATIOS = { landscape: [1920, 1080], portrait: [1080, 1920], square: [1080, 1080] };
+const [W, H] = RATIOS[ratio] || RATIOS.landscape;
+
+const wsDir = `${PROJ}/flipbooks/${slug}`;
+const imgDir = `${wsDir}/assets/img`;
+fs.mkdirSync(imgDir, { recursive: true });
+
+const products = JSON.parse(fs.readFileSync(dataPath, 'utf8')).filter(p => p.image);
+if (!products.length) { console.error('No products with images in', dataPath); process.exit(1); }
+console.log(`Building flipbook "${title}" — ${products.length} pages @ ${W}x${H}`);
+
+// ---------- localize + resize images ----------
+function download(url, dest) {
+  return new Promise((resolve, reject) => {
+    const file = fs.createWriteStream(dest);
+    https.get(url, { headers: { 'User-Agent': 'Mozilla/5.0 DW-flipbook' } }, (res) => {
+      if (res.statusCode >= 300 && res.headers.location) {
+        file.close(); fs.rmSync(dest, { force: true });
+        return download(res.headers.location, dest).then(resolve, reject);
+      }
+      if (res.statusCode !== 200) { file.close(); return reject(new Error('HTTP ' + res.statusCode)); }
+      res.pipe(file);
+      file.on('finish', () => file.close(resolve));
+    }).on('error', reject);
+  });
+}
+
+const PAGE_MAX = Math.round(Math.min(W, H) * 0.95); // resize cap for render speed
+let localized = 0;
+for (let i = 0; i < products.length; i++) {
+  const p = products[i];
+  const dest = `${imgDir}/p${i}.jpg`;
+  if (doImages) {
+    if (/^https?:/.test(p.image)) {
+      try {
+        await download(p.image.replace(/\?.*$/, '') + '?width=1200', dest);
+        // resize/normalize with macOS sips ($0 local) — square-ish crop-safe max box
+        try { execSync(`sips -Z ${PAGE_MAX} "${dest}" >/dev/null 2>&1`); } catch {}
+        localized++;
+      } catch (e) { console.warn(`  ! image ${i} (${p.title}): ${e.message}`); }
+    } else if (fs.existsSync(p.image)) {
+      fs.copyFileSync(p.image, dest);
+      try { execSync(`sips -Z ${PAGE_MAX} "${dest}" >/dev/null 2>&1`); } catch {}
+      localized++;
+    }
+  }
+  p._img = `assets/img/p${i}.jpg`;
+}
+console.log(`  localized ${localized}/${products.length} images`);
+
+// ---------- geometry ----------
+const N = products.length;
+const pageW = Math.round(H * 0.62);          // leaf width
+const pageH = Math.round(H * 0.82);          // leaf height
+const spineX = Math.round(W / 2);            // book spine at horizontal center
+const bookTop = Math.round((H - pageH) / 2);
+
+// ---------- timing ----------
+const INTRO = 1.7;                           // cover reveal
+const FLIP = 0.5;                            // one page turn
+const HOLD = 0.14;                           // read beat before next turn
+const INTERVAL = FLIP + HOLD;                // per-page cadence
+const HERO_EVERY = Math.max(4, Math.round(N / 6)); // slow-down cadence
+const OUTRO = 2.2;
+
+let t = INTRO;
+const flips = products.map((p, i) => {
+  const hero = (i % HERO_EVERY === 0);
+  const start = t;
+  const dur = FLIP;
+  t += INTERVAL + (hero ? 0.4 : 0);         // linger on hero pages
+  return { start, dur, hero };
+});
+const flipsEnd = t;
+const TOTAL = +(flipsEnd + OUTRO).toFixed(2);
+
+// ---------- html ----------
+const esc = s => String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+
+const leaves = products.map((p, i) => `
+    <div class="leaf" id="leaf${i}">
+      <div class="face front">
+        <img class="art" src="${p._img}" alt="${esc(p.title)}" />
+        <div class="cap"><div class="pat">${esc(p.title)}</div><div class="col">${esc(title)}</div></div>
+        <div class="shade"></div>
+      </div>
+      <div class="face back"></div>
+    </div>`).join('');
+
+// z-index + flip tweens
+const tweens = products.map((p, i) => {
+  const f = flips[i];
+  const mid = +(f.start + f.dur / 2).toFixed(3);
+  return `
+    tl.to("#leaf${i}", { rotateY: -180, duration: ${f.dur}, ease: "power2.inOut" }, ${f.start.toFixed(3)});
+    tl.to("#leaf${i} .shade", { opacity: 0.55, duration: ${(f.dur/2).toFixed(3)}, ease:"power1.in" }, ${f.start.toFixed(3)});
+    tl.to("#leaf${i} .shade", { opacity: 0, duration: ${(f.dur/2).toFixed(3)}, ease:"power1.out" }, ${mid});
+    tl.set("#leaf${i}", { zIndex: ${1000 + i} }, ${mid});${f.hero ? `
+    tl.to("#leaf${i+1 < N ? i+1 : i} .art", { scale: 1.04, duration: 0.5, ease:"power2.out" }, ${(f.start+f.dur).toFixed(3)});
+    tl.to("#leaf${i+1 < N ? i+1 : i} .art", { scale: 1.0, duration: 0.4, ease:"power2.in" }, ${(f.start+f.dur+0.5).toFixed(3)});` : ''}`;
+}).join('');
+
+const html = `<!doctype html>
+<html lang="en" data-resolution="${ratio}">
+<head>
+<meta charset="UTF-8" />
+<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
+<style>
+  :root { --ink:#1c1a17; --cream:#f4efe6; --paper:#fbf8f1; --gold:#b08d57; }
+  html,body { margin:0; padding:0; width:${W}px; height:${H}px; overflow:hidden;
+    background:radial-gradient(120% 120% at 50% 0%, #2a2622 0%, #14110e 70%);
+    font-family:"Helvetica Neue",system-ui,sans-serif; }
+  #main-composition { position:relative; width:${W}px; height:${H}px; overflow:hidden; }
+  .stage { position:absolute; inset:0; perspective:2600px; perspective-origin:50% 46%; }
+
+  /* left static page (the book's verso) */
+  .verso { position:absolute; top:${bookTop}px; left:${spineX - pageW}px; width:${pageW}px; height:${pageH}px;
+    background:var(--paper); border-radius:6px 2px 2px 6px;
+    box-shadow: inset -28px 0 44px rgba(0,0,0,.10), 0 30px 60px rgba(0,0,0,.45);
+    display:flex; align-items:center; justify-content:center; }
+  .verso .spinemark { font-family:Georgia, serif; color:#cbb48f;
+    writing-mode:vertical-rl; font-size:34px; letter-spacing:.28em; text-transform:uppercase; opacity:.6; }
+
+  /* stacked flipping leaves — pinned at the spine */
+  .leaf { position:absolute; top:${bookTop}px; left:${spineX}px; width:${pageW}px; height:${pageH}px;
+    transform-origin:left center; transform-style:preserve-3d; will-change:transform;
+    border-radius:2px 6px 6px 2px; }
+  .leaf .face { position:absolute; inset:0; backface-visibility:hidden; overflow:hidden;
+    border-radius:2px 6px 6px 2px; background:var(--paper);
+    box-shadow: 20px 26px 50px rgba(0,0,0,.40), inset 22px 0 40px rgba(0,0,0,.08); }
+  .leaf .front { }
+  .leaf .back { transform:rotateY(180deg); background:
+    linear-gradient(90deg,#efe9dc, #fbf8f1 22%);
+    box-shadow: -20px 26px 50px rgba(0,0,0,.35), inset -22px 0 40px rgba(0,0,0,.08); }
+  .leaf .art { position:absolute; left:0; top:0; width:100%; height:78%; object-fit:cover; }
+  .leaf .cap { position:absolute; left:0; right:0; bottom:0; height:22%; padding:0 34px;
+    display:flex; flex-direction:column; justify-content:center; background:var(--paper); }
+  .leaf .cap .pat { font-family:Georgia, serif; font-size:${Math.round(pageW*0.062)}px;
+    line-height:1.04; color:var(--ink); }
+  .leaf .cap .col { margin-top:8px; font-size:${Math.round(pageW*0.028)}px; letter-spacing:.22em;
+    text-transform:uppercase; color:var(--gold); }
+  .leaf .shade { position:absolute; inset:0; opacity:0; pointer-events:none;
+    background:linear-gradient(90deg, rgba(0,0,0,.42), rgba(0,0,0,0) 60%); }
+
+  /* cover + outro cards */
+  .card { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center;
+    text-align:center; color:var(--cream); }
+  .card .kicker { font-size:${Math.round(W*0.017)}px; letter-spacing:.44em; text-transform:uppercase; color:var(--gold); }
+  .card .big { font-family:Georgia, serif; font-size:${Math.round(W*0.072)}px; line-height:1.0; margin:22px 60px; }
+  .card .sub { font-size:${Math.round(W*0.019)}px; letter-spacing:.18em; text-transform:uppercase; color:#c9bfae; }
+  .card .rule { width:120px; height:2px; background:var(--gold); margin:34px 0; }
+  .card .url { margin-top:30px; font-size:${Math.round(W*0.017)}px; letter-spacing:.24em; text-transform:uppercase; color:var(--cream); }
+</style>
+</head>
+<body>
+  <div id="main-composition" data-composition-id="flipbook"
+       data-width="${W}" data-height="${H}" data-start="0" data-duration="${TOTAL}">
+
+    <!-- cover -->
+    <div class="card" id="cover">
+      <div class="kicker">Designer Wallcoverings presents</div>
+      <div class="big">${esc(title)}</div>
+      <div class="rule"></div>
+      <div class="sub">${esc(subtitle)}</div>
+    </div>
+
+    <div class="stage" id="stage">
+      <div class="verso"><div class="spinemark">${esc(title)}</div></div>
+      ${leaves}
+    </div>
+
+    <!-- outro -->
+    <div class="card" id="outro">
+      <div class="kicker">Shop the collection</div>
+      <div class="big">${esc(title)}</div>
+      <div class="url">designerwallcoverings.com</div>
+    </div>
+
+    <script>
+      window.__timelines = window.__timelines || {};
+      const tl = gsap.timeline({ paused: true });
+
+      // initial state — leaves stacked, page 0 on top of the right stack
+      ${products.map((p, i) => `gsap.set("#leaf${i}", { rotateY: 0, zIndex: ${N - i} });`).join('\n      ')}
+      gsap.set("#stage", { opacity: 0 });
+      gsap.set("#outro", { opacity: 0 });
+      gsap.set("#outro .big", { y: 36, opacity: 0 });
+      gsap.set("#outro .url", { opacity: 0 });
+      gsap.set("#cover .big", { y: 40, opacity: 0 });
+      gsap.set("#cover .kicker,#cover .sub,#cover .rule", { opacity: 0 });
+
+      // cover in
+      tl.to("#cover .kicker", { opacity: 1, duration: 0.5 }, 0.15);
+      tl.to("#cover .big", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 0.35);
+      tl.to("#cover .rule,#cover .sub", { opacity: 1, duration: 0.5 }, 0.95);
+      tl.to("#cover", { opacity: 0, duration: 0.5, ease: "power1.in" }, ${(INTRO-0.55).toFixed(2)});
+      tl.to("#stage", { opacity: 1, duration: 0.5, ease: "power1.out" }, ${(INTRO-0.5).toFixed(2)});
+
+      // page turns
+      ${tweens}
+
+      // outro
+      tl.to("#stage", { opacity: 0, duration: 0.5, ease: "power1.in" }, ${flipsEnd.toFixed(2)});
+      tl.to("#outro", { opacity: 1, duration: 0.5 }, ${(flipsEnd+0.1).toFixed(2)});
+      tl.to("#outro .big", { opacity: 1, y: 0, duration: 0.7, ease: "power2.out" }, ${(flipsEnd+0.3).toFixed(2)});
+      tl.to("#outro .url", { opacity: 1, duration: 0.5 }, ${(flipsEnd+0.8).toFixed(2)});
+
+      window.__timelines["flipbook"] = tl;
+    </script>
+  </div>
+</body>
+</html>`;
+
+fs.writeFileSync(`${wsDir}/index.html`, html);
+console.log(`  wrote ${wsDir}/index.html  (duration ${TOTAL}s, ${N} pages)`);
+console.log(`\nNext:\n  cd flipbooks/${slug} && npm run check && npm run render`);

← 8892eec auto-save: 2026-07-30T07:15:28 (2 files) — data/new-arrivals  ·  back to Dw Marketing Reels  ·  Graduate Collection flipbook: reusable generator + narrated 76e3f7b →