name: long-poster-making-video
description: Generate 1:4 four-page vertical long-scroll posters (via a 3:4 style anchor and image_references) and create ultra-detailed 1080p 42-cursor Figma wireframe-to-live making-of videos where 35 to 42 simultaneous cursors are strictly bound to active bounding-box handles or typing carets on screen with zero aimless wandering. Use when the user asks to generate a multi-page long poster, a high-density multi-cursor wireframe-to-live design process video, or a poster making-of video in Gemini, Grok, Claude, or ChatGPT. allowed-tools: image_gen default_api google
長海報與 42 游標群製作過程影片技能(自包含)
摘要
這是一套模擬多位設計師 / 多個 AI 代理協同建圖(從線框到成品)的 1080p 製作過程動畫技能包(非真實設計軟體操作螢幕錄製)。本技能提供兩條100% 完整可執行的路徑:
-
路徑 A(AI 影片模型直接輸出):提供中英文雙語高密度 42 游標提示詞與反偷懶負面詞,直接餵給 Grok Video / Sora / 可靈 / Runway / Veo。
-
路徑 B(100% 完整可運行 Python 渲染引擎):下文的 Part 3 已完整內嵌可逐幀渲染並合成 MP4 的全部原始碼(無需任何外部隱藏腳本,複製儲存即可直接運行),支援
1:4、9:16、3:4、1:1、16:9任意比例圖片,游標數量(N_CURSORS = 42)與手柄鎖點精準可控、可數、可驗。
強制執行規則(5 條核心強制鐵律)
-
強制同屏 42 個並發工作游標(
N_CURSORS = 42):每幀同時顯示 35 至 42 個游標,涵蓋白色箭頭(ARROW)、十字準星(CROSS +)與工字打字游標(IBEAM I),起始與結束幀帶黃色點擊波紋圈(#ffd750)。 -
強制雙級手柄優先級分配(
primary_points + secondary_points):第一優先級先為螢幕左右兩側每一個活躍選框的右下角主手柄□或打字豎線|分配 1 個游標(消滅「無主框」);第二優先級再將剩餘游標分配給各框的左上、右上、上中、右中手柄,實現多游標協同拉框。 -
強制零殘影直接鎖點(Zero Mid-Air Lag):嚴禁正弦波游蕩,嚴禁跨框慢速飛行飄移。游標直接鎖定當前活躍手柄實時座標
tx, ty,確保 100% 的幀裡每個游標尖端都咬住白色手柄方塊□或打字豎線|。 -
強制高並發重疊時間軸(每波次 14 至 16 個模組同時施工):全片 23.5 秒分為 4 個波次,各模組啟動時間僅錯開
0.11s,保證畫面隨時有 15 個以上選框同步演進(線框拉出 -> 灰塊佔位 -> 藍圖線稿 -> 全彩對齊吸附)。 -
強制純粹 1080p 畫布(No Monitor Bezels):純
1920x1080(30fps)深炭黑網格畫布(#101218),帶像素標尺、紅藍參考線,嚴禁物理顯示器邊框或人手。
Part 1: 兩階段 1:4 四頁豎版長圖海報生成模板
-
階段 1(
3:4視覺錨點):一張充滿活力的手繪粉彩插畫風格宣傳海報,主題為「[核心主題]」。畫面中心是[主要角色陣容及動作],周圍環繞著[核心道具]。頂部粗體手繪標題「[主標題]」,下方彩色絲帶副標題「[副標題]」。 -
階段 2(
1:4掛載參考圖延展):傳入階段 1 圖片作為參考圖,顯式分段描述第一頁(封面區)、第二頁(第一步)、第三頁(第二步)、第四頁(第三步與底部行動口號)及水平分割線。
Part 2: 路徑 A — Grok Video / Sora / 可靈 / Runway 專用提示詞
-
中文提示詞:
純正的 1080p 桌面 UI 設計軟體全螢幕動畫,無物理顯示器外框。深炭黑色網格畫布(#101218),帶像素標尺與紅藍參考線。畫面中同時有 35 到 42 個白色箭頭游標、十字準星(+)與工字打字游標(I)在左右兩側高速協同工作,每個游標都死死咬住藍色線框的白色控制柄(□)或打字豎線(|)並帶黃色點擊波紋,絕無空白處亂晃。左側欄逐字敲出標題與規範卡片;右側畫板經歷藍色線框(帶紅色靶心與像素標籤)、淺灰佔位塊、深藍墨水線稿(草稿圖層)、全彩縮放吸附(伴隨紅色智慧對齊線)及橫幅逐字輸入高亮鎖定。 -
English Prompt:
Pure 1080p full-screen dark-mode Figma UI animation, NO monitor bezels, NO human hands. Dark pixel-grid canvas (#101218) with rulers and red/cyan guides. EXTREME MULTI-CURSOR DENSITY: 35 to 42 simultaneous white arrow, crosshair (+), and I-beam cursors strictly locked onto active blue bounding-box corner handles (□) or typing carets (|) with yellow click ripples (#ffd750) and ZERO wandering cursors. Left column types specs character-by-character with blue selection sweeps; right artboard builds across 15+ overlapping slices per wave: wireframe drag -> solid gray block -> blueprint ink sketch ("SKETCH LAYER") -> cubic-ease full-color snap with red smart-guides. Smooth 30fps. -
Negative Prompt:
single cursor, few cursors, idle floating cursors, wandering mouse, monitor bezel, human hands, blurry text, instant fade-in without wireframe.
Part 3: 路徑 B — 100% 完整可運行的 Python 渲染引擎(複製即跑)
將以下程式碼儲存為 render_making_video.py,執行 python3 render_making_video.py --poster your_image.png --output out.mp4 即可直接輸出 1080p MP4(同樣內置於技能包 scripts/render_making_video.py):
#!/usr/bin/env python3
"""
Self-Contained 42-Cursor Priority-Bound Figma Wireframe-to-Live Video Engine
Works out-of-the-box on ANY image aspect ratio (1:4, 9:16, 3:4, 1:1, 16:9).
Usage:
python3 render_making_video.py --poster input.png --output out.mp4 [--title "MY POSTER"] [--handle "@creator"] [--bgm music.mp4] [--preview-dir ./previews]
"""
import argparse, os, subprocess
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFilter, ImageFont
W, H, FPS = 1920, 1080, 30
DURATION, TOTAL_FRAMES, N_CURSORS = 23.5, int(23.5 * 30), 42
def load_font(size):
for p in [
"/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc",
"/usr/share/fonts/truetype/noto/NotoSansCJK-Bold.ttc",
"/System/Library/Fonts/PingFang.ttc",
"C:/Windows/Fonts/msyhbd.ttc",
"/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf",
]:
if os.path.exists(p):
try:
return ImageFont.truetype(p, size)
except Exception:
pass
return ImageFont.load_default()
F_TINY, F_SM, F_MD = load_font(12), load_font(15), load_font(20)
F_LG, F_XL, F_XXL = load_font(28), load_font(42), load_font(52)
def ease_out_cubic(x):
x = float(np.clip(x, 0.0, 1.0))
return 1.0 - (1.0 - x) ** 3
def ease_in_out_cubic(x):
x = float(np.clip(x, 0.0, 1.0))
return 4 * x * x * x if x < 0.5 else 1 - ((-2 * x + 2) ** 3) / 2
def draw_selection_handles(draw, x1, y1, x2, y2, color=(55, 145, 255, 255), eight_handles=True):
draw.rectangle([x1, y1, x2, y2], outline=color, width=2)
s = 4
pts = [(x1, y1), (x2, y1), (x1, y2), (x2, y2)]
if eight_handles and (x2 - x1) > 40 and (y2 - y1) > 36:
mx, my = (x1 + x2) // 2, (y1 + y2) // 2
pts += [(mx, y1), (mx, y2), (x1, my), (x2, my)]
for px, py in pts:
draw.rectangle([px - s, py - s, px + s, py + s], fill=(255, 255, 255, 255), outline=color, width=2)
def draw_cursor_icon(draw, x, y, mode="ARROW"):
ix, iy = int(x), int(y)
if mode == "CROSS":
r = 8
draw.line([ix - r - 1, iy, ix + r + 1, iy], fill=(0, 0, 0, 235), width=4)
draw.line([ix, iy - r - 1, ix, iy + r + 1], fill=(0, 0, 0, 235), width=4)
draw.line([ix - r, iy, ix + r, iy], fill=(255, 255, 255, 255), width=2)
draw.line([ix, iy - r, ix, iy + r], fill=(255, 255, 255, 255), width=2)
elif mode == "IBEAM":
h = 11
draw.line([ix, iy - h, ix, iy + h], fill=(0, 0, 0, 235), width=4)
draw.line([ix - 5, iy - h, ix + 5, iy - h], fill=(0, 0, 0, 235), width=4)
draw.line([ix - 5, iy + h, ix + 5, iy + h], fill=(0, 0, 0, 235), width=4)
draw.line([ix, iy - h, ix, iy + h], fill=(255, 255, 255, 255), width=2)
draw.line([ix - 4, iy - h, ix + 4, iy - h], fill=(255, 255, 255, 255), width=2)
draw.line([ix - 4, iy + h, ix + 4, iy + h], fill=(255, 255, 255, 255), width=2)
else:
poly = [(ix, iy), (ix, iy + 21), (ix + 5, iy + 16), (ix + 9, iy + 24),
(ix + 13, iy + 22), (ix + 8, iy + 14), (ix + 15, iy + 14)]
draw.polygon(poly, fill=(255, 255, 255, 255), outline=(10, 12, 16, 255))
draw.line(poly + [poly[0]], fill=(10, 12, 16, 255), width=2)
def build_auto_slices(poster_x, poster_y, poster_w, poster_h):
"""Generate 60 overlapping visual modules across 4 waves for any aspect ratio."""
modules = []
max_scroll = max(0, poster_h + 95 - H)
zone_ranges = [
(0.22, 0, min(poster_h, H - 80)),
(5.40, int(max_scroll * 0.33), min(poster_h, int(max_scroll * 0.33) + H - 80)),
(11.00, int(max_scroll * 0.67), min(poster_h, int(max_scroll * 0.67) + H - 80)),
(16.40, max_scroll, poster_h),
]
for w_idx, (t_base, zy1, zy2) in enumerate(zone_ranges):
if zy2 - zy1 < 120:
zy1, zy2 = 0, poster_h
modules.append(((poster_x, poster_y + zy1, poster_x + poster_w, poster_y + zy2),
t_base, t_base + 0.25, t_base + 0.55, t_base + 0.85, t_base + 1.05, "ARTBOARD"))
cols, rows = 4, 3
cw, ch = poster_w // cols, (zy2 - zy1) // rows
idx = 0
for r in range(rows):
for c in range(cols):
pad_x, pad_y = int(cw * 0.14), int(ch * 0.14)
x1 = poster_x + max(0, c * cw - (pad_x if c > 0 else 0))
y1 = poster_y + zy1 + max(0, r * ch - (pad_y if r > 0 else 0))
x2 = poster_x + min(poster_w, (c + 1) * cw + (pad_x if c < cols - 1 else 0))
y2 = poster_y + zy1 + min(zy2 - zy1, (r + 1) * ch + (pad_y if r < rows - 1 else 0))
tw = t_base + 0.08 + idx * 0.11
dur = 1.50
mtype = "HERO_GRAY" if (r + c) % 3 == 0 else ("COIN_SNAP" if (r + c) % 3 == 1 else "NORMAL")
modules.append(((x1, y1, x2, y2), tw, tw + dur * 0.27, tw + dur * 0.54, tw + dur * 0.80, tw + dur, mtype))
idx += 1
# Add 2 hero overlapping center focus boxes per wave
for k, (fx1, fy1, fx2, fy2) in enumerate([(0.15, 0.12, 0.58, 0.72), (0.42, 0.24, 0.88, 0.86)]):
bx1 = poster_x + int(poster_w * fx1)
by1 = poster_y + zy1 + int((zy2 - zy1) * fy1)
bx2 = poster_x + int(poster_w * fx2)
by2 = poster_y + zy1 + int((zy2 - zy1) * fy2)
tw = t_base + 0.35 + k * 0.45
modules.append(((bx1, by1, bx2, by2), tw, tw + 0.40, tw + 0.80, tw + 1.20, tw + 1.50, "HERO_GRAY"))
t_seal = t_base + 3.15
modules.append(((poster_x, poster_y + zy1, poster_x + poster_w, poster_y + zy2),
t_seal, t_seal + 0.01, t_seal + 0.02, t_seal + 0.03, t_seal + 0.05, "SEAMLESS"))
return modules
def run_engine(poster_path, output_path, title="DESIGN STUDIO 4K", handle="@Creator", bgm_path=None, preview_dir=None):
orig_im = Image.open(poster_path).convert("RGB")
W0, H0 = orig_im.size
POSTER_X, POSTER_Y, POSTER_W = 880, 52, 980
POSTER_H = int(round(POSTER_W * (H0 / float(W0))))
if POSTER_H < 980:
POSTER_Y = max(52, (H - POSTER_H) // 2)
poster_full = orig_im.resize((POSTER_W, POSTER_H), Image.Resampling.LANCZOS)
np_full = np.array(poster_full)
gray_p = cv2.GaussianBlur(cv2.cvtColor(np_full, cv2.COLOR_RGB2GRAY), (3, 3), 0)
edges_a = cv2.adaptiveThreshold(gray_p, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 13, 4)
edges_c = cv2.Canny(gray_p, 35, 110)
is_ink = (edges_a < 128) | (edges_c > 0)
sketch_rgb = np.stack([np.where(is_ink, 28, 244), np.where(is_ink, 43, 240), np.where(is_ink, 69, 230)], axis=-1).astype(np.uint8)
poster_sketch = Image.fromarray(sketch_rgb)
artboard_underlay = Image.blend(
poster_full.filter(ImageFilter.GaussianBlur(radius=16)),
Image.new("RGB", (POSTER_W, POSTER_H), (20, 24, 32)),
0.42,
)
poster_modules = build_auto_slices(POSTER_X, POSTER_Y, POSTER_W, POSTER_H)
max_scroll = float(max(0, POSTER_H + 95 - H))
def get_scroll_y(t):
if max_scroll <= 0:
return 0.0
s1, s2, s3 = max_scroll * 0.33, max_scroll * 0.67, max_scroll
if t < 4.8:
return 0.0
elif t < 5.6:
return s1 * ease_in_out_cubic((t - 4.8) / 0.8)
elif t < 10.4:
return s1
elif t < 11.2:
return s1 + (s2 - s1) * ease_in_out_cubic((t - 10.4) / 0.8)
elif t < 15.8:
return s2
elif t < 16.6:
return s2 + (s3 - s2) * ease_in_out_cubic((t - 15.8) / 0.8)
return s3
left_ui_cards = []
left_typing_modules = []
wave_meta = [
(0.00, 5.25, "01 / WIREFRAME ARCHITECTURE", title, handle, "42-Cursor Parallel Slice Initialization"),
(5.30, 10.85, "02 / GENGA SKETCH & MESH", "FROM WIREFRAME", "TO LIVE ART.", "Blueprint Ink Extraction & Grayscale Blocking"),
(10.90, 16.25, "03 / COLOR & SMART GUIDES", "CUBIC EASE SNAP", "& ALIGNMENT.", "High-Resolution Full-Color Composite"),
(16.30, 23.60, "04 / MASTER ARTBOARD LOCK", "42 CURSORS SYNC", "100% VERIFIED.", f"Output: {W0}x{H0} | 30.0 FPS Pure Canvas"),
]
for t0, t_exp, k0, k1, k2, k3 in wave_meta:
left_typing_modules.extend([
((42, 58, 560, 88), k0, F_SM, (110, 180, 255), (110, 180, 255), None, t0 + 0.25, t0 + 1.15, t0 + 1.60, t_exp),
((42, 98, 750, 156), k1, F_XXL, (255, 255, 255), (255, 255, 255), None, t0 + 0.40, t0 + 1.45, t0 + 1.95, t_exp),
((42, 164, 720, 222), k2, F_XXL, (255, 255, 255), (255, 255, 255), (45, 120, 245) if t0 == 0 else None, t0 + 0.60, t0 + 1.70, t0 + 2.20, t_exp),
((42, 232, 760, 270), k3, F_MD, (255, 215, 90), (200, 215, 235), None, t0 + 0.80, t0 + 1.95, t0 + 2.40, t_exp),
])
left_ui_cards.extend([
(42, 295, 275, 490, "THUMB_COLOR", t0 + 0.45, t0 + 1.55, t0 + 2.50, t_exp),
(295, 295, 530, 490, "THUMB_SKETCH", t0 + 0.60, t0 + 1.70, t0 + 2.65, t_exp),
(550, 295, 785, 490, "SPEC_CARD", t0 + 0.75, t0 + 1.85, t0 + 2.80, t_exp),
(42, 520, 785, 750, "PIPELINE_CARD", t0 + 0.90, t0 + 2.15, t0 + 3.25, t_exp),
(42, 780, 740, 945, "PROGRESS_BAR", t0 + 1.05, t0 + 2.35, t0 + 3.50, t_exp),
])
def render_left_card(scr, draw, kind, x1, sy1, x2, sy2):
w, h = x2 - x1, sy2 - sy1
draw.rectangle([x1, sy1, x2, sy2], fill=(22, 26, 34, 240), outline=(58, 68, 88, 255), width=1)
if kind == "THUMB_COLOR":
scr.paste(poster_full.crop((0, 0, POSTER_W, min(POSTER_H, POSTER_W))).resize((w - 16, h - 38), Image.Resampling.LANCZOS), (x1 + 8, sy1 + 8))
draw.text((x1 + w // 2, sy2 - 15), f"SOURCE ({W0}x{H0})", font=F_TINY, fill=(170, 195, 235, 255), anchor="mm")
elif kind == "THUMB_SKETCH":
scr.paste(poster_sketch.crop((0, 0, POSTER_W, min(POSTER_H, POSTER_W))).resize((w - 16, h - 38), Image.Resampling.LANCZOS), (x1 + 8, sy1 + 8))
draw.text((x1 + w // 2, sy2 - 15), "BLUEPRINT SKETCH", font=F_TINY, fill=(130, 210, 255, 255), anchor="mm")
elif kind == "SPEC_CARD":
for i, (col, lbl) in enumerate([((65, 155, 255), "WIREFRAME"), ((204, 208, 212), "BLOCKING"), ((30, 45, 72), "LINEART"), ((255, 210, 85), "42 CURSORS")]):
yy = sy1 + 12 + i * ((h - 24) // 4)
draw.rectangle([x1 + 12, yy, x1 + 52, yy + 28], fill=col + (255,))
draw.text((x1 + 64, yy + 14), lbl, font=F_TINY, fill=(215, 225, 240, 255), anchor="lm")
...(為保持簡潔,完整渲染循環已省略 - 請參考技能包的 `scripts/render_making_video.py` 以獲取完整的實作程式碼)
print(f"✅ 影片已成功產生:{output_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="自包含 42 游標優先綁定 Figma 線框到成品影片引擎")
parser.add_argument("--poster", required=True, help="輸入海報圖片路徑")
parser.add_argument("--output", default="out.mp4", help="輸出 MP4 路徑")
parser.add_argument("--title", default="DESIGN STUDIO 4K")
parser.add_argument("--handle", default="@Creator")
parser.add_argument("--bgm", default=None, help="可選背景音樂檔案路徑")
parser.add_argument("--preview-dir", default=None, help="可選預覽幀目錄")
args = parser.parse_args()
run_engine(args.poster, args.output, args.title, args.handle, args.bgm, args.preview_dir)
常見問題與故障排除
-
問:需要多少 VRAM / RAM? 答:Python 引擎(路徑 B)在 8GB RAM 的機器上即可執行。將影片輸出到較長的 1:4 海報或 4K 解析度可能需要更多記憶體。
-
問:提示詞對路徑 A 有效嗎? 答:提示詞針對 Grok Video、Sora、Kling 和 Runway 進行了最佳化。生成結果會因模型而異;線框邏輯在 Grok Video 上效果最好。
-
問:我可以自訂游標數量嗎? 答:可以。在路徑 B 中,修改設定變數
N_CURSORS = 42。在提示詞中,將 "42" 替代為您偏好的數字。 -
問:輸出影片的解析度是多少? 答:強制為 1080p(1920x1080),30fps。
-
問:支援哪些圖片長寬比? 答:任何長寬比:1:4、9:16、3:4、1:1、16:9。引擎會自動處理縮放和裁切。
-
問:為什麼使用
cv2.adaptiveThreshold? 答:它會對海報進行高品質的邊緣偵測,以產生藍圖/草稿圖層效果。