Files
jiapuapp/docs/superpowers/plans/2026-07-15-a01-layered-psd-assets.md
T
2026-07-16 07:58:53 +08:00

17 KiB
Raw Blame History

A01 分层 PSD 与正式 PNG 资产实施计划

执行要求: 只允许在当前会话内使用 superpowers:executing-plans 逐任务执行。用户明确禁止子代理、worktree、git addcommitpushresetcheckout 和上传,因此本计划不包含这些动作;每个任务以测试输出和用户视觉确认作为检查点。

目标: 使用本机 Adobe Photoshop 2021 建立 A01 真正分层的 PSD,并从同一 PSD 导出可直接投入 uni-app 的干净 PNG 资产与密码/验证码代表图。

架构: a01-psd-manifest.json 是 PSD 图层、坐标、导出尺寸和文件路径的唯一机器可读所有者;PowerShell 负责校验环境并调用 Photoshop COMExtendScript 负责建立 PSD、切换状态和导出。ImageGen 只逐项生成缺少的原始美术层,所有候选先进入设计候选目录,经检查和用户确认后才进入 PSD 与正式资产目录。

技术栈: Windows PowerShell、Adobe Photoshop 2021 COM、ExtendScript JSX、PNG/PSD、ImageGen、uni-app 现有 PowerShell 合同测试。

全局约束

  • 当前只处理 A01 分层 PSD 和 PNG 资产,不修改 pages/auth/a01-entry.vue,不进行接口对接。
  • 不使用 Figma,不把整张效果图作为页面资产,不从扁平图硬裁被遮挡的脏素材。
  • PSD 工作画布为 1236 × 2745,对应 412 × 915 的三倍密度基准。
  • brand-seal 唯一来源为 static/assets/foundation/transparent/brand-seal.png
  • 宗祠背景不得生成空牌匾、替代牌匾或新 Logo 底座;现有 brand-seal.png 直接作为独立图层叠放在宗祠中央。
  • 密码锁唯一复用来源为 static/assets/modules/auth/transparent/a01-icon-lock-v1.png
  • 闭眼图标必须保留中心瞳孔;短信验证码图标必须是消息气泡加且仅加三个点。
  • 密码和验证码为独立图层组,共用背景、卷轴、品牌和按钮资产。
  • 所有生成资产先写入 docs/design/assets/a01-vnext/candidates/,不得覆盖现有候选或正式文件。
  • Photoshop 自动化不得保存、关闭或覆盖用户原先打开的文档,只处理脚本自己创建或打开的临时文档。
  • 没有 PSD 图层复核、PNG Alpha 检查、412 × 915 代表图和用户确认,不得宣称资产完成。

文件边界

新建:

  • docs/design/assets/a01-vnext/source/a01-psd-manifest.json:图层、组、位置、状态和导出规格的唯一机器可读所有者。
  • docs/design/assets/a01-vnext/source/A01-layered-source-v1.psd:最终分层源文件。
  • scripts/photoshop/a01-build-layered-psd.jsx:按清单建立 PSD、组和图层。
  • scripts/photoshop/a01-export-layered-assets.jsx:从 PSD 导出 PNG 与四状态代表图。
  • scripts/build-a01-layered-psd.ps1:验证环境和路径后调用构建 JSX。
  • scripts/export-a01-layered-assets.ps1:调用导出 JSX 并校验输出。
  • tests/a01-layered-psd-contract.ps1:审计清单、脚本、PSD 和 PNG 契约。
  • docs/design/assets/a01-vnext/review/:透明检查图、联系表和代表图候选。

仅在资产通过用户确认后修改:

  • docs/design/A01_启动登录引导_设计记录.md
  • docs/design/P00_页面结构与资产清单.md
  • docs/交接记录.md

本计划禁止修改:

  • pages/auth/a01-entry.vue
  • pages.json
  • A01 之外的页面、测试和资产

任务 1:建立 PSD 资产契约测试

文件:

  • 新建:tests/a01-layered-psd-contract.ps1
  • 读取:docs/superpowers/specs/2026-07-15-a01-layered-psd-assets-design.md

接口: 缺少文件或契约时抛出明确错误;全部满足时输出 A01-LAYERED-PSD-CONTRACT PASS

  • 步骤 1:编写失败测试

测试至少包含以下可执行断言:

