381 lines
17 KiB
Markdown
381 lines
17 KiB
Markdown
# A01 分层 PSD 与正式 PNG 资产实施计划
|
||
|
||
> **执行要求:** 只允许在当前会话内使用 `superpowers:executing-plans` 逐任务执行。用户明确禁止子代理、worktree、`git add`、`commit`、`push`、`reset`、`checkout` 和上传,因此本计划不包含这些动作;每个任务以测试输出和用户视觉确认作为检查点。
|
||
|
||
**目标:** 使用本机 Adobe Photoshop 2021 建立 A01 真正分层的 PSD,并从同一 PSD 导出可直接投入 uni-app 的干净 PNG 资产与密码/验证码代表图。
|
||
|
||
**架构:** `a01-psd-manifest.json` 是 PSD 图层、坐标、导出尺寸和文件路径的唯一机器可读所有者;PowerShell 负责校验环境并调用 Photoshop COM,ExtendScript 负责建立 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:编写失败测试**
|
||
|
||
测试至少包含以下可执行断言:
|
||
|
||
```powershell
|
||
$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
|
||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1
|
||
```
|
||
|
||
预期:失败并显示 `Missing layered PSD contract file`。
|
||
|
||
- [ ] **步骤 3:观察并保留工作区状态**
|
||
|
||
```powershell
|
||
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`
|
||
|
||
**接口:**
|
||
|
||
- 清单提供 `canvas`、`groups`、`layers`、`states`、`exports`。
|
||
- `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_ROOT`、`JIAPU_A01_MANIFEST`、`JIAPU_A01_PSD` 读取路径,不硬编码用户名。
|
||
|
||
- [ ] **步骤 1:创建最小清单**
|
||
|
||
```json
|
||
{
|
||
"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 包装**
|
||
|
||
核心调用固定为:
|
||
|
||
```powershell
|
||
$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 空壳构建器**
|
||
|
||
```javascript
|
||
#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
|
||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1
|
||
```
|
||
|
||
预期:`A01-LAYERED-PSD-CONTRACT PASS`。
|
||
|
||
- [ ] **步骤 5:运行空壳 PSD 冒烟检查**
|
||
|
||
```powershell
|
||
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` 项包含 `name`、`group`、`source`、`x`、`y`、`width`、`height`、`visible`、`exportName`、`alpha`。
|
||
|
||
- [ ] **步骤 1:制作宗祠背景候选**
|
||
|
||
使用用户已认可的宗祠母图,不再重新生成。保留 ImageGen 原始母图,再由 Photoshop 裁剪为 `1236 × 510` 候选;现有 `brand-seal.png` 后续作为独立图层叠放。
|
||
|
||
验收:中央为 `brand-seal` 留出干净视觉空间,但建筑本身不出现空牌匾、替代牌匾或新 Logo 底座;四边没有被截断的文字或控件。
|
||
|
||
- [ ] **步骤 2:生成一张完整无字卷轴母图并拆分**
|
||
|
||
一次生成完整无字卷轴母图,使用可清除的纯色背景。Photoshop 从同一母图拆出顶部卷轴、无字宣纸平铺纹理、左边框、右边框和底部卷轴,不从完整登录页面截图裁切。
|
||
|
||
验收:在纯黑、纯白和项目暖宣纸底色上检查透明边缘;拼接处没有亮线、断纹或重复阴影。
|
||
|
||
- [ ] **步骤 3:生成一张无字按钮与装饰母图并拆分**
|
||
|
||
主按钮先形成无字完整皮肤,再由 Photoshop 分出左端、可横向延展中段和右端;标题云纹、分隔纹样和四角回纹分别独立。
|
||
|
||
验收:按钮三段重新拼接后与完整皮肤一致;所有纹样不包含文字、Logo 或不可复用背景。
|
||
|
||
- [ ] **步骤 4:生成一张四图标母板并拆分**
|
||
|
||
在同一高分辨率纯色背景母板中生成彼此完全分离的手机、睁眼、保留瞳孔的闭眼、短信气泡三点图标,再由 Photoshop 分别导出;密码锁继续引用 `a01-icon-lock-v1.png`,Logo 继续引用 `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` 唯一,且可导出层属于 `10` 至 `60` 的合法组。
|
||
|
||
- [ ] **步骤 2:先运行测试确认不完整清单失败**
|
||
|
||
```powershell
|
||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File tests/a01-layered-psd-contract.ps1
|
||
```
|
||
|
||
预期:报告第一项缺失或重复的图层契约。
|
||
|
||
- [ ] **步骤 3:实现 PNG 导入与精确定位**
|
||
|
||
JSX 只复制脚本打开的源 PNG 合并像素层,复制后立即关闭源文档且不保存;位置按 `x × 3`、`y × 3` 和清单目标尺寸设置,不手工拖动猜测。
|
||
|
||
- [ ] **步骤 4:重建并复核 PSD**
|
||
|
||
```powershell
|
||
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-hidden`、`password-visible`、`sms-default`、`sms-countdown`。
|
||
|
||
- [ ] **步骤 1:添加导出失败测试**
|
||
|
||
验证每个 `exports.path` 存在、PNG 文件头正确、像素尺寸与清单一致;透明资产四角 Alpha 为 0,不透明资产四角 Alpha 为 255。未执行导出时测试必须失败。
|
||
|
||
- [ ] **步骤 2:实现独立图层导出**
|
||
|
||
JSX 打开 PSD 后记录原可见性,只显示目标层或组,按清单矩形复制到新的透明临时文档并保存 PNG;完成后关闭脚本打开的 PSD 副本且不写回可见性变化。
|
||
|
||
- [ ] **步骤 3:实现四状态代表图和联系表**
|
||
|
||
按清单切换密码/验证码组以及眼睛、倒计时等状态专用层,分别导出 412 × 915 预览,再组合为一张两行两列联系表。代表图只进入 `review`,页面不得引用。
|
||
|
||
- [ ] **步骤 4:运行导出验证**
|
||
|
||
```powershell
|
||
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:记录文件证据**
|
||
|
||
```powershell
|
||
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
|
||
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 实施计划;不得在本计划中顺手修改页面。
|