fix:修复页面样式
19
Dockerfile
@@ -1,4 +1,9 @@
|
||||
FROM nvidia/cuda:12.1.1-runtime-ubuntu22.04 AS builder
|
||||
ARG NODE_BASE_IMAGE=docker.m.daocloud.io/library/node:20-bookworm-slim
|
||||
ARG CUDA_BASE_IMAGE=docker.m.daocloud.io/nvidia/cuda:12.1.1-runtime-ubuntu22.04
|
||||
|
||||
FROM ${NODE_BASE_IMAGE} AS node20
|
||||
|
||||
FROM ${CUDA_BASE_IMAGE} AS builder
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
@@ -11,18 +16,18 @@ ENV DEBIAN_FRONTEND=noninteractive \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Base deps + Python 3.10 + Node.js 20.x
|
||||
# Base deps + Python 3.10
|
||||
RUN sed -i 's|http://archive.ubuntu.com/ubuntu|https://mirrors.tuna.tsinghua.edu.cn/ubuntu|g; s|http://security.ubuntu.com/ubuntu|https://mirrors.tuna.tsinghua.edu.cn/ubuntu|g' /etc/apt/sources.list \
|
||||
&& apt-get -o Acquire::Retries=5 update \
|
||||
&& apt-get -o Acquire::Retries=5 install -y --no-install-recommends --fix-missing \
|
||||
ca-certificates curl gnupg \
|
||||
python3.10 python3.10-distutils python3-pip \
|
||||
ffmpeg fonts-dejavu-core \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||
&& apt-get -o Acquire::Retries=5 install -y --no-install-recommends --fix-missing nodejs \
|
||||
&& ln -sf /usr/bin/python3.10 /usr/local/bin/python \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=node20 /usr/local /usr/local
|
||||
|
||||
COPY requirements.txt /app/requirements.txt
|
||||
RUN python3.10 -m pip install -r /app/requirements.txt
|
||||
|
||||
@@ -31,7 +36,7 @@ RUN cd /app/server && npm ci --omit=dev
|
||||
|
||||
COPY . /app
|
||||
|
||||
FROM nvidia/cuda:12.1.1-runtime-ubuntu22.04 AS runtime
|
||||
FROM ${CUDA_BASE_IMAGE} AS runtime
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
@@ -50,11 +55,11 @@ RUN sed -i 's|http://archive.ubuntu.com/ubuntu|https://mirrors.tuna.tsinghua.edu
|
||||
ca-certificates \
|
||||
python3.10 python3.10-distutils python3-pip \
|
||||
ffmpeg fonts-dejavu-core \
|
||||
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
||||
&& apt-get -o Acquire::Retries=5 install -y --no-install-recommends --fix-missing nodejs \
|
||||
&& ln -sf /usr/bin/python3.10 /usr/local/bin/python \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=node20 /usr/local /usr/local
|
||||
|
||||
COPY --from=builder /usr/local/lib/python3.10 /usr/local/lib/python3.10
|
||||
COPY --from=builder /usr/local/bin /usr/local/bin
|
||||
COPY --from=builder /app /app
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- Output: a 3-scene narrated video `final_poc.mp4` (mock mode supported)
|
||||
|
||||
## Quick start (Docker)
|
||||
`docker compose up` includes a **ComfyUI** service (default image `jamesbrink/comfyui:latest` from Docker Hub). If you use another registry image, set `COMFYUI_IMAGE` in the environment.
|
||||
`docker compose up` includes a **ComfyUI** service (default through domestic mirror: `docker.1ms.run/ardenius/comfyui-cpu:latest`). If you use another registry image, set `COMFYUI_IMAGE` in the environment.
|
||||
|
||||
Build:
|
||||
|
||||
@@ -49,3 +49,4 @@ Open `http://127.0.0.1:3000` and click “运行” to see `main.py --script-onl
|
||||
- **apt**: TUNA Debian mirrors (baked into `Dockerfile`)
|
||||
- **pip**: `PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple`
|
||||
- **npm**: `NPM_CONFIG_REGISTRY=https://registry.npmmirror.com`
|
||||
- **docker images**: default base images now pull via `docker.m.daocloud.io` mirror
|
||||
|
||||
52
clone.html
Normal file
@@ -10,15 +10,17 @@ services:
|
||||
- PORT=3000
|
||||
volumes:
|
||||
- ./:/app
|
||||
# Keep dependencies inside container volume to avoid host FS read issues on macOS.
|
||||
- /app/server/node_modules
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
# Default: Docker Hub (anonymous pull). GHCR comfyanonymous image often returns "denied" without login.
|
||||
# Override: COMFYUI_IMAGE=ghcr.io/... after `docker login ghcr.io`
|
||||
# Default: use domestic mirror to speed up pulls in CN networks.
|
||||
# Override with COMFYUI_IMAGE to use another registry/image.
|
||||
comfyui:
|
||||
# CPU-friendly default image for non-NVIDIA development machines.
|
||||
# Override with COMFYUI_IMAGE to switch back to a GPU image.
|
||||
image: ${COMFYUI_IMAGE:-ardenius/comfyui-cpu:latest}
|
||||
image: ${COMFYUI_IMAGE:-docker.1ms.run/ardenius/comfyui-cpu:latest}
|
||||
# Force bind to all interfaces so other containers (and `check_comfy`) can reach it.
|
||||
# Works with the default ardenius/comfyui-cpu image layout (/ComfyUI-cpu/main.py).
|
||||
command: ${COMFYUI_COMMAND:-python3 /ComfyUI-cpu/main.py --cpu --cpu-vae --listen 0.0.0.0 --port 8188}
|
||||
|
||||
61
docs/studio_rearchitecture.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# AiVideo Studio 重构方案(V2)
|
||||
|
||||
## 目标
|
||||
- 实现与参考编辑器页面一致的工作台布局:顶部导航、中央预览舞台、底部时间线、右侧参数与日志面板。
|
||||
- 保留并强化现有能力:自动分镜、单镜头润色、渲染、阶段日志、任务跟踪。
|
||||
- 将前端代码从“流程散落”改造为“分层架构”,减少重复逻辑与状态不一致风险。
|
||||
|
||||
## 新架构
|
||||
|
||||
### 1. UI Shell 层
|
||||
- `TopNav`:品牌、快捷操作、Play/Render 入口。
|
||||
- `ToolBar`:上下文状态(task/mock)与工具位。
|
||||
- `PreviewStage`:展示当前 Scene 预览或 final video。
|
||||
- `TimelineStrip`:镜头缩略图时间线与进度条。
|
||||
- `SceneEditor`:单镜头编辑与润色入口。
|
||||
|
||||
### 2. 状态层(StudioState)
|
||||
- 统一使用 `useReducer` 管理工作台状态。
|
||||
- 核心状态:
|
||||
- `scenes`
|
||||
- `selectedSceneIndex`
|
||||
- `stageState`
|
||||
- `stageLogs`
|
||||
- `renderProgress`
|
||||
- `taskId`
|
||||
- `finalVideoUrl`
|
||||
- `toast`
|
||||
- 所有修改均通过 `dispatch(action)` 进入 reducer,避免多处 `useState` 导致的竞态和重复。
|
||||
|
||||
### 3. API/流处理层(StudioAPI)
|
||||
- `startScriptStream()`:EventSource 流式接收 Script 阶段事件。
|
||||
- `postStream()`:统一处理 Refine/Render 的 fetch + SSE 流。
|
||||
- `consumeFetchSSE()`:抽象 SSE 分块解析,消除重复解析代码。
|
||||
|
||||
### 4. 事件编排层
|
||||
- `onStageEvent(sourceStage, event, data)` 统一路由:
|
||||
- `task`
|
||||
- `stage_update`
|
||||
- `line`
|
||||
- `error`
|
||||
- `done`
|
||||
- `applyStageUpdate()` 负责阶段状态、进度、scene upsert 的单点更新。
|
||||
|
||||
## 数据流
|
||||
1. 用户修改 Prompt / Provider 参数。
|
||||
2. 自动防抖触发 `startScript()`,进入 Script SSE。
|
||||
3. `stage_update.scene_json` 持续更新 `scenes`,时间线和右侧编辑器同步刷新。
|
||||
4. 用户可对当前 Scene 进行编辑与 `refine`。
|
||||
5. 用户触发 `render`,进度与日志实时反馈,完成后挂载 final video URL。
|
||||
|
||||
## 兼容性说明
|
||||
- 继续使用 `babel-standalone@6`,所以 JSX 不使用 `<>...</>`,统一为 `React.Fragment`。
|
||||
- 保持现有后端接口契约不变:
|
||||
- `GET /api/script`
|
||||
- `POST /api/refine`
|
||||
- `POST /api/render`
|
||||
|
||||
## 后续建议
|
||||
- 将当前单文件页面拆分为真正多文件前端工程(Vite + React),引入 TypeScript 与单元测试。
|
||||
- 增加 Timeline 的拖拽排序与片段时长编辑。
|
||||
- 增加右侧“资产库”与“模板库”,进一步贴近参考产品完整体验。
|
||||
19
outputs/0c7eca55-8d10-4808-a5da-bd0b1247b4ed/scenes.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,城市夜景,霓虹灯,电影感",
|
||||
"video_motion": "缓慢推进镜头,轻微摇镜",
|
||||
"narration": "夜色温柔落在街灯上"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,咖啡店窗边,暖光,细雨",
|
||||
"video_motion": "侧向平移,人物轻轻抬头",
|
||||
"narration": "雨声里藏着一段回忆"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,桥上远景,车流光轨,温暖",
|
||||
"video_motion": "拉远全景,光轨流动",
|
||||
"narration": "我们在光里学会告别"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
19
outputs/2be794b9-5b7b-4769-b25b-b8f9539f786d/scenes.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,城市夜景,霓虹灯,电影感",
|
||||
"video_motion": "缓慢推进镜头,轻微摇镜",
|
||||
"narration": "夜色温柔落在街灯上"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,咖啡店窗边,暖光,细雨",
|
||||
"video_motion": "侧向平移,人物轻轻抬头",
|
||||
"narration": "雨声里藏着一段回忆"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,桥上远景,车流光轨,温暖",
|
||||
"video_motion": "拉远全景,光轨流动",
|
||||
"narration": "我们在光里学会告别"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
19
outputs/4f7d41b0-e28a-430a-9d86-dbde570388c3/scenes.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,城市夜景,霓虹灯,电影感",
|
||||
"video_motion": "缓慢推进镜头,轻微摇镜",
|
||||
"narration": "夜色温柔落在街灯上"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,咖啡店窗边,暖光,细雨",
|
||||
"video_motion": "侧向平移,人物轻轻抬头",
|
||||
"narration": "雨声里藏着一段回忆"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,桥上远景,车流光轨,温暖",
|
||||
"video_motion": "拉远全景,光轨流动",
|
||||
"narration": "我们在光里学会告别"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
19
outputs/617c1a3f-1c19-42d9-86c6-d121ae08f708/scenes.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,城市夜景,霓虹灯,电影感",
|
||||
"video_motion": "缓慢推进镜头,轻微摇镜",
|
||||
"narration": "夜色温柔落在街灯上"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,咖啡店窗边,暖光,细雨",
|
||||
"video_motion": "侧向平移,人物轻轻抬头",
|
||||
"narration": "雨声里藏着一段回忆"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,桥上远景,车流光轨,温暖",
|
||||
"video_motion": "拉远全景,光轨流动",
|
||||
"narration": "我们在光里学会告别"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
19
outputs/8853ac45-7c00-4ef8-a83c-603c4e14ddd8/scenes.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,城市夜景,霓虹灯,电影感",
|
||||
"video_motion": "缓慢推进镜头,轻微摇镜",
|
||||
"narration": "夜色温柔落在街灯上"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,咖啡店窗边,暖光,细雨",
|
||||
"video_motion": "侧向平移,人物轻轻抬头",
|
||||
"narration": "雨声里藏着一段回忆"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,桥上远景,车流光轨,温暖",
|
||||
"video_motion": "拉远全景,光轨流动",
|
||||
"narration": "我们在光里学会告别"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
19
outputs/a3396ccd-b7ec-48ad-b976-6991b45e4ebd/scenes.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,城市夜景,霓虹灯,电影感",
|
||||
"video_motion": "缓慢推进镜头,轻微摇镜",
|
||||
"narration": "夜色温柔落在街灯上"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,咖啡店窗边,暖光,细雨",
|
||||
"video_motion": "侧向平移,人物轻轻抬头",
|
||||
"narration": "雨声里藏着一段回忆"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,桥上远景,车流光轨,温暖",
|
||||
"video_motion": "拉远全景,光轨流动",
|
||||
"narration": "我们在光里学会告别"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
19
outputs/df867ed0-8d50-40e3-b839-f61cfb7439bd/scenes.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,城市夜景,霓虹灯,电影感",
|
||||
"video_motion": "缓慢推进镜头,轻微摇镜",
|
||||
"narration": "夜色温柔落在街灯上"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,咖啡店窗边,暖光,细雨",
|
||||
"video_motion": "侧向平移,人物轻轻抬头",
|
||||
"narration": "雨声里藏着一段回忆"
|
||||
},
|
||||
{
|
||||
"image_prompt": "写一个温暖的城市夜景故事\n\n\n[Global Constraints]\n- Global Style: 电影感\n请严格遵守上述全局信息,并保持三分镜主角一致。,桥上远景,车流光轨,温暖",
|
||||
"video_motion": "拉远全景,光轨流动",
|
||||
"narration": "我们在光里学会告别"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
373
prompt/v1.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# 3分钟短片分镜脚本(5秒/镜头)
|
||||
|
||||
## 基础设定
|
||||
- 总时长:180秒
|
||||
- 分镜数量:36个(每个5秒)
|
||||
- 叙事风格:军事写实 + 高压营救
|
||||
- 画幅建议:2.39:1,24fps
|
||||
- 色调建议:
|
||||
- 战前与巡航:冷蓝灰
|
||||
- 被击落与搜捕:黄沙+火光高反差
|
||||
- 夜间营救:深蓝+红色告警光
|
||||
|
||||
## 角色映射(拟人化动物代号)
|
||||
- 美国:鹰酱
|
||||
- 伊朗:波猫
|
||||
- 以色列:乌贼(本片仅作为电台背景提及,不正面出场)
|
||||
- 中国:熊猫(新闻墙背景信息)
|
||||
- 俄罗斯:棕熊(新闻墙背景信息)
|
||||
- 印度:白象(新闻墙背景信息)
|
||||
- 法国:高卢鸡(新闻墙背景信息)
|
||||
- 英国:约翰牛(新闻墙背景信息)
|
||||
|
||||
## 身份与语言锁定(必须严格保持)
|
||||
- 人物国籍/身份:
|
||||
- `Falcon-1`、`Falcon-2`、Rescue机组、鹰酱指挥链:美国人(American)。
|
||||
- 波猫地面部队、波猫指挥员、波猫电台:波斯人(Persian / Iranian)。
|
||||
- 语种使用:
|
||||
- 鹰酱侧人物对白与无线电:英语(English)。
|
||||
- 波猫侧人物对白与无线电:波斯语(Persian / Farsi)。
|
||||
- 旁白可保留中文版本用于成片叙事;若做国际版,旁白统一英语。
|
||||
- 字幕与播报规范:
|
||||
- 对白保持原语种发声,不要“角色直接说中文”。
|
||||
- 成片字幕建议双语:中文主字幕 + 英文副字幕;波斯语台词保留音译或意译其一并全片统一。
|
||||
- 无线电口令优先使用军事短句,避免口语化长句。
|
||||
|
||||
## 连续性规则(后续生成必须严格保持)
|
||||
- 飞行员共2名:
|
||||
- 1号飞行员“Falcon-1”:橙色应急信标、右臂擦伤。
|
||||
- 2号飞行员“Falcon-2”:绿色应急信标、左腿轻伤。
|
||||
- 被击落战机:鹰酱双机编队,共2架,均在山地荒漠区坠毁。
|
||||
- 营救空中力量:
|
||||
- 黑鹰直升机2架(代号 Rescue-1、Rescue-2)
|
||||
- 加油机1架(代号 Shell-6)
|
||||
- 护航战机若干(不固定数量,远景表现)
|
||||
- 结局战损必须出现:
|
||||
- 1架运输机被炸毁
|
||||
- 2架直升机被炸毁(对应 Rescue-1 与 Rescue-2)
|
||||
- 主结局必须保留:两名飞行员均被成功救出。
|
||||
|
||||
## 人物形象一致性圣经(必须锁定)
|
||||
- `Falcon-1`(橙标):
|
||||
- 识别锚点:头盔左侧白色短划痕、右臂外侧止血贴、橙色频闪信标固定在胸挂左下。
|
||||
- 动作特征:右臂发力受限,举枪与攀爬时明显护臂动作。
|
||||
- 台词状态:语速偏稳、短句下达信息。
|
||||
- `Falcon-2`(绿标):
|
||||
- 识别锚点:头盔后缘绿色反光贴、左腿膝下弹性绷带、绿色频闪信标固定在腰后。
|
||||
- 动作特征:落地后全程轻度跛行,冲刺时左腿拖步。
|
||||
- 台词状态:呼吸更急,句尾常有停顿。
|
||||
- 拟人化呈现边界:
|
||||
- 仅保留“代号化动物身份”语义,不使用夸张兽化比例。
|
||||
- 面部与体型遵循真人军事题材比例,装备佩戴方式符合实战逻辑。
|
||||
- 不出现卡通眼神、夸张毛发、Q版肢体。
|
||||
- 全员装备佩戴统一:
|
||||
- 同一角色的头盔编号、护目镜款式、战术背心挂载位置在全片不改变。
|
||||
- 血迹、划伤、灰尘只增不减,不能在后续镜头“突然变干净”。
|
||||
|
||||
## 武器与装备真实性基线(建议锁定)
|
||||
- 鹰酱舰载打击机:`F/A-18E/F` 双机编队(对应镜头02-07)。
|
||||
- 营救直升机:`UH-60` 级别中型通用直升机(Rescue-1 / Rescue-2),侧门机枪位清晰可见。
|
||||
- 空中加油机:`KC-46/KC-135` 级别(Shell-6),受油阶段以软管锥套或硬管受油呈现,不出现“接驳火花”。
|
||||
- 运输机:`C-130` 级别战术运输机(镜头25、28、29)。
|
||||
- 波猫地面防空:
|
||||
- 中程防空系统(雷达车 + 发射车)负责初次击落。
|
||||
- 末段近程威胁以重机枪 + 便携防空导弹(MANPADS)为主。
|
||||
- 弹药与火力效果写实化:
|
||||
- 曳光弹比例控制在“数发可见”,避免整条激光束观感。
|
||||
- 近炸与破片效果优先,减少夸张球形大火团。
|
||||
- 爆炸后要有二次碎片与烟尘延迟,不要“一炸即净空”。
|
||||
|
||||
## 分镜脚本(36镜头)
|
||||
|
||||
### 镜头01(00:00-00:05)
|
||||
- 画面:高空俯瞰,波猫领地城市边缘被连续轰炸,冲击波掀起尘墙。
|
||||
- 机位/运动:无人机式广角,缓慢前推。
|
||||
- 关键元素:夜色未尽,地表火点连成线,防空探照灯扫空。
|
||||
- 音效:低沉爆炸滚雷,远处防空警报。
|
||||
- 台词/旁白:旁白「战争进入第七夜,鹰酱的空袭仍在继续。」
|
||||
|
||||
### 镜头02(00:05-00:10)
|
||||
- 画面:鹰酱航母甲板,2架F/A-18E/F挂弹弹射起飞,蒸汽与尾焰交叠。
|
||||
- 机位/运动:低机位仰拍,快速摇镜跟随起飞。
|
||||
- 关键元素:甲板人员手势指挥、夜航灯闪烁。
|
||||
- 音效:喷气轰鸣、甲板指令哨音。
|
||||
- 台词/旁白:无线电「Viper编队,进入打击航线。」
|
||||
|
||||
### 镜头03(00:10-00:15)
|
||||
- 画面:双机编队穿过云层,HUD叠加锁定地面目标。
|
||||
- 机位/运动:座舱第一视角与外景切换。
|
||||
- 关键元素:导弹挂架细节、雷达波纹扫描。
|
||||
- 音效:电子告警“滴滴”,呼吸声。
|
||||
- 台词/旁白:Falcon-1「目标区在前,保持队形。」
|
||||
|
||||
### 镜头04(00:15-00:20)
|
||||
- 画面:波猫山地防空阵地启动,雷达车转入跟踪,导弹发射车舱盖弹开。
|
||||
- 机位/运动:地面中景,手持震动感。
|
||||
- 关键元素:士兵奔跑装填,红外追踪镜头特写。
|
||||
- 音效:机械液压声、点火咆哮。
|
||||
- 台词/旁白:波猫指挥员「锁定高空双目标,发射!」
|
||||
|
||||
### 镜头05(00:20-00:25)
|
||||
- 画面:一枚防空导弹破云而出,拖着白色尾迹直扑编队。
|
||||
- 机位/运动:导弹追踪镜头,高速推进。
|
||||
- 关键元素:云层被撕开,导弹尾焰占满画面。
|
||||
- 音效:尖啸上扬,心跳加重。
|
||||
- 台词/旁白:Falcon-2「警报!导弹来袭!」
|
||||
|
||||
### 镜头06(00:25-00:30)
|
||||
- 画面:第一架战机被命中,机翼断裂起火,飞行员弹射。
|
||||
- 机位/运动:慢动作+快速拉远。
|
||||
- 关键元素:火球碎片雨、橙色降落伞打开、Falcon-1头盔左侧白色划痕可辨。
|
||||
- 音效:爆裂巨响后瞬间闷音。
|
||||
- 台词/旁白:Falcon-1「我中弹了,弹射!」
|
||||
|
||||
### 镜头07(00:30-00:35)
|
||||
- 画面:第二架战机规避失败,在山脊后方爆炸,第二名飞行员跳伞。
|
||||
- 机位/运动:远景长焦,爆炸后切近景。
|
||||
- 关键元素:绿色信标闪烁,黑烟柱升空,Falcon-2左腿落地姿态明显受伤。
|
||||
- 音效:山谷回响爆炸、碎片落地声。
|
||||
- 台词/旁白:Falcon-2「我也跳伞了,落点偏东!」
|
||||
|
||||
### 镜头08(00:35-00:40)
|
||||
- 画面:两名飞行员分别落入荒漠沟壑,迅速解伞隐蔽。
|
||||
- 机位/运动:俯拍切地面跟拍。
|
||||
- 关键元素:Falcon-1右臂流血并贴止血贴,Falcon-2左腿跛行前进,信标颜色不可互换。
|
||||
- 音效:风沙呼啸,急促喘息。
|
||||
- 台词/旁白:旁白「两人坠入波猫腹地,距离最近友军超过百公里。」
|
||||
|
||||
### 镜头09(00:40-00:45)
|
||||
- 画面:Falcon-1开启橙色应急信标,贴地发报。
|
||||
- 机位/运动:特写手部操作,微距切换。
|
||||
- 关键元素:终端屏幕坐标跳动:Grid K-27。
|
||||
- 音效:加密电台短促脉冲声。
|
||||
- 台词/旁白:Falcon-1「Mayday,坐标K-27,等待回收。」
|
||||
|
||||
### 镜头10(00:45-00:50)
|
||||
- 画面:Falcon-2在岩缝内发送绿色信标,标记L-31。
|
||||
- 机位/运动:肩扛镜头,压迫感近景。
|
||||
- 关键元素:夜视模式闪现,腿部绑带止血。
|
||||
- 音效:远处履带车轰鸣渐近。
|
||||
- 台词/旁白:Falcon-2「L-31,敌巡逻接近,快。」
|
||||
|
||||
### 镜头11(00:50-00:55)
|
||||
- 画面:鹰酱前线基地作战室,大屏锁定两个信标点。
|
||||
- 机位/运动:环绕镜头扫过指挥台。
|
||||
- 关键元素:地图上红蓝箭头交错,倒计时启动。
|
||||
- 音效:键盘急击,警铃短鸣。
|
||||
- 台词/旁白:指挥官「启动CSAR,黑鹰立即起飞。」
|
||||
|
||||
### 镜头12(00:55-01:00)
|
||||
- 画面:黑鹰Rescue-1与Rescue-2低空起飞,加油机Shell-6升空。
|
||||
- 机位/运动:侧向跟拍,旋翼掠过镜头。
|
||||
- 关键元素:机腹绞盘、双侧机枪位、夜航识别灯、机身战术编号清晰。
|
||||
- 音效:旋翼重拍,地勤呼喊。
|
||||
- 台词/旁白:无线电「Rescue编队离场,航线A-9。」
|
||||
|
||||
### 镜头13(01:00-01:05)
|
||||
- 画面:空中加油,护航机与加油机在云海上方并行。
|
||||
- 机位/运动:远景稳定镜头后推进到受油管连接点。
|
||||
- 关键元素:受油管锥套轻微摆动后稳定咬合,无异常火花。
|
||||
- 音效:稳定低频引擎噪音。
|
||||
- 台词/旁白:Shell-6「油量窗口三分钟,动作快。」
|
||||
|
||||
### 镜头14(01:05-01:10)
|
||||
- 画面:波猫地面部队成网状推进,热成像无人机升空搜捕。
|
||||
- 机位/运动:高空俯拍+热成像视角切换。
|
||||
- 关键元素:车灯组成搜索弧线,士兵犬队前导。
|
||||
- 音效:引擎轰鸣、犬吠、短波口令。
|
||||
- 台词/旁白:波猫电台「封锁K-27到L-31,全线搜索。」
|
||||
|
||||
### 镜头15(01:10-01:15)
|
||||
- 画面:Falcon-1躲在废弃输油管下,抬头望见搜索无人机掠过。
|
||||
- 机位/运动:主观视角仰拍,镜头轻颤。
|
||||
- 关键元素:尘土落在面罩,橙色信标被紧急关闭。
|
||||
- 音效:无人机电机嗡鸣从近到远。
|
||||
- 台词/旁白:Falcon-1(低声)「再晚十分钟我就暴露了。」
|
||||
|
||||
### 镜头16(01:15-01:20)
|
||||
- 画面:Falcon-2在峡谷底打出红外闪码,远处有敌军灯柱扫来。
|
||||
- 机位/运动:长焦压缩景深,红外闪码特写。
|
||||
- 关键元素:膝盖血迹、沙地拖拽痕。
|
||||
- 音效:高频电报码、远处喊话回声。
|
||||
- 台词/旁白:Falcon-2「我能听见他们,快点。」
|
||||
|
||||
### 镜头17(01:20-01:25)
|
||||
- 画面:黑鹰编队贴地穿越山谷,规避雷达,机枪手戒备。
|
||||
- 机位/运动:直升机舱门外侧跟拍,快速掠地。
|
||||
- 关键元素:旋翼扬沙,地形匹配航迹投影。
|
||||
- 音效:旋翼轰鸣压迫感增强。
|
||||
- 台词/旁白:机组长「保持无线静默,距目标12公里。」
|
||||
|
||||
### 镜头18(01:25-01:30)
|
||||
- 画面:鹰酱空中分队反复盘旋搜寻,终于双点位重合确认。
|
||||
- 机位/运动:战术地图与夜空外景交叉剪辑。
|
||||
- 关键元素:K-27与L-31连线形成回收走廊。
|
||||
- 音效:系统提示音“Target Confirmed”。
|
||||
- 台词/旁白:指挥官「位置确认,执行双点同步回收。」
|
||||
|
||||
### 镜头19(01:30-01:35)
|
||||
- 画面:Rescue-1悬停K-27上空,绞盘索下降。
|
||||
- 机位/运动:俯冲到近景,绞盘视角向下看。
|
||||
- 关键元素:地面火光反射在机腹,Falcon-1挥荧光棒。
|
||||
- 音效:钢索摩擦声、机枪上膛声。
|
||||
- 台词/旁白:救援员「看到你了,接索!」
|
||||
|
||||
### 镜头20(01:35-01:40)
|
||||
- 画面:波猫地面火力突然开火,曳光弹扫向黑鹰。
|
||||
- 机位/运动:地面对空仰拍,快速抖动。
|
||||
- 关键元素:重机枪阵地压制、MANPADS射手完成瞄准准备。
|
||||
- 音效:密集枪声、金属击穿声。
|
||||
- 台词/旁白:波猫士兵「压住它!别让它降!」
|
||||
|
||||
### 镜头21(01:40-01:45)
|
||||
- 画面:护航机俯冲压制,投下制导炸弹清除火力点。
|
||||
- 机位/运动:高速俯冲镜头切地爆炸全景。
|
||||
- 关键元素:先精确命中火力核心点,再出现破片与次生爆炸扩散。
|
||||
- 音效:破空尖啸后巨响。
|
||||
- 台词/旁白:护航飞行员「地面威胁压制中!」
|
||||
|
||||
### 镜头22(01:45-01:50)
|
||||
- 画面:Rescue-2靠近L-31,准备接Falcon-2,地面车队逼近。
|
||||
- 机位/运动:机舱内向外拍,远处车灯快速放大。
|
||||
- 关键元素:Falcon-2拖伤腿冲刺,绿色信标闪烁。
|
||||
- 音效:引擎轰鸣、队员喊口令。
|
||||
- 台词/旁白:救援员「跑!再十米!」
|
||||
|
||||
### 镜头23(01:50-01:55)
|
||||
- 画面:一枚肩射导弹命中Rescue-1尾梁,直升机失控。
|
||||
- 机位/运动:慢动作表现中弹点,然后急速旋转坠落。
|
||||
- 关键元素:尾桨碎裂,液压失效导致偏航失控,火星与碎片洒落。
|
||||
- 音效:告警蜂鸣连续拉满。
|
||||
- 台词/旁白:机组长「我们中弹,迫降失败!」
|
||||
|
||||
### 镜头24(01:55-02:00)
|
||||
- 画面:Rescue-1撞上山坡爆炸,火球照亮峡谷。
|
||||
- 机位/运动:远景定镜,冲击波推沙而来。
|
||||
- 关键元素:残骸燃烧,弹药殉爆二次闪光。
|
||||
- 音效:爆炸闷响叠加耳鸣效果。
|
||||
- 台词/旁白:旁白「第一架黑鹰坠毁,回收窗口骤然收缩。」
|
||||
|
||||
### 镜头25(02:00-02:05)
|
||||
- 画面:地面快速反应队由运输机空投到临时降落区。
|
||||
- 机位/运动:机腹舱门外拍,队员索降。
|
||||
- 关键元素:C-130级运输机低空掠过,红色舱灯明灭,队员按序离机。
|
||||
- 音效:风噪剧烈,索降扣具碰撞。
|
||||
- 台词/旁白:指挥官「地面队接管,强行打通撤离点。」
|
||||
|
||||
### 镜头26(02:05-02:10)
|
||||
- 画面:Falcon-1被拉上Rescue-2,救援员给右臂注射止痛剂。
|
||||
- 机位/运动:机舱手持近景,节奏急促。
|
||||
- 关键元素:橙色信标熄灭,血迹染红手套。
|
||||
- 音效:呼喊、弹壳落舱声。
|
||||
- 台词/旁白:Falcon-1「还有一个人,别丢下他!」
|
||||
|
||||
### 镜头27(02:10-02:15)
|
||||
- 画面:Falcon-2与地面队汇合,巷战式近距离交火爆发。
|
||||
- 机位/运动:平视跟跑镜头,快速切换掩体点。
|
||||
- 关键元素:废墟掩体崩裂、火花四溅、Falcon-2左腿拖步清晰。
|
||||
- 音效:突击步枪点射,手雷爆炸。
|
||||
- 台词/旁白:队长「烟幕弹!掩护伤员后撤!」
|
||||
|
||||
### 镜头28(02:15-02:20)
|
||||
- 画面:运输机准备二次接应时被便携防空导弹命中右翼油箱。
|
||||
- 机位/运动:中远景追拍,命中瞬间闪白。
|
||||
- 关键元素:右侧机翼根部命中起火,燃油泄漏后拖尾燃烧。
|
||||
- 音效:巨大爆鸣,电流噼啪。
|
||||
- 台词/旁白:无线电「运输机中弹!重复,中弹!」
|
||||
|
||||
### 镜头29(02:20-02:25)
|
||||
- 画面:运输机坠地爆炸,火焰蘑菇云升起。
|
||||
- 机位/运动:超远景静镜,地平线被火光吞没。
|
||||
- 关键元素:冲击波掀翻附近车辆。
|
||||
- 音效:低频冲击后环境声短暂真空。
|
||||
- 台词/旁白:旁白「运输机被摧毁,撤离计划只剩最后通道。」
|
||||
|
||||
### 镜头30(02:25-02:30)
|
||||
- 画面:Rescue-2超低空穿插,试图带走Falcon-2与地面队。
|
||||
- 机位/运动:机头视角穿越电线塔与峡谷拐点。
|
||||
- 关键元素:曳光弹擦过机身,机体多处中弹,告警面板出现尾传动异常。
|
||||
- 音效:金属撞击、告警语音不断。
|
||||
- 台词/旁白:飞行员「坚持住,最后一次进场!」
|
||||
|
||||
### 镜头31(02:30-02:35)
|
||||
- 画面:第二枚导弹命中Rescue-2腹部,直升机带火硬着陆后爆炸。
|
||||
- 机位/运动:侧后方跟拍到撞地翻滚。
|
||||
- 关键元素:主旋翼断裂飞散,机舱门被炸飞,机体翻滚后二次殉爆。
|
||||
- 音效:连续爆炸、旋翼断裂尖啸。
|
||||
- 台词/旁白:旁白「第二架黑鹰也被击毁。」
|
||||
|
||||
### 镜头32(02:35-02:40)
|
||||
- 画面:幸存救援员与两名飞行员冲入废墟掩体,近距离枪战白热化。
|
||||
- 机位/运动:手持近景,跟随冲刺与卧倒。
|
||||
- 关键元素:子弹打碎混凝土,火星与粉尘充满画面。
|
||||
- 音效:枪声密集、耳麦里杂音尖叫。
|
||||
- 台词/旁白:队长「全员向北侧缺口突围!」
|
||||
|
||||
### 镜头33(02:40-02:45)
|
||||
- 画面:护航战机再度空袭,炸开北侧封锁线,制造撤离窗口。
|
||||
- 机位/运动:空地交叉剪,先空中俯冲再地面仰视。
|
||||
- 关键元素:封锁阵地连环爆破,烟尘墙形成遮蔽。
|
||||
- 音效:炸弹连响、无线电倒计时。
|
||||
- 台词/旁白:护航飞行员「北线已开,窗口60秒!」
|
||||
|
||||
### 镜头34(02:45-02:50)
|
||||
- 画面:备用撤离直升机(无编号)从烟幕中突入,救援员推送两名飞行员登机。
|
||||
- 机位/运动:地面仰拍到机舱内反打。
|
||||
- 关键元素:Falcon-2被拖上机舱时左腿包扎仍在,Falcon-1右臂受限下短点射掩护。
|
||||
- 音效:旋翼压制一切环境声,喊话靠吼。
|
||||
- 台词/旁白:救援员「人齐了!起飞!」
|
||||
|
||||
### 镜头35(02:50-02:55)
|
||||
- 画面:直升机拉升脱离火网,地面仍有零星追击火力。
|
||||
- 机位/运动:后向追踪镜头,地面火线逐渐变小。
|
||||
- 关键元素:机舱内两名飞行员并排固定担架,医护紧急处理。
|
||||
- 音效:呼吸机、心率监测滴答声混合旋翼声。
|
||||
- 台词/旁白:Falcon-2(虚弱)「我们……还活着吗?」
|
||||
|
||||
### 镜头36(02:55-03:00)
|
||||
- 画面:黎明前天际线,撤离机飞向海面方向;地面远处仍燃着三处残骸火点(运输机+两架黑鹰)。
|
||||
- 机位/运动:超远景缓慢拉远,最后定格。
|
||||
- 关键元素:火光映出战场轮廓,字幕淡入“救援成功,代价惨重”。
|
||||
- 音效:音乐转低沉弦乐,枪声远去。
|
||||
- 台词/旁白:旁白「两名飞行员获救,但这一夜,没人真正获胜。」
|
||||
|
||||
## 统一画面生成约束(给AI视频模型)
|
||||
- 风格关键词:`cinematic war realism, high detail, volumetric smoke, dramatic lighting, handheld tension, tactical HUD overlay, desert canyon battlefield`
|
||||
- 画质关键词:`4k, ultra-detailed, film grain, motion blur, depth of field`
|
||||
- 禁止项:`no cartoon style, no cute style, no exaggerated proportions, no text watermark, no logo`
|
||||
- 人物一致性:两名飞行员伤情与信标颜色在全片保持一致,不可互换。
|
||||
- 物件一致性:黑鹰涂装、运输机编号风格、波猫地面车辆迷彩在跨镜头保持一致。
|
||||
- 时间连续性:夜间到拂晓过渡,光线需逐步变化,不可突变白天。
|
||||
- 连续伤痕规则:血迹扩散、灰尘堆积、装备磨损按时间递增,不可“重置”。
|
||||
- 镜头语言约束:爆炸不过曝、枪口焰不过度拉长、烟尘保留体积光层次。
|
||||
- 语种一致性:鹰酱侧仅英语、波猫侧仅波斯语;不得跨阵营混用口语。
|
||||
|
||||
## 音频后期建议
|
||||
- BGM三段式:
|
||||
- 00:00-01:00:低频压迫 + 战争环境声主导
|
||||
- 01:00-02:30:节奏加速、打击乐增强
|
||||
- 02:30-03:00:弦乐收束、留白
|
||||
- 枪炮声做空间方位:左/右声道随机位变化,增强临场感。
|
||||
- 关键对白建议保留无线电失真,提升军事纪实感。
|
||||
- 语言音色区分:英语通话保持北美军用电台质感;波斯语通话保持短波压缩感与环境底噪。
|
||||
|
||||
## 声音与特效细节刻画清单(执行版)
|
||||
- 声音分轨建议(至少8轨):
|
||||
- `DX`:角色对白/无线电(300Hz以下滚降,加入轻微带限失真)。
|
||||
- `FX-GUN`:枪声与抛壳(近景强调机械复进声,远景以混响尾音为主)。
|
||||
- `FX-EXP`:爆炸与破片(分“初爆/碎片/回响”三层,避免单层大轰鸣)。
|
||||
- `FX-AIR`:固定翼与旋翼(区分掠过、悬停、远离三种多普勒曲线)。
|
||||
- `FX-FOLEY`:脚步、布料、挂具碰撞、拖拽声。
|
||||
- `AMB-DAYNIGHT`:风沙/城市远噪/战场底噪,按夜到黎明逐步抬高高频空气感。
|
||||
- `UI`:HUD提示、告警蜂鸣、心率仪。
|
||||
- `MUS`:三段式BGM。
|
||||
- 关键时间点声音重心:
|
||||
- `00:20-00:35`(击落段):导弹尖啸由右后声像切入,命中瞬间做0.2-0.4秒闷听觉模拟。
|
||||
- `01:30-02:00`(首轮回收段):旋翼低频与地面曳光弹破空声交替压制,对白仅保留关键词。
|
||||
- `02:15-02:35`(连环战损段):运输机爆炸与Rescue-2坠毁分开设计频段,避免低频互相遮蔽。
|
||||
- `02:45-03:00`(撤离段):枪声快速衰减到远景,心率监测与呼吸机接管听觉焦点。
|
||||
- 特效(VFX)颗粒度要求:
|
||||
- 火焰颜色分层:近白芯 + 橙黄主体 + 黑烟边缘,不使用纯色“贴图火”。
|
||||
- 破片运动遵循抛物线与空气阻力,远小近大,禁止匀速直线飞散。
|
||||
- 曳光弹亮度受烟尘遮挡衰减,不可全程同亮。
|
||||
- 夜战镜头保留暗部细节,避免“黑成一片”或“亮如白天”。
|
||||
@@ -23,6 +23,7 @@ app.use(
|
||||
},
|
||||
})
|
||||
);
|
||||
app.use("/assets", express.static(path.join(repoRoot, "assets")));
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
app.get("/api/health", (_req, res) => {
|
||||
@@ -475,4 +476,3 @@ const port = Number(process.env.PORT || 3000);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||