You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

14 KiB

打光功能实施文档

Version: 0.1 Status: Draft Scope: popiart-node-canvas Target area: bottom composer, image node controls only

1. 目标

在底部 composer 的图片节点控制区中新增「打光」入口,尺寸、布局、交互状态与现有「风格」「标记」「聚焦」「参考」保持一致。

该功能是图片节点专有能力,只在当前选中图片节点时出现或可用。这里的图片节点包含 imageInput 图片输入节点和 nanoBanana 图片生成节点。用户必须先上传图片,或当前图片节点已有可编辑图片素材后,才能点击「打光」按钮。点击后弹出「打光效果」面板,用户可以调整全局打光参数、选择主光源方向、开启轮廓光,并在智能模式中输入描述、上传打光参考图、选择预设打光效果。

当前版本不扩展到视频、音频、3D 或其它媒体节点。

2. 用户体验

2.1 底部入口

在底部 composer 顶部功能格子区域新增「打光」按钮:

  • 位置建议:放在「聚焦」之后、「参考」之前。
  • 尺寸:与现有格子一致,当前实现约为 h-14 w-16
  • 可见范围:
    • 仅当前 composer 处于图片节点模式时显示,包括 imageInputnanoBanana
    • 非图片节点、流程处理节点、多选状态、空创建状态不显示。
  • 可点击条件:
    • 当前图片节点已经有至少一张上传图片或可编辑图片素材。
    • imageInput 判断 data.image 是否存在。
    • nanoBanana 判断 draft.inputImages.length > 0,并兼容当前节点已有 outputImage 或上游连接图片的场景。
    • 如果没有图片,按钮保持禁用,不弹窗。
  • 状态:
    • 默认:深色背景、灰色文字、灰色描边。
    • Hover:提高描边和文字亮度。
    • 激活:使用与其它 active chip 一致的 cyan 高亮。
    • 不可用:没有上传图片时禁用,title 提示 请先上传图片
  • 文案:
    • 中文:打光
    • 图标:优先使用 lucide 图标,如 Sun, Lightbulb, SparklesFlashlight;如果项目当前没有 lucide,可先沿用现有符号风格,后续统一替换。

2.2 弹窗基础模式

点击可用状态下的「打光」打开居中的「打光效果」弹窗。基础模式内容对应示意图三:

  • 标题:打光效果
  • 关闭按钮:右上角。
  • 左侧预览区:
    • 顶部为视角切换:透视 / 正面
    • 中间为球形/空间光照预览图。
    • 底部为 重置参数
  • 右侧参数区:
    • 分组标题:全局
    • 智能模式 开关,默认关闭。
    • 亮度 slider。
    • 亮度百分比输入或只读显示,默认 50%
    • 颜色 色块选择,默认白色。
    • 主光源 方向按钮:
      • 左侧
      • 顶部
      • 右侧
      • 前方
      • 底部
      • 后方
    • 轮廓光 开关,默认关闭。
  • 底部右侧:
    • 成本提示,如 14
    • 生成/应用按钮,沿用 composer 的上箭头视觉。

2.3 智能模式

开启 智能模式 后弹窗横向扩展,对应示意图四:

  • 保留左侧预览区。
  • 中间保留 全局 参数区。
  • 右侧新增智能模式区:
    • 标题:智能模式
    • 文本输入框,占一整行宽度,placeholder:
      • 简单描述你想实现的打光效果,或者情绪风格
    • 打光参考图 上传按钮。
    • 预设 网格。
  • 预设建议首批 8 个:
    • 过曝胶片
    • 蓝色逆光
    • 伦勃朗光
    • 赛博朋克
    • 落日迷幻
    • 神秘暗调
    • 黄金时刻
    • 清晨冷灰
  • 每个预设包含:
    • id
    • label
    • thumbnail
    • prompt fragment
    • structured lighting patch

3. 数据模型

新增打光参数类型,建议放在 src/types/nodes.ts 或单独 src/types/lighting.ts 后再导出。

export type LightingViewMode = "perspective" | "front";
export type LightingDirection = "left" | "top" | "right" | "front" | "bottom" | "back";

export interface LightingPreset {
  id: string;
  label: string;
  thumbnail: string;
  prompt: string;
  settings: Partial<LightingSettings>;
}

export interface LightingSettings {
  enabled: boolean;
  viewMode: LightingViewMode;
  smartMode: boolean;
  brightness: number;
  color: string;
  mainLightDirection: LightingDirection;
  rimLight: boolean;
  smartPrompt: string;
  referenceImage: string | null;
  selectedPresetId: string | null;
}

NanoBananaNodeData 增加:

lighting?: LightingSettings;

默认值建议放在 src/store/utils/nodeDefaults.ts

