diff --git a/.memory/worklog.json b/.memory/worklog.json index 006e059..aef3d34 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -182,6 +182,25 @@ "type": "session-heartbeat", "message": "Claude 会话活跃 · 最近命令:claude · 分支 master · 1 项未提交变更 · 最近提交:auto-save 2026-05-19 00:06 (+1, ~1)", "files_changed": 1 + }, + { + "ts": "2026-05-19T00:11:58+08:00", + "type": "commit", + "message": "auto-save 2026-05-19 00:11 (+3, ~1)", + "hash": "c3a4637", + "files_changed": 4 + }, + { + "ts": "2026-05-18T16:13:50Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:auto-save 2026-05-19 00:11 (+3, ~1)", + "files_changed": 1 + }, + { + "ts": "2026-05-18T16:16:50Z", + "type": "session-heartbeat", + "message": "Claude 会话活跃 · 最近命令:claude · 分支 master · 7 项未提交变更 · 最近提交:auto-save 2026-05-19 00:11 (+3, ~1)", + "files_changed": 7 } ] } diff --git a/src/app/globals.css b/src/app/globals.css index 80e64f2..4818162 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3,88 +3,150 @@ @tailwind utilities; html, body { - background: #FAFAFA; - color: #09090B; - font-feature-settings: "cv02", "cv03", "cv04", "cv11"; + background: #0A0A0F; + color: #FFFFFF; + font-feature-settings: "cv02", "cv03", "cv04", "cv11", "ss01"; -webkit-font-smoothing: antialiased; } * { box-sizing: border-box; } body { font-family: ui-sans-serif, system-ui, -apple-system, "SF Pro Text", "PingFang SC", "Noto Sans SC", "Helvetica Neue", sans-serif; + background-color: #0A0A0F; + background-image: + radial-gradient(circle at 18% -10%, rgba(139, 92, 246, 0.22), transparent 55%), + radial-gradient(circle at 88% 8%, rgba(59, 130, 246, 0.18), transparent 50%), + radial-gradient(circle at 50% 110%, rgba(217, 70, 239, 0.12), transparent 60%); + background-attachment: fixed; + min-height: 100vh; } +::selection { background: rgba(139, 92, 246, 0.35); color: #fff; } + +/* ===== Buttons ===== */ .btn { @apply inline-flex items-center justify-center gap-1.5 px-4 py-2 rounded-xl text-sm font-medium transition-all; } .btn-primary { - @apply bg-zinc-900 text-white hover:bg-zinc-800 active:scale-[0.98] shadow-sm; + @apply text-white bg-gradient-to-r from-violet-500 via-indigo-500 to-blue-500 hover:brightness-110 active:scale-[0.98]; + box-shadow: 0 6px 24px -8px rgba(99, 102, 241, 0.6), inset 0 1px 0 rgba(255,255,255,0.18); } .btn-ghost { - @apply bg-zinc-100 text-zinc-700 hover:bg-zinc-200 active:scale-[0.98]; + @apply text-white/80 bg-white/[0.05] hover:bg-white/[0.09] border border-white/[0.08] active:scale-[0.98]; } .btn-outline { - @apply bg-white text-zinc-700 border border-zinc-200 hover:border-zinc-300 hover:bg-zinc-50 active:scale-[0.98]; + @apply text-white/80 bg-white/[0.03] hover:bg-white/[0.07] border border-white/[0.1] hover:border-white/[0.18] active:scale-[0.98]; +} +.btn-glass { + @apply text-white bg-white/[0.06] hover:bg-white/[0.10] border border-white/[0.12] backdrop-blur-xl active:scale-[0.98]; } +/* ===== Cards (glass) ===== */ .card { - @apply bg-white border border-zinc-200/70 rounded-2xl shadow-[0_1px_2px_rgba(0,0,0,0.04),0_4px_12px_rgba(0,0,0,0.04)]; + @apply relative rounded-3xl bg-white/[0.035] border border-white/[0.08] backdrop-blur-xl; + box-shadow: + 0 1px 0 0 rgba(255,255,255,0.06) inset, + 0 18px 60px -24px rgba(0,0,0,0.6); +} +.card-2 { + @apply rounded-2xl bg-white/[0.03] border border-white/[0.07] backdrop-blur-xl; } .card-hover { - @apply transition-shadow hover:shadow-[0_2px_4px_rgba(0,0,0,0.04),0_8px_24px_rgba(0,0,0,0.06)]; + @apply transition-all hover:border-white/[0.14]; } +/* ===== Chips ===== */ .chip { - @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium; + @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[11px] font-medium border; } .chip-mock { - @apply bg-amber-50 text-amber-700 border border-amber-200; + @apply bg-amber-500/10 text-amber-300 border-amber-400/30; } .chip-live { - @apply bg-emerald-50 text-emerald-700 border border-emerald-200; + @apply bg-emerald-500/10 text-emerald-300 border-emerald-400/30; +} +.chip-neutral { + @apply bg-white/[0.05] text-white/70 border-white/[0.12]; +} +.chip-violet { + @apply bg-violet-500/15 text-violet-200 border-violet-400/30; } +/* ===== Segmented ===== */ .seg { - @apply inline-flex p-1 bg-zinc-100 rounded-xl gap-1; + @apply inline-flex p-1 bg-white/[0.04] border border-white/[0.07] rounded-xl gap-1; } .seg-item { - @apply px-3 py-1.5 rounded-lg text-xs font-medium text-zinc-600 transition-all cursor-pointer; + @apply px-3 py-1.5 rounded-lg text-xs font-medium text-white/55 transition-all cursor-pointer; } .seg-item-active { - @apply bg-white text-zinc-900 shadow-sm; + @apply text-white; + background: linear-gradient(135deg, rgba(139,92,246,0.35), rgba(59,130,246,0.25)); + box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 4px 16px -8px rgba(99,102,241,0.6); } +/* ===== Tiles ===== */ .tile { - @apply relative aspect-square overflow-hidden rounded-2xl bg-zinc-100 border-2 border-transparent ring-1 ring-zinc-200/70 transition-all cursor-pointer; + @apply relative aspect-square overflow-hidden rounded-2xl bg-white/[0.04] ring-1 ring-white/[0.08] transition-all cursor-pointer; } .tile-selected { - @apply border-zinc-900 ring-0 shadow-[0_4px_16px_rgba(0,0,0,0.12)]; + position: relative; + background: linear-gradient(#0A0A0F, #0A0A0F) padding-box, linear-gradient(135deg, #8B5CF6, #3B82F6) border-box; + border: 2px solid transparent; + box-shadow: 0 0 0 1px rgba(139,92,246,0.25), 0 8px 32px -8px rgba(139,92,246,0.55); } .tile-rejected { @apply opacity-30 grayscale; } .tile-keynum { - @apply absolute top-2 left-2 w-7 h-7 rounded-lg bg-white/95 backdrop-blur text-[11px] font-semibold text-zinc-700 flex items-center justify-center shadow-sm; + @apply absolute top-2 left-2 w-7 h-7 rounded-lg bg-black/60 backdrop-blur text-[11px] font-semibold text-white/85 flex items-center justify-center ring-1 ring-white/10; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; } .tile-badge { - @apply absolute top-2 right-2 w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold shadow-sm; + @apply absolute top-2 right-2 w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold; + box-shadow: 0 6px 18px -4px rgba(0,0,0,0.6); } .tile-badge-selected { - @apply bg-zinc-900 text-white; + background: linear-gradient(135deg, #8B5CF6, #3B82F6); + color: #fff; } .tile-badge-rejected { - @apply bg-red-500 text-white; + @apply bg-rose-500 text-white; } +/* ===== Fields ===== */ input, textarea { font-family: inherit; } .field { - @apply w-full bg-white border border-zinc-200 rounded-xl px-3.5 py-3 text-sm text-zinc-900 placeholder:text-zinc-400 transition-colors focus:border-zinc-900 focus:ring-2 focus:ring-zinc-900/5 outline-none resize-none; + @apply w-full rounded-xl px-3.5 py-3 text-sm text-white placeholder:text-white/30 outline-none resize-none transition-colors; + background: rgba(255,255,255,0.04); + border: 1px solid rgba(255,255,255,0.08); +} +.field:focus { + border-color: rgba(139, 92, 246, 0.55); + box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.12); } +/* ===== KBD ===== */ .kbd { - @apply inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 rounded bg-white border border-zinc-200 text-[10px] font-medium text-zinc-600 shadow-sm; + @apply inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 rounded text-[10px] font-medium text-white/70 ring-1 ring-white/10 bg-white/[0.06]; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; } + +/* ===== Section header ===== */ +.section-eyebrow { + @apply inline-block text-[10px] font-semibold uppercase tracking-[0.18em] text-violet-300/80; +} + +/* ===== Divider ===== */ +.divider-line { + @apply h-px w-full; + background: linear-gradient(to right, transparent, rgba(255,255,255,0.10), transparent); +} + +/* ===== Scrollbar (subtle) ===== */ +::-webkit-scrollbar { width: 10px; height: 10px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.06); border-radius: 8px; } +::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.12); } diff --git a/src/app/page.tsx b/src/app/page.tsx index be9dc04..82b95eb 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -176,7 +176,7 @@ export default function Home() { } return ( -
+
setSidebarOpen(v => !v)} @@ -186,20 +186,22 @@ export default function Home() { onNew={() => setCurrent(null)} />
-
+
-

- AI 玩具专利生成工作流 + AI Toy Workflow +

+ 把一句想法 + 变成专利、生产、宣发的素材包

-

- 批量出意向 → 快筛 → 多角度尺寸 → 喂专利 +

+ 批量出意向 · 九宫格快筛 · 锁定角色 · 一键三包 · Seedance 视频

-
- - - {provider === 'gpt' ? 'GPT · 最高规格' : provider === 'mock' ? 'Mock · 占位图' : provider} +
+ + + {provider === 'gpt' ? 'GPT · 最高规格' : provider === 'mock' ? 'Mock · 占位图' : provider === '?' ? '待连接' : provider}
@@ -207,15 +209,16 @@ export default function Home() {
{current && ( -
+
-

本次生成

-

+ Step · 02 · Quick Screen +

本次生成

+

{new Date(current.createdAt).toLocaleString('zh-CN')}

- {current.id} + {current.id}
= { - patent: '六面视图、45 度立体图和局部放大,用于外观专利素材整理。', + patent: '六面视图、45° 立体图和局部放大,用于外观专利素材整理。', production: '尺寸、材料、颜色、拆件和包装结构,用于工厂报价与打样沟通。', marketing: '白底商品图、场景图、细节图和社媒图,用于新品宣发。', }; +const PACK_ACCENT: Record = { + patent: { + ring: 'ring-violet-400/30', + chip: 'bg-violet-500/15 text-violet-200 border-violet-400/30', + dot: 'bg-violet-400', + bar: 'from-violet-400 to-indigo-400', + }, + production: { + ring: 'ring-amber-400/30', + chip: 'bg-amber-500/15 text-amber-200 border-amber-400/30', + dot: 'bg-amber-400', + bar: 'from-amber-400 to-orange-400', + }, + marketing: { + ring: 'ring-emerald-400/30', + chip: 'bg-emerald-500/15 text-emerald-200 border-emerald-400/30', + dot: 'bg-emerald-400', + bar: 'from-emerald-400 to-teal-400', + }, +}; + function manifestUrl(sessionId: string, kind: PackKind, version: string) { return `/api/export/${sessionId}_${kind}_${version}_manifest.json`; } @@ -40,26 +61,35 @@ export default function PackPanel({ if (!primaryImage) { return ( -
-

下一步素材包

-

- 先在上方九宫格选中一个主方案,再生成专利、生产和宣发模板包。 -

+
+
+
+
+ Step · 03 · Lock Character +

下一步素材包

+

+ 先在上方九宫格选中一个主方案,再生成专利、生产、宣发模板包,以及 Seedance 视频。 +

+
+
); } return ( -
+
-

角色锁定与素材包

-

- 当前以第一个选中图作为主方案,可先锁定角色,再全量生成三类素材包。 + Step · 03 · Lock Character +

角色锁定 & 素材包

+

+ 以第一个选中图作为主方案。先锁定角色设定,再全量生成三类素材包,所有图引用同一份 CharacterSpec 保持一致性。

-
+
selected source +
+
主方案
@@ -67,64 +97,88 @@ export default function PackPanel({
{session.characterSpec && ( -
-
+
+
-
{session.characterSpec.name}
-
{session.characterSpec.oneLiner}
+
{session.characterSpec.name}
+
{session.characterSpec.oneLiner}
- CharacterSpec + CharacterSpec · v1
-
-
形态:{session.characterSpec.speciesShape}
-
比例:{session.characterSpec.bodyRatio}
-
配色:{session.characterSpec.colorPalette.join('、')}
-
材料:{session.characterSpec.materials.join('、')}
+
+
+
形态{session.characterSpec.speciesShape}
+
比例{session.characterSpec.bodyRatio}
+
配色{session.characterSpec.colorPalette.join('、')}
+
材料{session.characterSpec.materials.join('、')}
)} -
+
{PACK_ORDER.map(kind => { const pack = packs.find(item => item.kind === kind && item.sourceImageId === primaryImage.id); const isLoading = loadingKind === kind; + const accent = PACK_ACCENT[kind]; return ( -
-
-
{PACK_LABELS[kind]}
-

{PACK_DESCRIPTIONS[kind]}

+
+
+
+
+
+
{PACK_LABELS[kind]}
+
+ {pack && {pack.version}}
+

{PACK_DESCRIPTIONS[kind]}

{pack && ( -
-
- 已生成 {pack.assets.length} 张 · {pack.version} +
+
+ 已生成 {pack.assets.length}
- 下载 manifest JSON + + + + 下载 manifest
)} @@ -134,48 +188,69 @@ export default function PackPanel({
{packs.length > 0 && ( -
- {packs.map(pack => ( -
-
-

{PACK_LABELS[pack.kind]} · {pack.assets.length} 张

- {pack.id} -
-
- {pack.assets.map(asset => ( -
-
- {asset.title} -
-
-
{asset.title}
-
{asset.view}
-
+
+ {packs.map(pack => { + const accent = PACK_ACCENT[pack.kind]; + return ( +
+
+
+
+

+ {PACK_LABELS[pack.kind]} · {pack.assets.length} 张 +

- ))} + {pack.id} +
+
+ {pack.assets.map(asset => ( +
+
+ {asset.title} +
+
+
{asset.title}
+
{asset.view}
+
+ {asset.required && ( + + 必备 + + )} +
+ ))} +
-
- ))} + ); + })}
)} -
-
-
Seedance 视频
-

- 视频固定走 Seedance。这里先用当前主方案生成标准宣发/展示短片任务。 -

+
+
+
+
+
+
+
Seedance 视频
+
+

+ 视频固定走 Seedance · 用当前主方案生成宣发/展示短片 +

+
+ 异步任务
-
+
{VIDEO_TEMPLATES.map(template => ( ))}
diff --git a/src/components/PromptPanel.tsx b/src/components/PromptPanel.tsx index 878b333..b74302f 100644 --- a/src/components/PromptPanel.tsx +++ b/src/components/PromptPanel.tsx @@ -38,9 +38,14 @@ export default function PromptPanel({ onGenerate, loading }: PromptPanelProps) { } return ( -
+
+
+ Step · 01 · Ideation + · 描述意向 + 数量 + 风格 +
+
-