{
  "$schema": "https://bestaiskill.com/schemas/agent-install/2.json",
  "skill": "p5-paint-animation",
  "built": "2026-10-26",
  "control_level": 4,
  "control_level_label": "L4 高权限",
  "capabilities": [
    "execute_command",
    "network",
    "write_file"
  ],
  "required_controls": {
    "agent": [
      "sandbox_recommended",
      "graded_authorization"
    ],
    "admin": [
      "approval_process",
      "rollback_support",
      "full_audit"
    ]
  },
  "evidence": [
    {
      "file": "scripts/",
      "summary": "Execute local scripts or commands: node scripts/render.mjs <sketch.js> [out.png] [--size WxH] [--seed N] [--im"
    },
    {
      "file": "网络端点",
      "summary": "Declare external network access: registry.npmjs.org: npm ci installs puppeteer 25.9.0 / p5 2.3.2 / p5.brush 2.2.1 (p"
    },
    {
      "file": "本地工作目录",
      "summary": "File I/O and artifact output: Output paths specified by caller: out.png / out.mp4; render-anim also writes co-located <out>.track.json (per-frame pen tip position and mark"
    }
  ],
  "verification": {
    "method": "第二遍独立重读 + 反查：① 全量文件清单核对（14 个文件：SKILL.md + scripts/{render.mjs,render-anim.mjs,render-video.mjs,setup.sh,package.json,package-lock.json} + scripts/lib/{inject.mjs,page-safety.mjs} + scripts/sketches/{handwriting.anim.js,repaint.anim.js,repaint-video.js} + references/{flows.md,gotchas.md}）。② import 与网络扫描：三个 harness 均 import puppeteer + node:child_process（execFileSync ffmpeg）；全目录 process.env/os.environ 零命中。③ 逐个 launcher 核对 Chromium 参数与请求拦截是否真的装上（hardenPage 在 newPage() 后立即调用）。④ 把 SKILL.md 声明的每个旋钮回查到 sketch 源码（PHRASE/INK/BRUSH/PAPER、STYLE/DETAIL/LOOSE/SAT/SUBJECT、WORLD/MASKED/BG、--frames）。⑤ 反例检查：专门找关闭沙箱、TLS 降级、隐藏上传（结论：都没有）。",
    "second_pass": [
      {
        "item": "『渲染期网络与本地文件访问被挡住』是否真成立",
        "status": "ok",
        "detail": "render.mjs / render-anim.mjs / render-video.mjs 都在 const page = await browser.newPage(); 之后立即 await hardenPage(page)；page-safety.mjs 用 page.setRequestInterception(true) 后只放行 about:/blob:/data:，其余 request.abort('blockedbyclient')。素材以 `var IMG_SRC = \"data:…;base64,…\"` 注入，故 sketch 拿不到 file:// 也发不出请求。"
      },
      {
        "item": "有没有关闭沙箱或安全降级的 flag（红档的关键判据）",
        "status": "ok",
        "detail": "三个 launcher 的 launch 参数只有 headless: \"new\" 与 args: [\"--enable-unsafe-swiftshader\"]；无 --no-sandbox、--disable-web-security、--allow-file-access-from-files、--single-process、--ignore-certificate-errors。--enable-unsafe-swiftshader 是为无 GPU 环境启用软件渲染，不属安全降级面。"
      },
      {
        "item": "『无凭证』是否成立",
        "status": "ok",
        "detail": "全目录 grep process.env / os.environ 零命中；三个 harness 无 token/key 参数；setup.sh 自述 'No credentials, no cost, nothing is uploaded.'；无 cookie/keychain/.env 访问。"
      },
      {
        "item": "--inject 是否等于任意代码执行",
        "status": "ok",
        "detail": "lib/inject.mjs 的 buildInjectDeclarations 只产出 `var NAME = <JSON.stringify(value)>;`；NAME 必须匹配 /^[A-Z][A-Z0-9_]*$/（否则 'invalid --inject name'），值非 JSON 字符串/数字/布尔即抛错，未闭合字符串亦抛错。全文件无 eval / new Function。"
      },
      {
        "item": "seed 可复现是否真落在代码（而非文档口号）",
        "status": "ok",
        "detail": "render.mjs 与 render-anim.mjs 都构造 seedShim，并在 addScriptTag 注入 p5.min.js / p5.brush.js **之前**先注入 mulberry32 覆盖 Math.random（注释：'Seeded PRNG (mulberry32) installed over Math.random BEFORE libs load'）。"
      },
      {
        "item": "文档声明的旋钮是否与 sketch 实现一致",
        "status": "ok",
        "detail": "handwriting.anim.js 有 typeof PHRASE / INK / BRUSH / PAPER 守卫（const TEXT = typeof PHRASE !== \"undefined\" ? PHRASE : \"hello world\"; 等）；repaint.anim.js 有 STYLE / DETAIL / LOOSE / SUBJECT（subject-first 段）；repaint-video.js 有 WORLD / MASKED / BG 且 render-video.mjs 支持 --frames DIR 传已抠像帧。与 SKILL.md 的 dial 列表逐项对得上。"
      },
      {
        "item": "『Requires: Node 22.12+』是否被运行时校验",
        "status": "discrepancy",
        "detail": "SKILL.md 的 Requirements 写 'Requires: Node 22.12+, ffmpeg on PATH, ~500MB disk (Chromium).'，但 scripts/package.json 没有 engines 字段，setup.sh 与三个 harness 也都不做 Node 版本检查；低版本 Node 会照常尝试执行，只在运行期以别的错误暴露。因此该版本要求是文档级而非技术门槛（对 pin commit 有效的真实出入）。"
      },
      {
        "item": "Flow C 抠像『local CoreML inference, no data leaves the machine』",
        "status": "unlocatable",
        "detail": "remove-background 属于 HyperFrames CLI，该 CLI 不在本仓库内，其后端实现（是否 CoreML、是否在非 macOS 平台改走别的推理路径、是否会下载权重）无法在本 skill 目录内复核；本次为只读侦查且不运行该命令，故按文档声明记录，不作为已核事实。"
      }
    ],
    "level": 1,
    "level_label": "V1 已固定",
    "commit": "ba7a0bb6d3567d124c51f6074625043bfe0b32eb",
    "sha256": "1f0478d5e5ca2ab08d938c26c8c545fbda90ebafd7f4b9e1174a3c5aea3118fe",
    "reviewed_by": null,
    "reviewed_at": null
  },
  "assessed_at": "2026-10-25",
  "method_version": "2.0",
  "mirror": {
    "archive": "https://skillpub.pages.dev/r2/v/2026-09-28/p5-paint-animation.tar.gz",
    "sha256": "1f0478d5e5ca2ab08d938c26c8c545fbda90ebafd7f4b9e1174a3c5aea3118fe",
    "commit": "ba7a0bb6d3567d124c51f6074625043bfe0b32eb"
  },
  "original": {
    "github": "https://github.com/heygen-com/hyperframes-community-skills/tree/main/skills/p5-paint-animation",
    "path": "skills/p5-paint-animation",
    "commit": "ba7a0bb6d3567d124c51f6074625043bfe0b32eb"
  }
}