export const DEFAULT_LIGHTING_SETTINGS: LightingSettings = {
  enabled: false,
  viewMode: "perspective",
  smartMode: false,
  brightness: 50,
  color: "#ffffff",
  mainLightDirection: "front",
  rimLight: false,
  smartPrompt: "",
  referenceImage: null,
  selectedPresetId: null,
};

4. 文件拆分建议

4.1 新增组件

新增目录:

src/components/lighting/

建议文件:

  • LightingEffectModal.tsx
    • 弹窗容器和整体布局。
  • LightingPreview.tsx
    • 左侧光照预览。
    • 第一版可用 CSS/SVG/Canvas 静态模拟,不必接真实 3D。
  • LightingControls.tsx
    • 亮度、颜色、方向、轮廓光。
  • LightingSmartPanel.tsx
    • 智能模式输入、参考图、预设网格。
  • lightingPresets.ts
    • 预设配置。
  • index.ts
    • 统一导出。

4.2 修改现有文件

  • src/components/composer/GenerationComposer.tsx
    • 增加 active chip 类型:"lighting"
    • 在图片节点模式的功能格子区域插入「打光」按钮。
    • 增加是否允许打光的派生状态,例如 canOpenLightingPanel
    • 当没有上传图片或可编辑图片素材时禁用按钮。
    • 管理 LightingEffectModal 打开/关闭。
    • 从当前 draft 或当前节点数据中读取 lighting。
    • 应用弹窗保存结果到当前 composer draft。
  • src/types/nodes.ts
    • 新增 LightingSettings 类型或从 types/lighting.ts 导入。
    • NanoBananaNodeData 增加 lighting?: LightingSettings
  • src/store/utils/nodeDefaults.ts
    • 给图片节点补默认 lighting
  • src/store/execution/nanoBananaExecutor.ts
    • lighting 转成 prompt 增强或 provider 参数。
  • src/components/__tests__/...
    • 增加 composer 入口和弹窗交互测试。

5. 与生成链路的关系

第一阶段不要改 provider 协议,先采用 prompt 增强方式。该增强只作用于图片节点生成:

function buildLightingPrompt(settings: LightingSettings): string {
  if (!settings.enabled) return "";
  // 根据方向、亮度、颜色、轮廓光、智能描述、预设 prompt 拼接自然语言。
}

图片生成执行时:

  1. 读取 NanoBananaNodeData.inputPrompt
  2. 读取 NanoBananaNodeData.lighting
  3. 确认当前节点有可编辑图片输入;没有图片时不启用 lighting。
  4. 生成 lighting prompt fragment。
  5. 将 fragment 附加到最终 prompt。

示例:

Lighting: front key light, 50% brightness, white color temperature, soft cinematic illumination, rim light disabled.

如果智能模式开启:

Lighting style: {smartPrompt}. Use the selected lighting preset: {presetPrompt}.

如果有参考图:

  • 第一版:把 reference image 加入 inputImagesdynamicInputs 前要谨慎,避免改变原始参考图语义。
  • 推荐第一版只保存,不传给 provider。
  • 第二阶段再支持「参考图作为打光参考」的 provider-specific 参数。

6. 分阶段实施计划

Phase 1: 文档与类型

目标:先定义功能边界,不改变运行行为。

任务:

  • 新增本文档。
  • 新增 LightingSettings 类型。
  • 在图片节点数据结构中加入可选 lighting
  • 新增默认 lighting 配置。

验收:

  • TypeScript 类型通过。
  • 旧 workflow 不需要迁移也能正常打开,因为 lighting 是可选字段。

Phase 2: 底部 composer 入口

目标:图片节点底部出现「打光」格子,并且只有上传图片后才能打开弹窗。

任务:

  • 扩展 activeChip 类型。
  • 添加「打光」按钮,尺寸与其它按钮一致。
  • 仅在图片节点模式显示「打光」按钮。
  • 计算当前图片节点是否已经上传图片。
  • 没有图片时禁用按钮并显示 请先上传图片 提示。
  • 新增 LightingEffectModal 的基础 shell。
  • 点击可用按钮打开弹窗。
  • 关闭按钮可关闭弹窗。

验收:

  • 底部「打光」按钮和其它格子同宽同高。
  • 非图片节点看不到「打光」按钮。
  • 图片节点没有上传图片时,「打光」按钮不可点击。
  • 图片节点上传图片后,「打光」按钮可点击。
  • 按钮 active 状态可见。
  • 弹窗打开和关闭稳定。

Phase 3: 基础参数 UI

目标:完成示意图三的基础模式。

任务:

  • 实现标题、关闭按钮、左右布局。
  • 实现视角切换。
  • 实现静态光照预览。
  • 实现亮度 slider。
  • 实现颜色选择。
  • 实现主光源方向按钮组。
  • 实现轮廓光开关。
  • 实现重置参数。
  • 实现保存/应用按钮。