$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$requiredFiles = @(
  'docs/design/assets/a01-vnext/source/a01-psd-manifest.json',
  'scripts/build-a01-layered-psd.ps1',
  'scripts/export-a01-layered-assets.ps1',
  'scripts/photoshop/a01-build-layered-psd.jsx',
  'scripts/photoshop/a01-export-layered-assets.jsx'
)
foreach ($relative in $requiredFiles) {
  if (-not (Test-Path -LiteralPath (Join-Path $root $relative))) {
    throw "Missing layered PSD contract file: $relative"
  }
}
$manifestPath = Join-Path $root $requiredFiles[0]
$manifest = Get-Content -Raw -Encoding UTF8 -LiteralPath $manifestPath | ConvertFrom-Json
if ($manifest.canvas.width -ne 1236 -or $manifest.canvas.height -ne 2745) {
  throw 'PSD canvas must be 1236x2745.'
}
foreach ($group in @('00-参考','10-背景','20-卷轴','30-品牌与标题装饰','40-公共控件皮肤','50-密码登录','60-验证码登录','70-内容与标注')) {
  if ($manifest.groups.name -notcontains $group) { throw "Missing PSD group: $group" }
}
foreach ($state in @('password-hidden','password-visible','sms-default','sms-countdown')) {
  if ($manifest.states.name -notcontains $state) { throw "Missing PSD state: $state" }
}
Write-Output 'A01-LAYERED-PSD-CONTRACT PASS'
  • 步骤 2:运行测试并确认按预期失败
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1

预期:失败并显示 Missing layered PSD contract file

  • 步骤 3:观察并保留工作区状态
git status --short

预期:只记录输出,不清理、暂存或提交任何文件。


任务 2:建立清单和 Photoshop 自动化空壳

文件:

  • 新建:docs/design/assets/a01-vnext/source/a01-psd-manifest.json
  • 新建:scripts/build-a01-layered-psd.ps1
  • 新建:scripts/export-a01-layered-assets.ps1
  • 新建:scripts/photoshop/a01-build-layered-psd.jsx
  • 新建:scripts/photoshop/a01-export-layered-assets.jsx
  • 测试:tests/a01-layered-psd-contract.ps1

接口:

  • 清单提供 canvasgroupslayersstatesexports

  • build-a01-layered-psd.ps1 -ManifestPath <path> -OutputPath <path> 使用 Photoshop.Application.150

  • export-a01-layered-assets.ps1 -ManifestPath <path> -PsdPath <path> 使用同一 COM 接口。

  • JSX 从 JIAPU_A01_ROOTJIAPU_A01_MANIFESTJIAPU_A01_PSD 读取路径,不硬编码用户名。

  • 步骤 1:创建最小清单

{
  "schemaVersion": 1,
  "canvas": { "width": 1236, "height": 2745, "logicalWidth": 412, "logicalHeight": 915, "scale": 3 },
  "groups": [
    { "name": "00-参考", "visible": false },
    { "name": "10-背景", "visible": true },
    { "name": "20-卷轴", "visible": true },
    { "name": "30-品牌与标题装饰", "visible": true },
    { "name": "40-公共控件皮肤", "visible": true },
    { "name": "50-密码登录", "visible": true },
    { "name": "60-验证码登录", "visible": false },
    { "name": "70-内容与标注", "visible": true }
  ],
  "layers": [],
  "states": [
    { "name": "password-hidden", "show": ["50-密码登录"], "hide": ["60-验证码登录"] },
    { "name": "password-visible", "show": ["50-密码登录"], "hide": ["60-验证码登录"] },
    { "name": "sms-default", "show": ["60-验证码登录"], "hide": ["50-密码登录"] },
    { "name": "sms-countdown", "show": ["60-验证码登录"], "hide": ["50-密码登录"] }
  ],
  "exports": []
}
  • 步骤 2:创建 PowerShell COM 包装

核心调用固定为:

