- 10 个页面 (工作台/项目/商品/流水线/资产/账户/创建向导) - V2.1 Restraint 设计规范 (冷灰底 + #FA5D19 + 8px 圆角) - 完整 design-system.html 组件库参考 - SVG line icon · stroke 1.5 全合规 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
785 lines
52 KiB
HTML
785 lines
52 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>补水面膜 · v3 · 流水线 · 流·Studio</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="assets/restraint.css">
|
||
<style>
|
||
/* ─── Project header ─── */
|
||
.proj-head { display: flex; justify-content: space-between; gap: 16px; margin-bottom: 22px; align-items: flex-start; }
|
||
.proj-head h1 { font-size: 20px; font-weight: 700; letter-spacing: -.012em; }
|
||
|
||
/* ─── Stepper ─── */
|
||
.stepper { display: flex; align-items: center; gap: 0; margin-bottom: 28px; padding: 14px 18px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); position: relative; }
|
||
.stepper::before, .stepper::after { content: ''; position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||
.stepper::before { top: -7px; left: -7px; }
|
||
.stepper::after { bottom: -7px; right: -7px; }
|
||
.stepper .corner-tr, .stepper .corner-bl { position: absolute; width: 14px; height: 14px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 21' fill='%23e8e8e8'%3E%3Cpath d='M10.5 4C10.5 7.31371 7.81371 10 4.5 10H0.5V11H4.5C7.81371 11 10.5 13.6863 10.5 17V21H11.5V17C11.5 13.6863 14.1863 11 17.5 11H21.5V10H17.5C14.1863 10 11.5 7.31371 11.5 4V0H10.5V4Z'/%3E%3C/svg%3E") no-repeat center; background-size: contain; pointer-events: none; }
|
||
.stepper .corner-tr { top: -7px; right: -7px; }
|
||
.stepper .corner-bl { bottom: -7px; left: -7px; }
|
||
.stage-step { display: flex; align-items: center; gap: 10px; padding: 6px 0; cursor: pointer; user-select: none; }
|
||
.stage-step .num { width: 26px; height: 26px; display: grid; place-items: center; font-family: var(--font-mono); font-size: 12px; font-weight: 600; border: 1px solid var(--border-faint); border-radius: var(--r-sm); background: var(--surface); color: var(--black-alpha-48); flex-shrink: 0; }
|
||
.stage-step.done .num { background: var(--accent-black); border-color: var(--accent-black); color: var(--accent-white); }
|
||
.stage-step.active .num { background: var(--heat); border-color: var(--heat); color: var(--accent-white); }
|
||
.stage-step.locked { opacity: .5; cursor: not-allowed; }
|
||
.stage-step .lbl { font-size: 13px; font-weight: 500; color: var(--black-alpha-56); }
|
||
.stage-step.active .lbl { color: var(--accent-black); font-weight: 600; }
|
||
.stage-step .st { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); margin-left: 4px; padding: 1px 6px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-sm); letter-spacing: .04em; }
|
||
.stage-step.active .st { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); }
|
||
.stage-line { flex: 1; height: 1px; background: var(--border-faint); margin: 0 14px; min-width: 30px; }
|
||
.stage-line.done { background: var(--accent-black); }
|
||
|
||
/* ─── Stage panes ─── */
|
||
.stage { display: none; }
|
||
.stage.active { display: block; }
|
||
|
||
/* Common pane */
|
||
.pane { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||
.pane-h { display: flex; align-items: center; gap: 8px; padding: 14px 18px; border-bottom: 1px solid var(--border-faint); }
|
||
.pane-h strong { font-size: 14px; font-weight: 600; }
|
||
|
||
/* Stage foot */
|
||
.stage-foot { display: flex; justify-content: space-between; align-items: center; padding: 18px 0 0; margin-top: 18px; border-top: 1px solid var(--border-faint); }
|
||
.stage-foot .info { font-size: 12.5px; color: var(--black-alpha-56); }
|
||
.stage-foot .info .mono { font-family: var(--font-mono); color: var(--black-alpha-48); font-size: 11.5px; letter-spacing: .02em; }
|
||
|
||
/* === STAGE 1 · 脚本 === */
|
||
.stage-script { display: grid; grid-template-columns: 1fr 1.2fr; gap: 16px; min-height: 560px; }
|
||
|
||
.chat-pane { display: flex; flex-direction: column; }
|
||
.chat-body { padding: 16px 18px; flex: 1; overflow-y: auto; max-height: 460px; display: flex; flex-direction: column; gap: 14px; }
|
||
.msg .bubble { max-width: 90%; padding: 10px 14px; font-size: 13px; line-height: 1.6; border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||
.msg.ai .bubble { background: var(--surface); }
|
||
.msg.user { display: flex; flex-direction: column; align-items: flex-end; }
|
||
.msg.user .bubble { background: var(--heat-12); color: var(--accent-black); border-color: var(--heat-20); }
|
||
.msg .time { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); margin-top: 4px; letter-spacing: .02em; }
|
||
.msg .actions { display: flex; gap: 6px; margin-top: 6px; }
|
||
.ai-avatar { width: 26px; height: 26px; background: var(--heat); color: var(--accent-white); display: grid; place-items: center; font-size: 11px; font-weight: 700; border: 1px solid var(--heat); border-radius: 50%; }
|
||
.del { text-decoration: line-through; color: var(--black-alpha-48); }
|
||
.ins { background: var(--forest-bg); color: var(--accent-forest); padding: 0 3px; }
|
||
.chat-input { padding: 14px 18px; border-top: 1px solid var(--border-faint); }
|
||
|
||
.shot-list { display: flex; flex-direction: column; }
|
||
.shots-body { padding: 12px 16px; flex: 1; overflow-y: auto; max-height: 540px; display: flex; flex-direction: column; gap: 10px; }
|
||
.shot-card { background: var(--background-base); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 12px 14px; }
|
||
.shot-card.highlight { border-color: var(--heat); background: var(--heat-12); }
|
||
.shot-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
|
||
.shot-num { width: 22px; height: 22px; background: var(--accent-black); color: var(--accent-white); display: grid; place-items: center; font-family: var(--font-mono); font-size: 11px; font-weight: 700; border-radius: var(--r-sm); }
|
||
.shot-time { font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); padding: 2px 6px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); }
|
||
.shot-row { display: grid; grid-template-columns: 36px 1fr; gap: 8px; padding: 4px 0; }
|
||
.shot-k { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); padding-top: 2px; letter-spacing: .04em; }
|
||
.shot-v { font-size: 12.5px; color: var(--accent-black); line-height: 1.55; }
|
||
.icon-mini-btn { width: 24px; height: 24px; display: grid; place-items: center; color: var(--black-alpha-48); background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); cursor: pointer; font-size: 14px; }
|
||
.icon-mini-btn:hover { color: var(--heat); border-color: var(--heat); }
|
||
|
||
/* === STAGE 2 · 基础资产 === */
|
||
.stage-assets { display: grid; grid-template-columns: 200px 1fr; gap: 24px; }
|
||
.asset-side .ttab { padding: 10px 12px; font-size: 13px; cursor: pointer; display: flex; align-items: center; gap: 8px; border: 1px solid transparent; border-radius: var(--r-md); }
|
||
.asset-side .ttab:hover { background: var(--background-lighter); }
|
||
.asset-side .ttab.active { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); font-weight: 600; }
|
||
.asset-side .ttab .num { font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); margin-left: auto; }
|
||
.asset-side .ttab.active .num { color: var(--heat); }
|
||
.asset-side .info { font-size: 12px; color: var(--black-alpha-48); padding: 14px 12px; line-height: 1.6; margin-top: 14px; border-top: 1px solid var(--border-faint); }
|
||
.asset-side .info strong { color: var(--black-alpha-56); display: block; }
|
||
.asset-side .info .mono { font-family: var(--font-mono); }
|
||
|
||
.asset-grid-2 { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
|
||
.asset-card-2 { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||
.asset-card-2 .thumb-2 { aspect-ratio: 1; }
|
||
.asset-card-2 .body-2 { padding: 12px 14px; }
|
||
.prompt-box { background: var(--background-base); border: 1px solid var(--border-faint); border-radius: var(--r-sm); padding: 10px 12px; font-size: 12px; color: var(--black-alpha-56); margin-top: 8px; line-height: 1.55; font-family: var(--font-mono); letter-spacing: .01em; }
|
||
.fail-icon { width: 28px; height: 28px; background: var(--accent-crimson); color: var(--accent-white); display: grid; place-items: center; font-weight: 700; font-size: 16px; border-radius: 50%; }
|
||
|
||
/* === STAGE 3 · 故事板 === */
|
||
.stage-storyboard { display: grid; grid-template-columns: 1.7fr 1fr; gap: 16px; align-items: start; }
|
||
.sb-canvas { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||
.sb-row { display: grid; grid-template-columns: 60px 1fr 1fr; gap: 0; border-bottom: 1px solid var(--border-faint); }
|
||
.sb-row:last-child { border-bottom: 0; }
|
||
.sb-row.head { background: var(--background-lighter); font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em; text-transform: uppercase; }
|
||
.sb-row.head > div { padding: 10px 14px; }
|
||
.sb-num { padding: 14px; font-family: var(--font-mono); font-size: 14px; font-weight: 700; color: var(--accent-black); border-right: 1px solid var(--border-faint); }
|
||
.sb-num .t { display: block; font-size: 10.5px; color: var(--black-alpha-48); font-weight: 400; margin-top: 4px; letter-spacing: .02em; }
|
||
.sb-img { padding: 10px; border-right: 1px solid var(--border-faint); }
|
||
.sb-img .placeholder { aspect-ratio: 16/9; }
|
||
.sb-text { padding: 14px; display: flex; flex-direction: column; gap: 6px; }
|
||
.sb-text .meta { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em; }
|
||
.sb-text .dialog { font-size: 12.5px; color: var(--accent-black); line-height: 1.55; }
|
||
.sb-text .sfx { font-size: 11.5px; color: var(--black-alpha-48); }
|
||
|
||
.sb-side .pane { padding: 18px; }
|
||
.prompt-edit { background: var(--background-base); border: 1px solid var(--border-faint); border-radius: var(--r-md); padding: 12px 14px; font-family: var(--font-mono); font-size: 11.5px; line-height: 1.7; color: var(--black-alpha-56); white-space: pre-wrap; min-height: 200px; outline: none; letter-spacing: .01em; }
|
||
.prompt-edit:focus { border-color: var(--heat); box-shadow: 0 0 0 3px var(--heat-12); }
|
||
.asset-tag { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-pill); font-size: 11.5px; }
|
||
.asset-tag .dotc { width: 14px; height: 14px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: 50%; }
|
||
|
||
/* === STAGE 4 · 视频片段 === */
|
||
.queue-bar { display: flex; align-items: center; gap: 16px; padding: 14px 18px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); margin-bottom: 18px; }
|
||
.queue-bar .bar-wrap { flex: 1; height: 6px; background: var(--background-lighter); overflow: hidden; }
|
||
.queue-bar .bar-wrap > span { display: block; height: 100%; background: var(--heat); }
|
||
|
||
.video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
|
||
.video-card { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||
.video-thumb { aspect-ratio: 9/16; max-height: 320px; position: relative; border-radius: var(--r-md) var(--r-md) 0 0; }
|
||
.video-thumb .play { position: absolute; inset: 0; display: grid; place-items: center; background: rgba(0,0,0,0.05); cursor: pointer; opacity: 0; transition: opacity .15s; }
|
||
.video-thumb:hover .play { opacity: 1; }
|
||
.video-thumb .btn-play { width: 36px; height: 36px; background: rgba(0,0,0,.7); color: var(--accent-white); border-radius: 50%; display: grid; place-items: center; }
|
||
.video-card .body { padding: 10px 12px; }
|
||
|
||
/* === STAGE 5 · 编辑器 === */
|
||
.editor { display: grid; grid-template-columns: 1fr 280px; grid-template-rows: 1fr auto; gap: 0; height: 580px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); }
|
||
.editor-preview { padding: 16px; border-right: 1px solid var(--border-faint); border-bottom: 1px solid var(--border-faint); display: flex; flex-direction: column; gap: 12px; }
|
||
.editor-preview .canvas { flex: 1; aspect-ratio: 9/16; max-height: 380px; margin: 0 auto; background:
|
||
repeating-linear-gradient(135deg, rgba(0,0,0,0.03) 0 1px, transparent 1px 12px),
|
||
var(--background-lighter);
|
||
border: 1px solid var(--border-faint);
|
||
border-radius: var(--r-md);
|
||
display: grid; place-items: center;
|
||
color: var(--black-alpha-48);
|
||
font-family: var(--font-mono);
|
||
font-size: 12px; }
|
||
.editor-preview .controls { display: flex; align-items: center; gap: 8px; justify-content: center; }
|
||
.ctl-btn { width: 36px; height: 36px; border: 1px solid var(--border-faint); background: var(--surface); color: var(--black-alpha-56); border-radius: var(--r-md); display: grid; place-items: center; cursor: pointer; transition: background var(--t-base), border-color var(--t-base), color var(--t-base); }
|
||
.ctl-btn:hover { color: var(--heat); border-color: var(--heat-40); background: var(--heat-12); }
|
||
|
||
.editor-props { padding: 16px; border-bottom: 1px solid var(--border-faint); overflow-y: auto; }
|
||
.props-tabs { display: flex; gap: 0; margin-bottom: 14px; border-bottom: 1px solid var(--border-faint); }
|
||
.props-tabs > div { padding: 8px 12px; font-size: 12.5px; color: var(--black-alpha-56); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; }
|
||
.props-tabs > div.active { color: var(--heat); border-bottom-color: var(--heat); font-weight: 600; }
|
||
.style-swatch { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
|
||
.swatch-card { padding: 10px; border: 1px solid var(--border-faint); border-radius: var(--r-md); cursor: pointer; }
|
||
.swatch-card:hover { background: var(--background-lighter); }
|
||
.swatch-card.selected { border-color: var(--heat); background: var(--heat-12); }
|
||
.swatch-card .demo { font-size: 12px; padding: 6px 8px; background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-sm); margin-bottom: 4px; text-align: center; }
|
||
.swatch-card .demo.b { background: var(--accent-black); color: var(--accent-white); font-family: serif; }
|
||
.swatch-card .demo.c { color: var(--heat); -webkit-text-stroke: 0.5px var(--accent-black); }
|
||
.swatch-card .demo.d { background: var(--accent-honey); color: var(--accent-black); font-weight: 700; }
|
||
.swatch-card .nm { font-size: 11px; color: var(--black-alpha-48); font-family: var(--font-mono); letter-spacing: .02em; }
|
||
.props-row { display: flex; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border-faint); font-size: 12.5px; }
|
||
.props-row:last-child { border-bottom: 0; }
|
||
.props-row .k { color: var(--black-alpha-48); flex: 1; font-family: var(--font-mono); font-size: 11px; letter-spacing: .02em; }
|
||
.input-mini { width: 90px; padding: 0 10px; height: 28px; font-size: 12px; border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--black-alpha-12); }
|
||
|
||
.timeline { grid-column: 1 / -1; padding: 14px 16px; background: var(--background-base); }
|
||
.tl-toolbar { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid var(--border-faint); }
|
||
.tl-ruler { display: grid; grid-template-columns: 80px 1fr; align-items: center; padding: 4px 0; font-size: 10.5px; }
|
||
.tl-ruler .l { font-family: var(--font-mono); color: var(--black-alpha-48); padding-left: 4px; }
|
||
.tl-ruler .ticks { display: flex; justify-content: space-between; font-family: var(--font-mono); color: var(--black-alpha-48); padding: 0 4px; letter-spacing: .04em; }
|
||
.tl-track { display: grid; grid-template-columns: 80px 1fr; align-items: center; gap: 0; padding: 6px 0; }
|
||
.tl-track .label { font-size: 11.5px; color: var(--black-alpha-56); display: flex; align-items: center; gap: 6px; padding-left: 4px; }
|
||
.tl-track .label .dot { width: 8px; height: 8px; }
|
||
.tl-track .lane { display: flex; gap: 2px; height: 30px; position: relative; }
|
||
.clip { padding: 0 8px; font-size: 11px; display: flex; align-items: center; cursor: pointer; overflow: hidden; white-space: nowrap; user-select: none; }
|
||
.clip.video { background: var(--heat-12); border: 1px solid var(--heat-40); color: var(--heat); }
|
||
.clip.video.selected { background: var(--heat); color: var(--accent-white); border-color: var(--heat); }
|
||
.clip.subtitle { background: var(--forest-bg); border: 1px solid var(--forest-bd); color: var(--accent-forest); }
|
||
.clip.bgm { background: rgba(144, 97, 255, 0.10); border: 1px solid rgba(144, 97, 255, 0.30); color: var(--accent-amethyst); }
|
||
.clip .num { font-family: var(--font-mono); font-weight: 700; margin-right: 6px; opacity: .7; }
|
||
.playhead { position: absolute; top: -16px; bottom: -54px; width: 1px; background: var(--heat); pointer-events: none; }
|
||
.playhead::before { content: ''; position: absolute; top: -2px; left: -4px; width: 9px; height: 9px; background: var(--heat); transform: rotate(45deg); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="page">
|
||
|
||
<!-- Project header -->
|
||
<div class="proj-head">
|
||
<div style="display:flex; gap:14px; align-items:center;">
|
||
<div class="placeholder" style="width:42px;height:54px;"><span class="ph-frame">9:16</span></div>
|
||
<div>
|
||
<div style="display:flex; gap:8px; align-items:center;">
|
||
<h1>补水面膜 · 痛点种草 · v3</h1>
|
||
<span class="pill info"><span class="dot"></span>进行中</span>
|
||
</div>
|
||
<div class="muted-2 mono" style="font-size:11.5px; margin-top:4px; letter-spacing:.02em;">// 透真补水面膜 · AI 全生 · 6 镜 · 0-15s · 9:16</div>
|
||
</div>
|
||
</div>
|
||
<div class="hstack">
|
||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('分享', '/projects/p3/share')">分享</button>
|
||
<button class="btn btn-sm" onclick="Shell.toast('已复制项目', '补水面膜 · v4')">复制项目</button>
|
||
<button class="btn btn-sm" onclick="Shell.toast('归档项目', '/projects/p3/archive')">归档</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Stage stepper -->
|
||
<div class="stepper">
|
||
<span class="corner-tr" aria-hidden></span><span class="corner-bl" aria-hidden></span>
|
||
<a class="stage-step done" data-stage="1" href="#stage-1"><div class="num">1</div><div class="lbl">脚本</div><div class="st">已确认</div></a>
|
||
<div class="stage-line done"></div>
|
||
<a class="stage-step done" data-stage="2" href="#stage-2"><div class="num">2</div><div class="lbl">基础资产</div><div class="st">已确认</div></a>
|
||
<div class="stage-line done"></div>
|
||
<a class="stage-step active" data-stage="3" href="#stage-3"><div class="num">3</div><div class="lbl">故事板</div><div class="st">待确认</div></a>
|
||
<div class="stage-line"></div>
|
||
<a class="stage-step" data-stage="4" href="#stage-4"><div class="num">4</div><div class="lbl">视频片段</div><div class="st">未开始</div></a>
|
||
<div class="stage-line"></div>
|
||
<a class="stage-step" data-stage="5" href="#stage-5"><div class="num">5</div><div class="lbl">拼接导出</div><div class="st">未开始</div></a>
|
||
</div>
|
||
|
||
<!-- ============= STAGE 1 · 脚本 ============= -->
|
||
<section class="stage" data-stage-pane="1">
|
||
<div class="stage-script">
|
||
<div class="pane chat-pane">
|
||
<div class="pane-h">
|
||
<div class="ai-avatar">AI</div>
|
||
<strong>脚本助手</strong>
|
||
<span class="muted-2 mono" style="font-size:11px;">· GPT-4o</span>
|
||
<span class="spacer"></span>
|
||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('已清空对话')">清空对话</button>
|
||
</div>
|
||
<div class="chat-body">
|
||
<div class="msg ai">
|
||
<div style="display:flex; gap:10px; align-items:flex-start;">
|
||
<div class="ai-avatar" style="margin-top:2px;">AI</div>
|
||
<div class="bubble">根据 <strong>透真补水面膜</strong> 和"痛点种草"风格,我先生成了一版 6 镜的脚本,主线是"加班党的深夜急救"。你可以直接编辑右侧的镜头,或者让我重写某一镜。</div>
|
||
</div>
|
||
<div class="time" style="margin-left:36px;">14:02</div>
|
||
</div>
|
||
<div class="msg user">
|
||
<div class="bubble">第 4 镜对白太硬了,能不能更口语化?</div>
|
||
<div class="time">14:05</div>
|
||
</div>
|
||
<div class="msg ai">
|
||
<div style="display:flex; gap:10px; align-items:flex-start;">
|
||
<div class="ai-avatar" style="margin-top:2px;">AI</div>
|
||
<div>
|
||
<div class="bubble">把 "<span class="del">补水力极强,锁水持久</span>" 改成 "<span class="ins">真的,敷完第二天起来脸是软的,不是绷着的</span>",更像真实分享。已替换右侧第 4 镜,确认要的话点 [接受]。</div>
|
||
<div class="actions">
|
||
<button class="btn btn-sm" onclick="Shell.toast('已接受改动', 'shot-4')">接受</button>
|
||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('再来一版')">再来一版</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="time" style="margin-left:36px;">14:05</div>
|
||
</div>
|
||
</div>
|
||
<div class="chat-input">
|
||
<textarea class="textarea" placeholder="对脚本的修改诉求 · 比如:让第 5 镜更夸张一点、整体加 1 镜结尾……" rows="2"></textarea>
|
||
<div class="hstack" style="margin-top:8px;">
|
||
<button class="btn btn-ghost btn-sm">↻ 整体重写</button>
|
||
<span class="spacer"></span>
|
||
<button class="btn btn-primary" onclick="Shell.toast('已发送', 'POST /chat')">发送 ⌘↵</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pane shot-list">
|
||
<div class="pane-h">
|
||
<strong>镜头脚本</strong>
|
||
<span class="muted-2 mono" style="font-size:11px;">· 6 镜 · 0-15s</span>
|
||
<span class="spacer"></span>
|
||
<button class="btn btn-ghost btn-sm" onclick="Shell.toast('已加一镜')">+ 加一镜</button>
|
||
</div>
|
||
<div class="shots-body">
|
||
<div class="shot-card">
|
||
<div class="shot-head"><div class="shot-num">1</div><div class="shot-time">0-2s</div><span class="spacer"></span><button class="icon-mini-btn" title="重写">↻</button></div>
|
||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">深夜的办公桌,电脑屏幕亮着,女主对着镜子叹气,皮肤干燥起皮特写。</div></div>
|
||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">(叹气)"加班三天,脸已经不能看了……"</div></div>
|
||
</div>
|
||
<div class="shot-card">
|
||
<div class="shot-head"><div class="shot-num">2</div><div class="shot-time">2-5s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">女主从抽屉拿出补水面膜,包装特写,光线柔和。</div></div>
|
||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"还好我有这个 —— 透真玻尿酸面膜。"</div></div>
|
||
</div>
|
||
<div class="shot-card">
|
||
<div class="shot-head"><div class="shot-num">3</div><div class="shot-time">5-8s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">面膜布展开,30g 精华液从布上滴落特写,慢镜头。</div></div>
|
||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"30g 精华液,一片顶三片的量。"</div></div>
|
||
</div>
|
||
<div class="shot-card highlight">
|
||
<div class="shot-head"><div class="shot-num">4</div><div class="shot-time">8-11s</div><span class="pill info" style="margin-left:6px;"><span class="dot"></span>刚改</span><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">女主敷面膜,闭眼平躺,灯光暖。床头闹钟显示 23:41。</div></div>
|
||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"真的,敷完第二天起来脸是软的,不是绷着的。"</div></div>
|
||
</div>
|
||
<div class="shot-card">
|
||
<div class="shot-head"><div class="shot-num">5</div><div class="shot-time">11-13s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">第二天早上,女主对镜化妆,皮肤透亮,状态饱满。</div></div>
|
||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"早上化妆都能看出来,不假吹。"</div></div>
|
||
</div>
|
||
<div class="shot-card">
|
||
<div class="shot-head"><div class="shot-num">6</div><div class="shot-time">13-15s</div><span class="spacer"></span><button class="icon-mini-btn">↻</button></div>
|
||
<div class="shot-row"><span class="shot-k">画面</span><div class="shot-v">面膜产品大图,价格标签 "5 片装 ¥39.9",购物车浮动按钮。</div></div>
|
||
<div class="shot-row"><span class="shot-k">对白</span><div class="shot-v">"618 五片才 39.9,囤起来。"</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stage-foot">
|
||
<div class="info"><span class="mono">[ LLM 用量 ~2.4k tokens · ¥0.04 ]</span></div>
|
||
<div class="hstack">
|
||
<button class="btn" onclick="Shell.toast('重新生成', 'POST /script/regen')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12a8 8 0 0 1 14-5.5L21 9"/><path d="M21 4v5h-5"/><path d="M20 12a8 8 0 0 1-14 5.5L3 15"/><path d="M3 20v-5h5"/></svg> 重新生成全部</button>
|
||
<button class="btn btn-primary btn-lg" onclick="location.hash='#stage-2'">确认脚本,进入下一步 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============= STAGE 2 · 基础资产 ============= -->
|
||
<section class="stage" data-stage-pane="2">
|
||
<div class="stage-assets">
|
||
<div class="asset-side">
|
||
<div class="ttab active"><span>人物</span><span class="num">2/2</span></div>
|
||
<div class="ttab"><span>场景</span><span class="num">3/3</span></div>
|
||
<div class="ttab"><span>商品</span><span class="num">3 张</span></div>
|
||
<div class="info">
|
||
基础资产是后续故事板的素材。生成后可以单独修改提示词重跑,或上传你已有的图替换。
|
||
<br><br>
|
||
<strong class="mono">// 人物 +¥0.20/张</strong>
|
||
<strong class="mono">// 场景 +¥0.15/张</strong>
|
||
<span style="color:var(--black-alpha-48);">商品图无成本(直接复用商品库)</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="hstack" style="margin-bottom:14px;">
|
||
<h3 style="font-size:15px; font-weight:600;">人物 · 2 个</h3>
|
||
<span class="spacer"></span>
|
||
<button class="btn btn-ghost btn-sm">从我的资产库选</button>
|
||
<button class="btn btn-sm" onclick="Shell.toast('+ 新增人物')">+ 新增人物</button>
|
||
</div>
|
||
|
||
<div class="asset-grid-2">
|
||
<div class="asset-card-2">
|
||
<div class="placeholder thumb-2"><span class="ph-frame">林夕 · 都市白领</span></div>
|
||
<div class="body-2">
|
||
<div class="hstack"><strong style="font-size:13.5px;">主角 · 林夕</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>已确认</span></div>
|
||
<div class="prompt-box">25-30 岁都市白领,长发,穿宽松米色家居服,温柔但带点疲倦感,肤色偏黄/略干。</div>
|
||
<div class="hstack" style="margin-top:10px;">
|
||
<button class="btn btn-ghost btn-sm">改提示词</button>
|
||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||
<span class="spacer"></span>
|
||
<button class="btn btn-ghost btn-sm">⤓ 上传替换</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="asset-card-2">
|
||
<div class="placeholder thumb-2">
|
||
<div style="display:flex; flex-direction:column; gap:8px; align-items:center;">
|
||
<div class="spinner"></div>
|
||
<span class="ph-frame">生成中 · 约 8s</span>
|
||
</div>
|
||
</div>
|
||
<div class="body-2">
|
||
<div class="hstack"><strong style="font-size:13.5px;">朋友/同事 · 阿楠</strong><span class="spacer"></span><span class="pill info"><span class="dot"></span>生成中</span></div>
|
||
<div class="prompt-box">25-30 岁同龄女性,短发,穿白色衬衫,妆容精致皮肤好,作为对比。</div>
|
||
<div class="hstack" style="margin-top:10px;">
|
||
<button class="btn btn-ghost btn-sm" disabled>改提示词</button>
|
||
<button class="btn btn-ghost btn-sm" disabled>↻ 重跑</button>
|
||
<span class="spacer"></span>
|
||
<button class="btn btn-ghost btn-sm" disabled>⤓ 上传替换</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="hstack" style="margin:28px 0 14px;">
|
||
<h3 style="font-size:15px; font-weight:600;">场景 · 3 个</h3>
|
||
<span class="spacer"></span>
|
||
<button class="btn btn-ghost btn-sm">从我的资产库选</button>
|
||
<button class="btn btn-sm">+ 新增场景</button>
|
||
</div>
|
||
|
||
<div class="asset-grid-2">
|
||
<div class="asset-card-2">
|
||
<div class="placeholder thumb-2"><span class="ph-frame">深夜办公桌</span></div>
|
||
<div class="body-2">
|
||
<div class="hstack"><strong style="font-size:13.5px;">深夜办公桌</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>已确认</span></div>
|
||
<div class="prompt-box">深夜居家办公环境,木质书桌,台灯暖光,电脑屏幕亮着,背景虚化。</div>
|
||
</div>
|
||
</div>
|
||
<div class="asset-card-2">
|
||
<div class="placeholder thumb-2"><span class="ph-frame">床头特写</span></div>
|
||
<div class="body-2">
|
||
<div class="hstack"><strong style="font-size:13.5px;">卧室床头</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>已确认</span></div>
|
||
<div class="prompt-box">米白色床品,木质床头柜,闹钟显示晚间时间,氛围温柔安静。</div>
|
||
</div>
|
||
</div>
|
||
<div class="asset-card-2">
|
||
<div class="placeholder thumb-2">
|
||
<div style="display:flex; flex-direction:column; gap:6px; align-items:center;">
|
||
<div class="fail-icon">!</div>
|
||
<span class="ph-frame">生成失败</span>
|
||
</div>
|
||
</div>
|
||
<div class="body-2">
|
||
<div class="hstack"><strong style="font-size:13.5px;">通勤地铁</strong><span class="spacer"></span><span class="pill err"><span class="dot"></span>失败</span></div>
|
||
<div class="prompt-box">早高峰地铁车厢,光线偏冷,年轻通勤族,氛围紧张。</div>
|
||
<div class="muted-2" style="font-size:12px; margin-top:6px; display:flex; align-items:center; gap:6px;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="color:var(--accent-crimson); flex-shrink:0;"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>提示词被安全审核拦截,请调整后重试(不扣费)</div>
|
||
<div class="hstack" style="margin-top:8px;">
|
||
<button class="btn btn-sm">改提示词</button>
|
||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stage-foot">
|
||
<div class="info"><span class="mono">[ 已确认 ¥0.85 · 待生成 ¥0.20 · 失败 ¥0(不扣) ]</span></div>
|
||
<div class="hstack">
|
||
<button class="btn" onclick="location.hash='#stage-1'">← 返回脚本</button>
|
||
<button class="btn btn-primary btn-lg" disabled>1 个资产生成中 · 等待</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============= STAGE 3 · 故事板 ============= -->
|
||
<section class="stage active" data-stage-pane="3">
|
||
<div class="stage-storyboard">
|
||
<div class="sb-canvas">
|
||
<div class="sb-row head">
|
||
<div>镜号</div><div>画面</div><div>机位 / 对白 / 音效</div>
|
||
</div>
|
||
<div class="sb-row">
|
||
<div class="sb-num">1<span class="t">0-2s</span></div>
|
||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">深夜办公桌 · 女主对镜叹气 · 暖光</span></div></div>
|
||
<div class="sb-text">
|
||
<div class="meta">中景 / 固定机位</div>
|
||
<div class="dialog">"加班三天,脸已经不能看了……"</div>
|
||
<div class="sfx">SFX:键盘声 + 远处空调嗡鸣</div>
|
||
</div>
|
||
</div>
|
||
<div class="sb-row">
|
||
<div class="sb-num">2<span class="t">2-5s</span></div>
|
||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">面膜包装特写 · 抽屉光线柔和</span></div></div>
|
||
<div class="sb-text">
|
||
<div class="meta">特写 / 缓推</div>
|
||
<div class="dialog">"还好我有这个 —— 透真玻尿酸面膜。"</div>
|
||
<div class="sfx">SFX:抽屉滑动声</div>
|
||
</div>
|
||
</div>
|
||
<div class="sb-row">
|
||
<div class="sb-num">3<span class="t">5-8s</span></div>
|
||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">面膜布展开 · 30g 精华滴落 · 慢动作</span></div></div>
|
||
<div class="sb-text">
|
||
<div class="meta">微距 / 慢镜头</div>
|
||
<div class="dialog">"30g 精华液,一片顶三片的量。"</div>
|
||
<div class="sfx">SFX:水滴慢速回弹</div>
|
||
</div>
|
||
</div>
|
||
<div class="sb-row">
|
||
<div class="sb-num">4<span class="t">8-11s</span></div>
|
||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">女主敷面膜平躺 · 闹钟 23:41</span></div></div>
|
||
<div class="sb-text">
|
||
<div class="meta">中近景 / 固定</div>
|
||
<div class="dialog">"敷完第二天起来脸是软的,不是绷着的。"</div>
|
||
<div class="sfx">SFX:呼吸声 + 窗外风声</div>
|
||
</div>
|
||
</div>
|
||
<div class="sb-row">
|
||
<div class="sb-num">5<span class="t">11-13s</span></div>
|
||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">早晨化妆台 · 女主对镜上妆 · 透亮</span></div></div>
|
||
<div class="sb-text">
|
||
<div class="meta">中景 / 固定</div>
|
||
<div class="dialog">"早上化妆都能看出来,不假吹。"</div>
|
||
<div class="sfx">SFX:化妆刷轻扫声</div>
|
||
</div>
|
||
</div>
|
||
<div class="sb-row">
|
||
<div class="sb-num">6<span class="t">13-15s</span></div>
|
||
<div class="sb-img"><div class="placeholder"><span class="ph-frame">产品大图 · 价格 5片¥39.9 · 购物车</span></div></div>
|
||
<div class="sb-text">
|
||
<div class="meta">产品定格 / 静止</div>
|
||
<div class="dialog">"618 五片才 39.9,囤起来。"</div>
|
||
<div class="sfx">SFX:清脆叮咚音效</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sb-side">
|
||
<div class="pane">
|
||
<div class="hstack" style="margin-bottom:10px;">
|
||
<strong style="font-size:14px;">故事板</strong>
|
||
<span class="spacer"></span>
|
||
<span class="pill ok"><span class="dot"></span>已生成</span>
|
||
</div>
|
||
<div class="muted-2" style="font-size:12px; line-height:1.55; margin-bottom:14px;">
|
||
整张故事板由 image-2 一次性输出,包含画面 + 镜头说明。如需修改请编辑下方提示词整张重跑(不能局部改)。
|
||
</div>
|
||
|
||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:6px; letter-spacing:.04em;">// 视觉提示词</div>
|
||
<div class="prompt-edit" contenteditable="true">风格:日系小清新短视频,暖色调,午夜→清晨光线变化。
|
||
镜头列表(6 镜,0-15s):
|
||
1. 中景 · 深夜办公桌女主对镜叹气
|
||
2. 特写 · 面膜包装从抽屉拿出
|
||
3. 微距 · 面膜布展开 + 精华液滴落慢镜
|
||
4. 中近景 · 女主敷面膜平躺,床头闹钟 23:41
|
||
5. 中景 · 早晨化妆台 + 女主透亮上妆
|
||
6. 产品定格 · 面膜盒 + 价格标签 ¥39.9
|
||
人物:林夕(参考 R1)
|
||
场景:深夜办公桌(S1) + 卧室床头(S2)
|
||
要求:表格化布局,每镜含画面 + 文字说明</div>
|
||
|
||
<div class="hstack" style="margin-top:12px;">
|
||
<button class="btn btn-sm" onclick="Shell.toast('整张重跑', 'POST /storyboard/regen ¥0.45')">↻ 整张重跑</button>
|
||
<span class="spacer"></span>
|
||
<span class="muted-2 mono" style="font-size:11px;">~¥0.45</span>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// 绑定的资产</div>
|
||
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||
<span class="asset-tag"><span class="dotc"></span>林夕(人物)</span>
|
||
<span class="asset-tag"><span class="dotc"></span>深夜办公桌(场景)</span>
|
||
<span class="asset-tag"><span class="dotc"></span>卧室床头(场景)</span>
|
||
<span class="asset-tag"><span class="dotc"></span>面膜盒(商品)</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stage-foot">
|
||
<div class="info"><span class="mono">[ image-2 一次 ¥0.45 · 累计 ¥1.50 ]</span></div>
|
||
<div class="hstack">
|
||
<button class="btn" onclick="location.hash='#stage-2'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> 返回资产</button>
|
||
<button class="btn btn-primary btn-lg" onclick="location.hash='#stage-4'">确认故事板,开始生成视频片段 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============= STAGE 4 · 视频片段 ============= -->
|
||
<section class="stage" data-stage-pane="4">
|
||
<div class="queue-bar">
|
||
<div>
|
||
<div style="font-size:14px; font-weight:600;">视频生成中 · 4 / 6 完成</div>
|
||
<div class="muted-2 mono" style="font-size:11px; margin-top:3px; letter-spacing:.02em;">// 每镜 Seedance 调用 ~30s · 预计还需 1 分钟</div>
|
||
</div>
|
||
<div class="bar-wrap"><span style="width:67%"></span></div>
|
||
<span class="muted mono" style="font-size:12px;">67%</span>
|
||
<button class="btn btn-sm" onclick="Shell.toast('全部重跑', 'POST /video/regen-all')">↻ 全部重跑</button>
|
||
</div>
|
||
|
||
<div class="video-grid">
|
||
<div class="video-card">
|
||
<div class="placeholder video-thumb">
|
||
<span class="ph-frame">镜 1 · 0-2s</span>
|
||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||
</div>
|
||
<div class="body">
|
||
<div class="hstack"><strong style="font-size:13px;">镜 1 · 深夜办公桌</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">2.0s · 1080×1920 · ¥0.18</div>
|
||
<div class="hstack" style="margin-top:8px;">
|
||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="video-card">
|
||
<div class="placeholder video-thumb">
|
||
<span class="ph-frame">镜 2 · 2-5s</span>
|
||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||
</div>
|
||
<div class="body">
|
||
<div class="hstack"><strong style="font-size:13px;">镜 2 · 面膜包装</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">3.0s · 1080×1920 · ¥0.22</div>
|
||
<div class="hstack" style="margin-top:8px;">
|
||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="video-card">
|
||
<div class="placeholder video-thumb">
|
||
<span class="ph-frame">镜 3 · 5-8s</span>
|
||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||
</div>
|
||
<div class="body">
|
||
<div class="hstack"><strong style="font-size:13px;">镜 3 · 精华液微距</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">3.0s · 1080×1920 · ¥0.22</div>
|
||
<div class="hstack" style="margin-top:8px;">
|
||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="video-card">
|
||
<div class="placeholder video-thumb">
|
||
<span class="ph-frame">镜 4 · 8-11s</span>
|
||
<div class="play"><div class="btn-play"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M5 4l6 4-6 4z" fill="currentColor"/></svg></div></div>
|
||
</div>
|
||
<div class="body">
|
||
<div class="hstack"><strong style="font-size:13px;">镜 4 · 敷面膜平躺</strong><span class="spacer"></span><span class="pill ok"><span class="dot"></span>完成</span></div>
|
||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">3.0s · 1080×1920 · ¥0.22</div>
|
||
<div class="hstack" style="margin-top:8px;">
|
||
<button class="btn btn-ghost btn-sm">↻ 重跑</button>
|
||
<button class="btn btn-ghost btn-sm">⤓ 下载</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="video-card">
|
||
<div class="placeholder video-thumb">
|
||
<div style="display:flex; flex-direction:column; gap:8px; align-items:center;">
|
||
<div class="spinner"></div>
|
||
<span class="ph-frame">镜 5 · 生成中 18s</span>
|
||
</div>
|
||
</div>
|
||
<div class="body">
|
||
<div class="hstack"><strong style="font-size:13px;">镜 5 · 化妆台</strong><span class="spacer"></span><span class="pill info"><span class="dot"></span>生成中</span></div>
|
||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">2.0s · 排队中 · ~¥0.18</div>
|
||
<div class="hstack" style="margin-top:8px;">
|
||
<button class="btn btn-ghost btn-sm" disabled>↻ 重跑</button>
|
||
<button class="btn btn-ghost btn-sm" disabled>⤓ 下载</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="video-card">
|
||
<div class="placeholder video-thumb"><span class="ph-frame">镜 6 · 排队</span></div>
|
||
<div class="body">
|
||
<div class="hstack"><strong style="font-size:13px;">镜 6 · 产品定格</strong><span class="spacer"></span><span class="pill neutral"><span class="dot"></span>排队中</span></div>
|
||
<div class="muted-2 mono" style="font-size:11px; margin-top:4px;">2.0s · 等待中 · ~¥0.18</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stage-foot">
|
||
<div class="info"><span class="mono">[ 已确认 ¥0.84 · 待生成 ¥0.36 · 累计 ¥2.34 ]</span></div>
|
||
<div class="hstack">
|
||
<button class="btn" onclick="location.hash='#stage-3'">← 返回故事板</button>
|
||
<button class="btn btn-primary btn-lg" disabled>2 镜生成中 · 等待</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============= STAGE 5 · 拼接编辑器 ============= -->
|
||
<section class="stage" data-stage-pane="5">
|
||
<div class="editor">
|
||
<div class="editor-preview">
|
||
<div class="canvas">9:16 预览 · 1080×1920</div>
|
||
<div class="controls">
|
||
<button class="ctl-btn" title="上一帧"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M3 3v10l4-5zM9 3v10l4-5z" fill="currentColor"/></svg></button>
|
||
<button class="ctl-btn" title="播放" onclick="Shell.toast('播放', '00:08.42 / 00:15.00')"><svg width="16" height="16" viewBox="0 0 16 16"><path d="M5 4l7 4-7 4z" fill="currentColor"/></svg></button>
|
||
<button class="ctl-btn" title="下一帧"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M13 3v10l-4-5zM7 3v10l-4-5z" fill="currentColor"/></svg></button>
|
||
<span class="muted mono" style="font-size:12px; margin-left:8px;">00:08.42 / 00:15.00</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="editor-props">
|
||
<div class="props-tabs">
|
||
<div class="active">字幕</div>
|
||
<div>转场</div>
|
||
<div>BGM</div>
|
||
</div>
|
||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// 字幕样式</div>
|
||
<div class="style-swatch">
|
||
<div class="swatch-card selected"><div class="demo">真实分享</div><div class="nm">朴素白底</div></div>
|
||
<div class="swatch-card"><div class="demo b">真实分享</div><div class="nm">影视黑底</div></div>
|
||
<div class="swatch-card"><div class="demo c">真实分享</div><div class="nm">手写描边</div></div>
|
||
<div class="swatch-card"><div class="demo d">真实分享</div><div class="nm">综艺暖黄</div></div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// 当前选中(镜 4)</div>
|
||
<div class="props-row"><span class="k">起始</span><input class="input-mini" value="00:08.00"></div>
|
||
<div class="props-row"><span class="k">时长</span><input class="input-mini" value="3.00s"></div>
|
||
<div class="props-row"><span class="k">音量</span><input class="input-mini" value="100"></div>
|
||
<div class="props-row"><span class="k">速度</span><input class="input-mini" value="1.0x"></div>
|
||
<div class="props-row"><span class="k">入场</span><span class="mono" style="font-size:11.5px;">交叉淡化</span></div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<div class="muted mono" style="font-size:11px; font-weight:500; margin-bottom:8px; letter-spacing:.04em;">// BGM</div>
|
||
<div class="props-row" style="border-bottom:0;">
|
||
<span style="font-size:12px; flex:1;">温柔治愈钢琴 · 0:42</span>
|
||
<button class="btn btn-ghost btn-sm">替换</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="timeline">
|
||
<div class="tl-toolbar">
|
||
<button class="btn btn-ghost btn-sm">↶</button>
|
||
<button class="btn btn-ghost btn-sm">↷</button>
|
||
<span class="muted-2" style="font-size:12px;">|</span>
|
||
<button class="btn btn-ghost btn-sm">分割</button>
|
||
<button class="btn btn-ghost btn-sm">复制</button>
|
||
<button class="btn btn-ghost btn-sm">删除</button>
|
||
<span class="spacer"></span>
|
||
<span class="muted mono" style="font-size:11px;">缩放</span>
|
||
<input type="range" min="50" max="200" value="100" style="width:120px;">
|
||
</div>
|
||
|
||
<div class="tl-ruler">
|
||
<div class="l">// time</div>
|
||
<div class="ticks">
|
||
<span>0s</span><span>2s</span><span>5s</span><span>8s</span><span>11s</span><span>13s</span><span>15s</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tl-track">
|
||
<div class="label"><span class="dot" style="background:var(--heat);"></span>视频</div>
|
||
<div class="lane">
|
||
<div class="clip video" style="flex:2;"><span class="num">1</span> 深夜办公桌</div>
|
||
<div class="clip video" style="flex:3;"><span class="num">2</span> 面膜包装</div>
|
||
<div class="clip video" style="flex:3;"><span class="num">3</span> 精华液微距</div>
|
||
<div class="clip video selected" style="flex:3;"><span class="num">4</span> 敷面膜平躺</div>
|
||
<div class="clip video" style="flex:2;"><span class="num">5</span> 化妆台</div>
|
||
<div class="clip video" style="flex:2;"><span class="num">6</span> 产品定格</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tl-track">
|
||
<div class="label"><span class="dot" style="background:var(--accent-forest);"></span>字幕</div>
|
||
<div class="lane" style="position:relative;">
|
||
<div class="clip subtitle" style="flex:2;">加班三天 脸已经不能看了…</div>
|
||
<div class="clip subtitle" style="flex:3;">还好我有这个 透真玻尿酸面膜</div>
|
||
<div class="clip subtitle" style="flex:3;">30g 精华 一片顶三片</div>
|
||
<div class="clip subtitle" style="flex:3;">敷完起来脸是软的</div>
|
||
<div class="clip subtitle" style="flex:2;">化妆都能看出来</div>
|
||
<div class="clip subtitle" style="flex:2;">5 片 ¥39.9 囤起来</div>
|
||
<div class="playhead" style="left:56%;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tl-track">
|
||
<div class="label"><span class="dot" style="background:var(--accent-amethyst);"></span>BGM</div>
|
||
<div class="lane">
|
||
<div class="clip bgm" style="flex:15;">温柔治愈钢琴 · 0:42(循环 1 次,淡入淡出)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stage-foot">
|
||
<div class="info"><span class="mono">[ 合成预估 ~30s · 不消耗 token ]</span></div>
|
||
<div class="hstack">
|
||
<button class="btn" onclick="location.hash='#stage-4'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> 返回片段</button>
|
||
<button class="btn" onclick="Shell.toast('已保存草稿', '/projects/p3/draft')">保存草稿</button>
|
||
<button class="btn btn-primary btn-lg" onclick="Shell.toast('开始导出', 'POST /export · 1080P 9:16')">导出 MP4 · 1080P 9:16 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4v12m0 0l-5-5m5 5l5-5M4 20h16"/></svg></button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
</div>
|
||
<script src="assets/shell.js"></script>
|
||
<script>
|
||
Shell.render({
|
||
active: 'projects',
|
||
crumbs: [{ label: '工作台', href: 'index.html' }, { label: '视频项目', href: 'projects.html' }, { label: '补水面膜 · v3' }]
|
||
});
|
||
|
||
// hash routing
|
||
function activateStage(n) {
|
||
document.querySelectorAll('.stage').forEach(s => s.classList.remove('active'));
|
||
document.querySelector(`[data-stage-pane="${n}"]`)?.classList.add('active');
|
||
|
||
document.querySelectorAll('.stage-step').forEach(s => {
|
||
s.classList.remove('active');
|
||
if (+s.dataset.stage === +n) s.classList.add('active');
|
||
});
|
||
|
||
// update top breadcrumb fragment indicator with shell.toast
|
||
const stageNames = { 1:'脚本', 2:'基础资产', 3:'故事板', 4:'视频片段', 5:'拼接导出' };
|
||
Shell.toast('进入 Stage ' + n + ' · ' + stageNames[n], 'pipeline#stage-' + n);
|
||
}
|
||
function readHash() {
|
||
const m = location.hash.match(/stage-(\d)/);
|
||
if (m) activateStage(+m[1]);
|
||
}
|
||
window.addEventListener('hashchange', readHash);
|
||
readHash();
|
||
</script>
|
||
</body>
|
||
</html>
|