验收:

  • 所有控件都有受控状态。
  • 重置后恢复默认值。
  • 应用后写入当前图片节点的 data.lighting
  • 关闭再打开能读回当前节点保存的值。
  • 如果上传图片被移除,弹窗不能再次打开。

Phase 4: 智能模式 UI

目标:完成示意图四的智能模式完整面板。

任务:

  • 开启智能模式后扩展弹窗宽度。
  • 添加智能描述输入框。
  • 添加打光参考图上传按钮。
  • 添加 8 个预设卡片。
  • 点击预设后:
    • 设置 selectedPresetId
    • 合并预设 settings
    • 写入或追加 smartPrompt
  • 上传参考图后显示缩略状态。

验收:

  • 智能模式开关不会丢失基础参数。
  • 预设选中状态清晰。
  • 参考图可上传、替换、清除。

Phase 5: 生成执行接入

目标:打光参数实际影响图片生成。

任务:

  • 新增 buildLightingPrompt(settings) 工具函数。
  • nanoBananaExecutor 或 prompt 构造点追加 lighting fragment。
  • 确保未启用 lighting 时生成结果与旧逻辑一致。
  • 对智能模式、预设、亮度、方向分别加单元测试。

验收:

  • enabled: false 不改变请求 prompt。
  • enabled: true 会附加明确的 lighting 描述。
  • 智能模式描述会进入最终 prompt。
  • 预设 prompt 会进入最终 prompt。

Phase 6: 测试与回归

目标:确保不会破坏 composer、节点编辑和保存加载。

建议测试:

  • GenerationComposer.test.tsx
    • 渲染打光按钮。
    • 点击打开弹窗。
    • 应用参数调用 updateNodeData
  • LightingEffectModal.test.tsx
    • 控件初始值。
    • 亮度/颜色/方向/轮廓光交互。
    • 智能模式展开。
    • 预设选择。
  • nodeDefaults.test.ts
    • 图片节点默认包含 lighting。
  • nanoBananaExecutor.test.ts
    • lighting prompt 拼接。
  • workflowStore.integration.test.ts
    • 保存/加载旧 workflow 不报错。

7. 实现细节

7.1 Composer 状态同步

现有 composer 有本地 draft 和 dirty fields。打光弹窗建议不要直接每次改控件就写 store,而是:

  1. 打开弹窗时从当前节点读取 lighting。
  2. 弹窗内部维护临时状态。
  3. 点击应用后调用 composer 的 patch/update。
  4. 如果当前没有图片节点,或当前图片节点没有上传图片,则不允许打开弹窗,也不写入 draft。

这样可以避免用户在弹窗里试参数时频繁污染 undo history。

7.2 旧工作流兼容

读取时始终使用:

const lighting = data.lighting ?? DEFAULT_LIGHTING_SETTINGS;

保存时只有用户打开并应用后才写入,避免旧工作流文件无意义膨胀。

7.3 预览实现策略

第一版建议用轻量 CSS/SVG:

  • 一个圆形背景模拟空间球。
  • 一张竖向图片卡片作为主体。
  • 根据 mainLightDirection 改变光束渐变角度。
  • 根据 brightness 改变光束 opacity。
  • 根据 color 改变光束颜色。
  • rimLight 开启时给主体卡片增加边缘高光。

后续如果需要真实 3D 预览,再引入 Three.js,但第一版不建议增加复杂度。

8. 风险与注意事项

  • 不要把打光功能做成隐藏的新节点。当前需求是图片节点的 composer 参数入口,不是图节点类型。
  • 不要在空创建模式、视频节点、音频节点、3D 节点或流程处理节点上开放打光入口。
  • 不要在没有上传图片时弹出打光面板。
  • 不要让弹窗直接调用生成接口。生成仍然由现有 composer/节点执行按钮触发。
  • 不要把参考图默认混入 inputImages,否则可能改变图片生成语义。
  • 不要一次性重构整个 GenerationComposer.tsx。这个文件已经很大,应先最小接入,后续再拆。
  • 注意中文文案编码,当前仓库已有部分乱码,新增文件必须使用 UTF-8。

9. 推荐提交顺序

  1. docs: add lighting effect implementation plan
  2. feat: add lighting settings types and defaults
  3. feat: add lighting chip to generation composer
  4. feat: add lighting effect modal basic controls
  5. feat: add lighting smart mode presets
  6. feat: apply lighting settings to image generation prompt
  7. test: cover lighting composer and executor behavior

10. 最小可交付版本

MVP 包含:

  • 图片节点底部「打光」格子。
  • 未上传图片时按钮禁用。
  • 上传图片后点击按钮弹出打光面板。
  • 点击打开弹窗。
  • 亮度、颜色、主光源方向、轮廓光。
  • 参数保存到当前图片节点。
  • 生成时把打光参数拼入 prompt。

智能模式、预设缩略图、参考图上传可以作为第二个增量交付。