$app = New-Object -ComObject 'Photoshop.Application.150'
$env:JIAPU_A01_ROOT = $root
$env:JIAPU_A01_MANIFEST = $resolvedManifest
$env:JIAPU_A01_PSD = $resolvedOutput
$jsx = (Resolve-Path -LiteralPath (Join-Path $root 'scripts/photoshop/a01-build-layered-psd.jsx')).Path
$escaped = $jsx.Replace('\', '\\')
$app.DoJavaScript("$.evalFile(new File('$escaped'));", @(), 1)

调用前验证 Photoshop 正在运行、输入输出位于项目根目录,并拒绝覆盖不符合 A01-layered-source-v*.psd 的文件。

  • 步骤 3:创建 JSX 空壳构建器
#target photoshop
app.displayDialogs = DialogModes.NO;
var created = null;
try {
  var manifestFile = File($.getenv('JIAPU_A01_MANIFEST'));
  var psdFile = File($.getenv('JIAPU_A01_PSD'));
  manifestFile.encoding = 'UTF8';
  manifestFile.open('r');
  var manifest = eval('(' + manifestFile.read() + ')');
  manifestFile.close();
  created = app.documents.add(manifest.canvas.width, manifest.canvas.height, 72, 'JIAPU_A01_SCRIPT_SOURCE', NewDocumentMode.RGB, DocumentFill.TRANSPARENT);
  for (var i = 0; i < manifest.groups.length; i++) {
    var group = created.layerSets.add();
    group.name = manifest.groups[i].name;
    group.visible = manifest.groups[i].visible;
  }
  var options = new PhotoshopSaveOptions();
  options.layers = true;
  created.saveAs(psdFile, options, true, Extension.LOWERCASE);
  created.close(SaveOptions.DONOTSAVECHANGES);
  created = null;
} catch (error) {
  if (created) { created.close(SaveOptions.DONOTSAVECHANGES); }
  throw error;
}
  • 步骤 4:运行契约测试
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1

预期:A01-LAYERED-PSD-CONTRACT PASS

  • 步骤 5:运行空壳 PSD 冒烟检查
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/build-a01-layered-psd.ps1

预期:生成 docs/design/assets/a01-vnext/source/A01-layered-source-v1.psd,Photoshop 中包含八个命名组;脚本执行前已打开的用户文档未被保存或关闭。


任务 3:制作三类母图并由 Photoshop 拆出干净图层

文件:

  • 新建候选:docs/design/assets/a01-vnext/candidates/ 下的版本化 PNG
  • 修改:docs/design/assets/a01-vnext/source/a01-psd-manifest.json
  • 新建检查图:docs/design/assets/a01-vnext/review/

接口: ImageGen 只生成完整无字卷轴、无字按钮与装饰板、四枚功能图标板三类母图;Photoshop 将母图拆成每个只承载一个清单图层的 PNG。每个 layers 项包含 namegroupsourcexywidthheightvisibleexportNamealpha

  • 步骤 1:制作宗祠背景候选

使用用户已认可的宗祠母图,不再重新生成。保留 ImageGen 原始母图,再由 Photoshop 裁剪为 1236 × 510 候选;现有 brand-seal.png 后续作为独立图层叠放。

验收:中央为 brand-seal 留出干净视觉空间,但建筑本身不出现空牌匾、替代牌匾或新 Logo 底座;四边没有被截断的文字或控件。

  • 步骤 2:生成一张完整无字卷轴母图并拆分

一次生成完整无字卷轴母图,使用可清除的纯色背景。Photoshop 从同一母图拆出顶部卷轴、无字宣纸平铺纹理、左边框、右边框和底部卷轴,不从完整登录页面截图裁切。

验收:在纯黑、纯白和项目暖宣纸底色上检查透明边缘;拼接处没有亮线、断纹或重复阴影。

  • 步骤 3:生成一张无字按钮与装饰母图并拆分

主按钮先形成无字完整皮肤,再由 Photoshop 分出左端、可横向延展中段和右端;标题云纹、分隔纹样和四角回纹分别独立。

验收:按钮三段重新拼接后与完整皮肤一致;所有纹样不包含文字、Logo 或不可复用背景。

  • 步骤 4:生成一张四图标母板并拆分

在同一高分辨率纯色背景母板中生成彼此完全分离的手机、睁眼、保留瞳孔的闭眼、短信气泡三点图标,再由 Photoshop 分别导出;密码锁继续引用 a01-icon-lock-v1.pngLogo 继续引用 brand-seal.png。微信标志不由 ImageGen 重绘,继续使用具有来源记录的项目资产,只重新制作其容器皮肤。

验收:目标显示尺寸下仍清楚;短信气泡只有三个点;闭眼中心瞳孔可见。

  • 步骤 5:每类输出一张检查联系表并等待确认

联系表包含原尺寸、白底、黑底和页面底色预览。未收到用户确认前,不把该类候选写入正式导出清单,也不修改 A01 页面。


任务 4:组装真实 PSD

文件:

  • 修改:docs/design/assets/a01-vnext/source/a01-psd-manifest.json
  • 修改:scripts/photoshop/a01-build-layered-psd.jsx
  • 生成:docs/design/assets/a01-vnext/source/A01-layered-source-v1.psd
  • 测试:tests/a01-layered-psd-contract.ps1

接口: JSX 读取 layers,打开 PNG,复制到目标组并设置名称、位置和可见性。目标层名与 exportName 一一对应;每次从清单重建,不在旧 PSD 上堆叠。

  • 步骤 1:扩展失败测试

验证每个源文件存在,坐标和尺寸为整数,源路径位于工作区,exportName 唯一,且可导出层属于 1060 的合法组。

  • 步骤 2:先运行测试确认不完整清单失败
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1

预期:报告第一项缺失或重复的图层契约。

  • 步骤 3:实现 PNG 导入与精确定位

JSX 只复制脚本打开的源 PNG 合并像素层,复制后立即关闭源文档且不保存;位置按 x × 3y × 3 和清单目标尺寸设置,不手工拖动猜测。

  • 步骤 4:重建并复核 PSD
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/build-a01-layered-psd.ps1

预期:八个组顺序正确,密码和验证码可单独显示,公共图层只有一份,参考图默认隐藏。

  • 步骤 5:确认用户原文档未受影响

检查 Photoshop:脚本运行前用户已打开文档的数量、名称和未保存状态保持不变;脚本临时文档已关闭。


任务 5:从 PSD 导出 PNG 与四状态代表图

文件:

  • 修改:scripts/photoshop/a01-export-layered-assets.jsx
  • 生成候选:docs/design/assets/a01-vnext/exports/v1/
  • 生成联系表:docs/design/assets/a01-vnext/review/A01-layered-states-v1-contact-sheet.png
  • 测试:tests/a01-layered-psd-contract.ps1

接口: exports 定义来源层、裁切矩形、尺寸、Alpha 和文件名;四状态固定为 password-hiddenpassword-visiblesms-defaultsms-countdown

  • 步骤 1:添加导出失败测试

验证每个 exports.path 存在、PNG 文件头正确、像素尺寸与清单一致;透明资产四角 Alpha 为 0,不透明资产四角 Alpha 为 255。未执行导出时测试必须失败。

  • 步骤 2:实现独立图层导出

JSX 打开 PSD 后记录原可见性,只显示目标层或组,按清单矩形复制到新的透明临时文档并保存 PNG;完成后关闭脚本打开的 PSD 副本且不写回可见性变化。

  • 步骤 3:实现四状态代表图和联系表

按清单切换密码/验证码组以及眼睛、倒计时等状态专用层,分别导出 412 × 915 预览,再组合为一张两行两列联系表。代表图只进入 review,页面不得引用。

  • 步骤 4:运行导出验证
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/export-a01-layered-assets.ps1
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1
git diff --check

预期:导出成功,合同输出 A01-LAYERED-PSD-CONTRACT PASS,无新增空白错误。

  • 步骤 5:只展示一张联系表并等待用户确认

确认宗祠、卷轴、按钮、图标、密码/验证码状态和公共区域。用户未明确通过前,导出仍是候选,不复制到 static/assets,不修改页面。


任务 6:冻结资产证据并停在页面实施门禁前

文件:

  • 修改:docs/design/A01_启动登录引导_设计记录.md
  • 修改:docs/design/P00_页面结构与资产清单.md
  • 修改:docs/交接记录.md
  • 保留:docs/design/assets/a01-vnext/source/A01-layered-source-v1.psd
  • 保留:docs/design/assets/a01-vnext/exports/v1/

接口: A01 设计记录拥有用户视觉决定;P00 拥有正式资产路径、尺寸、Alpha 和引用状态;交接记录只保存真实停点。

  • 步骤 1:记录文件证据
Get-FileHash -Algorithm SHA256 docs/design/assets/a01-vnext/source/A01-layered-source-v1.psd
Get-ChildItem docs/design/assets/a01-vnext/exports/v1 -File | Get-FileHash -Algorithm SHA256

把 PSD 和已确认 PNG 的哈希、尺寸、Alpha、用途写入 A01 设计记录和 P00。

  • 步骤 2:更新真实状态

只能写“PSD 与 PNG 资产已获用户确认,A01 页面实现尚未开始”或事实对应的更早状态;不得写 A01 已验收、已冻结或页面已完成。

  • 步骤 3:运行最终验证
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-a02-ui-contract.ps1
git diff --check
git status --short
git status --short --ignored

预期:PSD 合同通过;既有 A01/A02 合同保持当前事实,若因页面尚未切换而失败则如实记录、不改页面;所有既有修改和未跟踪文件继续保留。

  • 步骤 4:停止

只有用户再次确认进入页面落地,才新建独立的 A01 image-to-code/TDD 实施计划;不得在本计划中顺手修改页面。