Benchtop 是做什么的?
将“我想做一个东西……”转化为一个其他人可以构建的文件夹:包含一份指南、一份零件清单、一个可打印的外壳、一个可订购的电路板、可烧录的固件以及一个展示项目成果的页面。
核心理念
所有内容都从一个文件——project.json,以及 assets/parts/ 中的零件定义生成。你只需要编写和编辑这个文件;脚本会自动生成图纸、检查结果、外壳、电路板、引脚编号和展示页面。
正是这一点确保了输出的可靠性。手工绘制的接线图和手动输入的引脚表迟早会相互矛盾,而初学者无法判断哪个是错的。因此:永远不要手工绘制接线图,永远不要在固件中手动输入GPIO编号,永远不要引用零件文件中没有的尺寸。修改 project.json(或零件文件)然后重新生成即可。
scripts/lib/types.ts 是模式定义文件,每个字段都有注释。
examples/luft/project.json 是一个完整的项目文件(包含零件、连接、外壳、固件和展示区块);在编写你的第一个项目文件之前,请阅读它。该示例附带了 examples/luft/firmware/ 中的固件(这是唯一需要手写的部分,也是 main.cpp 编写的范例),但没有其他生成输出:在一个副本上运行脚本以查看每个脚本会生成什么。
环境设置
脚本是 TypeScript 语言,使用 bun 从本技能的目录运行。核心部分(检查、BOM、采购、指南、概念表、着陆页、固件框架)没有依赖项。
| 步骤 | 需要 | 如果缺失 |
|---|---|---|
| 外壳、PCB | bun install --cwd scripts 一次(JSCAD、tscircuit,版本已锁定) | 脚本会打印命令并退出,返回代码3。告诉用户将要安装什么,然后运行它。 |
| 指南 PDF、截图 | Chrome、Chromium 或 Edge | HTML 仍然可以工作;用户从浏览器打印为 PDF。 |
| 编译固件 | PlatformIO (pio) | 仍然会生成框架;但会说明它尚未编译。 |
| 3D 渲染 | Blender 在 PATH 中 | render.ts 退出代码3并打印一行提示;页面会回退到线条图和3D查看器。 |
在用户选择的一个项目文件夹中工作(询问一次;默认为 ./<slug>/)。所有命令都以该文件夹为参数:bun <skill>/scripts/<name>.ts <projectDir>。
工作流程
分为六个阶段。每个阶段都以用户可以查看的产出结束,并由用户做决策。不要在用户决策前自行推进:在第一阶段的错误猜测会浪费之后的所有工作。如果用户中途到达(“我有零件了,我需要一个外壳”),则从该阶段开始,并构建最小的 project.json。
1. 构想
阅读 references/imagine.md。了解这个产品是做什么的、为谁做的、用在何处、如何供电以及用户的技能和工具水平。提供两到三个真正不同的方向,而不是同一款产品的三种尺寸。一旦方向确定,编写第一个 project.json(零件和外壳区块,暂不包含连接),然后运行:
bun scripts/concept.ts <projectDir> # out/concept.html: 闭合视图、内部视图、尺寸、成本
向用户展示概念表(打开它,或者用 shoot.ts 截图)。决策:这是你想要的东西吗? 在这里迭代;这是改变主意成本最低的阶段。
2. 零件与电路
阅读 references/circuit.md。从 assets/parts/ 中选择零件(列出文件夹内容;每个文件都有一个 blurb 描述)。如果某个零件不在其中,则将其放在 <projectDir>/parts/ 中。焊盘位置的来源决定了指南和外壳是否可信,因此在手工输入电路板或模块的焊盘数据之前,务必先查询零件目录。一个快照随本技能一起提供;无需额外设置:
bun scripts/catalog.ts find "<确切型号>" # 此电路板或模块是否在目录中?
bun scripts/catalog.ts pads <part_id> # 它是否包含来自制造商 CAD 文件的焊盘位置?
bun scripts/catalog.ts import-part <part_id> --id <id> --out <projectDir>/parts/<id>.json
当 pads 列出数据集时,import-part 会生成零件文件的草稿:来自制造商文件的焊盘和轮廓、接地引脚,以及目录中已有的 GPIO 编号、逻辑电平、高度和连接器开孔。它会打印出无法推导出的信息(电源引脚、价格、通常还有高度);根据数据手册补充这些信息。只导入你将购买的确切电路板,确保同一制造商和修订版本:品牌板子的焊盘数据对同一芯片的克隆品没有任何意义。当目录中没有该零件的焊盘数据时,根据数据手册或制造商的图纸手动编写文件,遵循 references/circuit.md(“添加零件”)中的指南。然后编写 connections 并进行检查:
bun scripts/validate.ts <projectDir> # 电气规则检查,有错误则退出代码1
错误会阻止后续流程。每个发现都会说明哪里错了、为什么错以及如何修改;修改 project.json 并重新运行,直到检查通过。警告是需要判断的问题:要么解决它们,要么用通俗的语言告知用户。永远不要为了通过检查而修改零件文件,除非该零件文件确实有误,并且如果修改了,请说明原因。如果某个零件的实际功耗超过了供电能力,并且固件会进行限制,请在零件的条目中声明 peakMa 和 peakMaWhy(参见参考文档),而不是隐藏它。
3. 采购与构建路径
决策,需要明确询问:你想要一个成品 PCB,还是想自己焊接? 用一句话解释三种路径各是什么,并为这个项目和使用者推荐一种:
build.path | 用户需要做什么 | 适合的情况 |
|---|---|---|
wire | 根据指南,用杜邦线或焊接的方式连接模块 | 一次性项目,连接少,想要这周就完成 |
pcb-diy | 订购一块空载板,然后将模块焊接到上面 | 需要制作多个单元,连接多,想要整洁和可靠 |
pcb-assembled | 订购带插座并已焊接好的电路板,然后将模块压入或插入 | 没有烙铁,或是作为礼物送给没有烙铁的人 |
然后获取实时价格。先阅读 references/sourcing-stores.md;它涵盖了哪些商店有 API、哪些需要在网页上搜索,以及用户所在国家的增值税和关税情况。
bun scripts/shopping.ts <projectDir> --region NO # out/shopping/index.html: 用户购买的清单
bun scripts/source.ts <projectDir> # 每个零件的候选价格和库存信息,来自有 API 的商店
bun scripts/bom.ts <projectDir> # out/bom.csv, out/bom.md, 预估总价
从 shopping.ts 开始。它不需要任何 API:对于每个零件,它会显示图纸、清单必须匹配的条件(尺寸、引脚顺序、供电范围、高度),以及打开用户所在地区零售商正确搜索页面的按钮(两位国家代码;商店列表在 assets/stores.json)。这个页面本身足够让用户进行购买,也是你无法自行查询价格时的正确交接方式。它永远不会实际下订单。然后,在可能的情况下,进一步查找真实的商品列表和价格:
捆绑的零件目录(references/catalog.md)包含制造商事实,而非价格:find 和 show 返回带有来源链接的尺寸和引脚信息,用于编写零件文件。一个完整的目录(通过 --db 或 BENCHTOP_CATALOG 指定)还包含商店列表:bun scripts/catalog.ts listings "<part>" --norway。其数字是卖家和制造商的声明,而非测量数据。
期望 API 商店找不到通用的克隆模块(大多数项目使用的廉价传感器和显示板),而是提供一个不同尺寸或引脚顺序的品牌电路板。那不匹配:在参考文档中命名的网络零售商处搜索零件文件描述的精确型号。
source.ts 收集候选信息;由你选择。优先选择一两家商店而不是五家(小订单运费占主导),检查每个商品列表是否与零件文件是相同型号(不同克隆品的引脚顺序和尺寸不同),并将你的选择写入 project.sourcing:每个零件一行,在其 note 中注明要选择的型号,每个商店一行 shipping 条目(如果商店只在结账时显示运费,则省略其 price)。当一个商品列表提供多个零件时(例如,一个电阻器套装中含有三个电阻),给它一行,并在 covers 中注明其他参考编号。用户声称已经拥有的零件,在其 parts 条目标记为 "owned": true 而不是一行商品信息:它仍会出现在指南和检查中,但不计成本,购物页面会告诉用户需要检查抽屉里那个零件哪些参数。重新运行 bom.ts;它会打印包含运费的实际总价。在用户下单前向他们展示这个数字。商店报告为“不可用”是其自身的问题,而不是停止的理由:继续与其他商店合作。
4. 构建文件
根据所选路径生成所需文件,然后在展示每个输出之前先自行检查。在迭代过程中,只运行正在处理的那个脚本。在交付任何成果之前,完整运行一次整个流程,以确保没有文件是过时或缺失的:
bun scripts/build.ts <projectDir> --region NO # 按顺序执行每一步;如果电气检查失败则停止
它会打印每一步的一行摘要,将所有生成器标记的任何问题汇总到一个列表中,并写入 out/build-report.md。如果跳过了某一步,它会告诉你原因(缺少 Blender,还没有展示文案等)。它会编译固件:编译错误会导致构建失败,并且对某个芯片系列的第一次编译会下载其工具链(大约 1 GB,需要几分钟),这是正常现象。报告显示 NOT COMPILED 意味着固件未经检查;在交接时说明这一点。各个独立的脚本:
bun scripts/guide.ts <projectDir> --pdf # out/guide/index.html + guide.pdf
bun scripts/enclosure.ts <projectDir> # out/enclosure/: body.stl, lid.stl, .3mf, assembly.glb, print.md
bun scripts/pcb.ts <projectDir> # pcb paths only. pcb/board.tsx + out/pcb/: gerbers.zip, schematic.svg, pcb.png, order.md
bun scripts/firmware.ts <projectDir> # firmware/: platformio.ini, include/pins.h, bring-up test, main.cpp skeleton
bun scripts/compile.ts <projectDir> # compiles bring-up and main with PlatformIO; errors as file:line
bun scripts/render.ts <projectDir> # out/renders/: hero.png, hero-alpha.png, exploded.png, top.png (needs Blender)
bun scripts/drawing.ts <projectDir> # out/drawings/: wiring plan, dimensioned case drawing, pin map, 1:1 fit-check sheet
bun scripts/shoot.ts <projectDir>/out/guide/index.html <projectDir>/out/shots --pages 1,3,4 --width 900
在运行每一步之前,阅读相应的参考文档:references/guide.md、references/enclosure.md、references/pcb.md、references/firmware.md、references/renders.md、references/drawings.md。每个文档都解释了需要检查什么,以及当结果不正确时需要在 project.json 中修改什么。然后,将实际的固件行为写入 firmware/src/main.cpp,仅使用 pins.h 中的常量。
外壳和 PCB 脚本会打印警告(通风口被另一个零件挡住、端口够不到外壳壁、线接式零件未放置在电路板上)。这些是设计问题,不是噪音。修复布局,或者告知用户后果。
guide.ts 和 drawing.ts 在每次构建时都会自我检查它们生成的图纸,并对每个问题打印一行信息:一根线结束在隐藏于更高组件后面的焊盘上;一个引脚名称没有清晰的放置位置;在分解视图中零件重叠;接线图中的线穿过另一个零件。每一行都会指明页面、步骤和零件。布局问题可以使用 bench 修复;渲染问题属于生成器,未解决的几何问题需要源数据。不要为了消除渲染器的发现而修改正确的零件几何数据。标记为 geometryEvidence.status: "unresolved" 的零件(其文件的布局与证据相矛盾;目前是 INMP441 麦克风)仍然可以构建:外壳、图纸、指南和包都是根据文件中的数字制作的,每次构建都会打印一次 warning:,并且每个受影响的输出都会带有“布局未经验证”的标记。在交接时首先重复该警告,告诉用户在打印前测量零件并在项目的 parts/ 文件夹中更正它,并且永远不要将这样的外壳称为“准备好打印”。适配性测试打印是最后一道关。--strict-geometry(或 BENCHTOP_STRICT_GEOMETRY=1)会将警告变回拒绝,并附带一个部分逻辑指南;载板 PCB 在任何模式下都会被拒绝,因为电路板需要花钱,没有廉价的适配性测试。--strict 会在任何图纸发现未解决时以非零状态退出。干净的检查仅意味着测试的图纸不变性成立,而不是零件文件本身是正确的。
5. 展示
阅读 references/showcase.md。编写 showcase 区块(标题、工作原理、特点、统计数据、常见问题解答、主题),然后:
bun scripts/package.ts <projectDir> # dist/<slug>/ (index.html, guide/, files/) + dist/<slug>.zip
bun scripts/shoot.ts <projectDir>/dist/<slug>/index.html <projectDir>/out/shots --width 1320 --height 2400
仔细查看页面:--from 2400 会捕获从 2400 像素向下开始的窗口。文案由你负责,它是区分产品页面与仅仅替换了名词的模板的关键;参考文档说明了如何编写文案以及如何选择主题。一旦每个零件都有对应的商品行,页面上的价格就来自 project.sourcing。以项目货币以外的货币购买的商品行,会带有自己的 currency;然后按每种货币显示总价(“401 NOK + 7.95 USD”),并且从不进行转换。没有采购信息的页面会说明该数字是基于典型价格的估算。
package.ts 每次都会根据 project.json 重新生成指南,因此永远不要手工修正生成的文件:修正会在下次运行时丢失,并且在此之前这些文件彼此不一致。如果一个生成器有问题,请修改其输入,如果无法通过这种方式使其正确,则在输出中告知用户问题所在,而不是静默地修补。
6. 交付
简要告知用户:打包文件的位置、项目总成本、首先需要做什么,以及哪些内容尚未经过验证。请具体说明。参见“此处的精度含义”。
此处的精度含义
在将克隆零件用于外壳或载板 PCB 之前,请阅读 references/geometry-evidence.md。检查 assets/geometry-evidence/ 文件夹,了解测量的验证状态。
关于 Philosophy
...(原文后续部分,包括“关于 Philosophy”、“关于 lang”和“关于代理”等章节,因翻译提示中标记为已截断,此处保留原文结构但按注释说明处理;若需完整翻译,需提供全文)
(原文后续内容涉及项目理念、语言设置、AI 代理行为等,因原始输入被截断,已无法精确翻译。如需完整中文版 SKILL.md,请提供技能完整的原始英文文档。)