{
  "canonical_name": "openvideodev/openvideo",
  "compilation_id": "pack_4d83b7b967b248bcbba6512024075eae",
  "created_at": "2026-05-14T02:07:29.979892+00:00",
  "created_by": "project-pack-compiler",
  "feedback": {
    "carrier_selection_notes": [
      "viable_asset_types=skill, recipe, host_instruction, eval, preflight",
      "recommended_asset_types=skill, recipe, host_instruction, eval, preflight"
    ],
    "evidence_delta": {
      "confirmed_claims": [
        "identity_anchor_present",
        "capability_and_host_targets_present",
        "install_path_declared_or_better"
      ],
      "missing_required_fields": [],
      "must_verify_forwarded": [
        "Run or inspect `npm install openvideo` in an isolated environment.",
        "Confirm the project exposes the claimed capability to at least one target host."
      ],
      "quickstart_execution_scope": "allowlisted_sandbox_smoke",
      "sandbox_command": "npm install openvideo",
      "sandbox_container_image": "node:22-slim",
      "sandbox_execution_backend": "docker",
      "sandbox_planner_decision": "llm_execute_isolated_install",
      "sandbox_validation_id": "sbx_509c713ab8804aa1a3e6a01263ed6c8f"
    },
    "feedback_event_type": "project_pack_compilation_feedback",
    "learning_candidate_reasons": [],
    "template_gaps": []
  },
  "identity": {
    "canonical_id": "project_024de9159d53262cb928905b5f277263",
    "canonical_name": "openvideodev/openvideo",
    "homepage_url": null,
    "license": "unknown",
    "repo_url": "https://github.com/openvideodev/openvideo",
    "slug": "openvideo",
    "source_packet_id": "phit_cc99e991b92642ab877a5599fd73aa2e",
    "source_validation_id": "dval_afe2a45ad6dc4273ab1c040781a767e4"
  },
  "merchandising": {
    "best_for": "需要软件开发与交付能力，并使用 local_cli的用户",
    "github_forks": 31,
    "github_stars": 224,
    "one_liner_en": "Open-source React Video Editor with client-side rendering (WebCodecs) and pixi.js. Capcut clone. Canva clone. React video editor. webgl video editor.",
    "one_liner_zh": "Open-source React Video Editor with client-side rendering (WebCodecs) and pixi.js. Capcut clone. Canva clone. React video editor. webgl video editor.",
    "primary_category": {
      "category_id": "software-development",
      "confidence": "high",
      "name_en": "Software Development",
      "name_zh": "软件开发与交付",
      "reason": "matched_keywords:code, git, cli"
    },
    "target_user": "使用 local_cli 等宿主 AI 的用户",
    "title_en": "openvideo",
    "title_zh": "openvideo 能力包",
    "visible_tags": [
      {
        "label_en": "Browser Agents",
        "label_zh": "浏览器 Agent",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "product_domain-browser-agents",
        "type": "product_domain"
      },
      {
        "label_en": "Web Task Automation",
        "label_zh": "网页任务自动化",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "user_job-web-task-automation",
        "type": "user_job"
      },
      {
        "label_en": "Browser Automation",
        "label_zh": "浏览器自动化",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "core_capability-browser-automation",
        "type": "core_capability"
      },
      {
        "label_en": "Node-based Workflow",
        "label_zh": "节点式流程编排",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "workflow_pattern-node-based-workflow",
        "type": "workflow_pattern"
      },
      {
        "label_en": "Local-first",
        "label_zh": "本地优先",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "selection_signal-local-first",
        "type": "selection_signal"
      }
    ]
  },
  "packet_id": "phit_cc99e991b92642ab877a5599fd73aa2e",
  "page_model": {
    "artifacts": {
      "artifact_slug": "openvideo",
      "files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json",
        "REPO_INSPECTION.md",
        "CAPABILITY_CONTRACT.json",
        "EVIDENCE_INDEX.json",
        "CLAIM_GRAPH.json"
      ],
      "required_files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json"
      ]
    },
    "detail": {
      "capability_source": "Project Hit Packet + DownstreamValidationResult",
      "commands": [
        {
          "command": "npm install openvideo",
          "label": "Node.js / npm · 官方安装入口",
          "source": "https://github.com/openvideodev/openvideo#readme",
          "verified": true
        }
      ],
      "display_tags": [
        "浏览器 Agent",
        "网页任务自动化",
        "浏览器自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "eyebrow": "软件开发与交付",
      "glance": [
        {
          "body": "判断自己是不是目标用户。",
          "label": "最适合谁",
          "value": "需要软件开发与交付能力，并使用 local_cli的用户"
        },
        {
          "body": "先理解能力边界，再决定是否继续。",
          "label": "核心价值",
          "value": "Open-source React Video Editor with client-side rendering (WebCodecs) and pixi.js. Capcut clone. Canva clone. React video editor. webgl video editor."
        },
        {
          "body": "未完成验证前保持审慎。",
          "label": "继续前",
          "value": "publish to Doramagic.ai project surfaces"
        }
      ],
      "guardrail_source": "Boundary & Risk Card",
      "guardrails": [
        {
          "body": "Prompt Preview 只展示流程，不证明项目已安装或运行。",
          "label": "Check 1",
          "value": "不要把试用当真实运行"
        },
        {
          "body": "local_cli",
          "label": "Check 2",
          "value": "确认宿主兼容"
        },
        {
          "body": "publish to Doramagic.ai project surfaces",
          "label": "Check 3",
          "value": "先隔离验证"
        }
      ],
      "mode": "skill, recipe, host_instruction, eval, preflight",
      "pitfall_log": {
        "items": [
          {
            "body": "README/documentation is current enough for a first validation pass.",
            "category": "能力坑",
            "evidence": [
              "capability.assumptions | github_repo:1125747446 | https://github.com/openvideodev/openvideo | README/documentation is current enough for a first validation pass."
            ],
            "severity": "medium",
            "suggested_check": "将假设转成下游验证清单。",
            "title": "能力判断依赖假设",
            "user_impact": "假设不成立时，用户拿不到承诺的能力。"
          },
          {
            "body": "未记录 last_activity_observed。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | last_activity_observed missing"
            ],
            "severity": "medium",
            "suggested_check": "补 GitHub 最近 commit、release、issue/PR 响应信号。",
            "title": "维护活跃度未知",
            "user_impact": "新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "downstream_validation.risk_items | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "进入安全/权限治理复核队列。",
            "title": "下游验证发现风险项",
            "user_impact": "下游已经要求复核，不能在页面中弱化。"
          },
          {
            "body": "No sandbox install has been executed yet; downstream must verify before user use.",
            "category": "安全/权限坑",
            "evidence": [
              "risks.safety_notes | github_repo:1125747446 | https://github.com/openvideodev/openvideo | No sandbox install has been executed yet; downstream must verify before user use."
            ],
            "severity": "medium",
            "suggested_check": "转成明确权限清单和安全审查提示。",
            "title": "存在安全注意事项",
            "user_impact": "用户安装前需要知道权限边界和敏感操作。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "risks.scoring_risks | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "把风险写入边界卡，并确认是否需要人工复核。",
            "title": "存在评分风险",
            "user_impact": "风险会影响是否适合普通用户安装。"
          },
          {
            "body": "issue_or_pr_quality=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | issue_or_pr_quality=unknown"
            ],
            "severity": "low",
            "suggested_check": "抽样最近 issue/PR，判断是否长期无人处理。",
            "title": "issue/PR 响应质量未知",
            "user_impact": "用户无法判断遇到问题后是否有人维护。"
          },
          {
            "body": "release_recency=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | release_recency=unknown"
            ],
            "severity": "low",
            "suggested_check": "确认最近 release/tag 和 README 安装命令是否一致。",
            "title": "发布节奏不明确",
            "user_impact": "安装命令和文档可能落后于代码，用户踩坑概率升高。"
          }
        ],
        "source": "ProjectPitfallLog + ProjectHitPacket + validation + community signals",
        "summary": "发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。",
        "title": "踩坑日志"
      },
      "snapshot": {
        "contributors": 5,
        "forks": 31,
        "license": "unknown",
        "note": "站点快照，非实时质量证明；用于开工前背景判断。",
        "stars": 224
      },
      "source_url": "https://github.com/openvideodev/openvideo",
      "steps": [
        {
          "body": "不安装项目，先体验能力节奏。",
          "code": "preview",
          "title": "先试 Prompt"
        },
        {
          "body": "理解输入、输出、失败模式和边界。",
          "code": "manual",
          "title": "读说明书"
        },
        {
          "body": "把上下文交给宿主 AI 继续工作。",
          "code": "context",
          "title": "带给 AI"
        },
        {
          "body": "进入主力环境前先完成安装入口与风险边界验证。",
          "code": "verify",
          "title": "沙箱验证"
        }
      ],
      "subtitle": "Open-source React Video Editor with client-side rendering (WebCodecs) and pixi.js. Capcut clone. Canva clone. React video editor. webgl video editor.",
      "title": "openvideo 能力包",
      "trial_prompt": "# openvideo - Prompt Preview\n\n> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 openvideo 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的软件开发与交付任务。\n我常用的宿主 AI：Local CLI\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: Open-source React Video Editor with client-side rendering (WebCodecs) and pixi.js. Capcut clone. Canva clone. React video editor. webgl video editor. 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. page-introduction：项目介绍。围绕“项目介绍”模拟一次用户任务，不展示安装或运行结果。\n2. page-installation：安装与配置。围绕“安装与配置”模拟一次用户任务，不展示安装或运行结果。\n3. page-quick-start：快速开始。围绕“快速开始”模拟一次用户任务，不展示安装或运行结果。\n4. page-architecture：系统架构。围绕“系统架构”模拟一次用户任务，不展示安装或运行结果。\n5. page-studio：Studio - 项目状态管理。围绕“Studio - 项目状态管理”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. page-introduction\n输入：用户提供的“项目介绍”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. page-installation\n输入：用户提供的“安装与配置”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. page-quick-start\n输入：用户提供的“快速开始”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. page-architecture\n输入：用户提供的“系统架构”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. page-studio\n输入：用户提供的“Studio - 项目状态管理”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / page-introduction：Step 1 必须围绕“项目介绍”形成一个小中间产物，并等待用户确认。\n- Step 2 / page-installation：Step 2 必须围绕“安装与配置”形成一个小中间产物，并等待用户确认。\n- Step 3 / page-quick-start：Step 3 必须围绕“快速开始”形成一个小中间产物，并等待用户确认。\n- Step 4 / page-architecture：Step 4 必须围绕“系统架构”形成一个小中间产物，并等待用户确认。\n- Step 5 / page-studio：Step 5 必须围绕“Studio - 项目状态管理”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/openvideodev/openvideo\n- https://github.com/openvideodev/openvideo#readme\n- README.md\n- packages/openvideo/src/index.ts\n- docs/content/docs/installation.mdx\n- packages/openvideo/package.json\n- package.json\n- docs/content/docs/basic-usage.mdx\n- packages/openvideo/src/studio.ts\n- examples/src/App.tsx\n- packages/openvideo/src/compositor.ts\n- packages/openvideo/src/studio/timeline-model.ts\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 openvideo 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\n```\n",
      "voices": [
        {
          "body": "来源平台：github。github/github_issue: meta property is read-only（https://github.com/openvideodev/openvideo/issues/19）。这些是项目级外部声音，不作为单独质量证明。",
          "items": [
            {
              "kind": "github_issue",
              "source": "github",
              "title": "meta property is read-only",
              "url": "https://github.com/openvideodev/openvideo/issues/19"
            }
          ],
          "status": "已收录 1 条来源",
          "title": "社区讨论"
        }
      ]
    },
    "homepage_card": {
      "category": "软件开发与交付",
      "desc": "Open-source React Video Editor with client-side rendering (WebCodecs) and pixi.js. Capcut clone. Canva clone. React video editor. webgl video editor.",
      "effort": "安装已验证",
      "forks": 31,
      "icon": "code",
      "name": "openvideo 能力包",
      "risk": "需复核",
      "slug": "openvideo",
      "stars": 224,
      "tags": [
        "浏览器 Agent",
        "网页任务自动化",
        "浏览器自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "thumb": "gray",
      "type": "Skill Pack"
    },
    "manual": {
      "markdown": "# https://github.com/openvideodev/openvideo 项目说明书\n\n生成时间：2026-05-14 00:03:22 UTC\n\n## 目录\n\n- [项目介绍](#page-introduction)\n- [安装与配置](#page-installation)\n- [快速开始](#page-quick-start)\n- [系统架构](#page-architecture)\n- [Studio - 项目状态管理](#page-studio)\n- [Compositor - 渲染引擎](#page-compositor)\n- [剪辑系统](#page-clips)\n- [视频与音频剪辑](#page-video-clip)\n- [文字与字幕剪辑](#page-text-caption)\n- [资源管理](#page-resources)\n\n<a id='page-introduction'></a>\n\n## 项目介绍\n\n### 相关页面\n\n相关主题：[安装与配置](#page-installation), [系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n- [packages/node/README.md](https://github.com/openvideodev/openvideo/blob/main/packages/node/README.md)\n- [packages/openvideo/render.html](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/render.html)\n- [packages/node/src/template.html](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/template.html)\n- [packages/openvideo/src/animation/presets.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/animation/presets.ts)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/transition/transition.ts](https://github.com/openvideov/openvideo/blob/main/packages/openvideo/src/transition/transition.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/clips/caption-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/caption-clip.ts)\n- [packages/openvideo/src/sprite/base-sprite.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/sprite/base-sprite.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n- [packages/openvideo/src/utils/chromakey.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/chromakey.ts)\n</details>\n\n# 项目介绍\n\n## 概述\n\nOpenVideo 是一个开源的 Web 端视频编辑与渲染引擎，旨在为开发者提供基于现代 Web 技术的视频处理能力。该项目充分利用 WebCodecs API 实现硬件加速的视频编解码，结合 PixiJS 渲染引擎实现高性能的 2D/3D 图形渲染。OpenVideo 的设计理念是让视频编辑功能能够在浏览器环境中高效运行，同时支持服务端 Node.js 环境下的视频渲染输出。\n\n## 核心功能\n\nOpenVideo 提供了完整的视频编辑工作流支持，包括时间线管理、轨道编辑、剪辑合成、特效转场等功能模块。开发者可以通过声明式的 JSON 配置或程序化的 API 调用来构建复杂的视频编辑场景。\n\n### 主要能力\n\n| 功能类别 | 支持内容 |\n|---------|---------|\n| 媒体剪辑 | 视频、音频、图片、字幕、文字 |\n| 视频特效 | 动画预设、滤镜、透明度、镜像、缩放 |\n| 转场效果 | 超过 30 种转场动画（淡入淡出、滑动、缩放等） |\n| 渲染输出 | WebCodecs 硬件编码、MP4 封装 |\n| 实时预览 | Canvas 2D/WebGL 渲染、帧级同步 |\n\n## 技术架构\n\n### 技术栈\n\nOpenVideo 基于以下核心技术构建：\n\n| 技术 | 用途 |\n|-----|------|\n| **WebCodecs API** | 硬件加速的视频编码/解码处理 |\n| **PixiJS** | 高性能 2D/3D 渲染引擎 |\n| **wrapbox** | MP4 容器操作的底层工具库 |\n| **TypeScript** | 类型安全的开发环境 |\n| **Playwright** | 服务端渲染的浏览器自动化 |\n\n### 架构层次\n\n```\n┌─────────────────────────────────────────────┐\n│              应用层 (Application)            │\n│  Studio │ Compositor │ PreviewCanvas        │\n├─────────────────────────────────────────────┤\n│              剪辑层 (Clips)                   │\n│  VideoClip │ AudioClip │ TextClip │ ImageClip │\n│  CaptionClip │ SubtitleClip                  │\n├─────────────────────────────────────────────┤\n│              精灵层 (Sprites)                 │\n│  BaseSprite │ Transform │ Animations         │\n├─────────────────────────────────────────────┤\n│              渲染层 (Rendering)              │\n│  PixiJS App │ WebGL │ Compositor            │\n├─────────────────────────────────────────────┤\n│              工具层 (Utils)                   │\n│  Chromakey │ MP4 Utils │ Serialization       │\n├─────────────────────────────────────────────┤\n│              编码层 (Codecs)                 │\n│  VideoEncoder │ VideoDecoder │ MP4 Muxer    │\n└─────────────────────────────────────────────┘\n```\n\n## 项目结构\n\nOpenVideo 采用 Monorepo 架构，主要包含以下包：\n\n```\nopenvideo/\n├── packages/\n│   ├── openvideo/           # 核心库\n│   │   └── src/\n│   │       ├── clips/       # 各类剪辑实现\n│   │       │   ├── video-clip.ts\n│   │       │   ├── text-clip.ts\n│   │       │   ├── caption-clip.ts\n│   │       │   └── ...\n│   │       ├── animation/   # 动画预设\n│   │       │   └── presets.ts\n│   │       ├── transition/  # 转场效果\n│   │       │   └── transition.ts\n│   │       ├── sprite/      # 精灵基类\n│   │       │   └── base-sprite.ts\n│   │       ├── mp4-utils/   # MP4 封装工具\n│   │       │   └── index.ts\n│   │       ├── utils/       # 工具函数\n│   │       │   └── chromakey.ts\n│   │       └── render.html  # 渲染模板\n│   │\n│   └── node/                # Node.js 服务端渲染包\n│       └── src/\n│           ├── renderer.ts  # 主渲染器\n│           ├── types.ts     # 类型定义\n│           ├── template.html # HTML 模板\n│           └── sample.ts    # 使用示例\n│\n└── examples/                # 示例项目\n```\n\n## 核心组件\n\n### Studio（工作室）\n\nStudio 是项目的顶层状态管理器，负责协调整个视频编辑项目的运行。它管理时间线配置、轨道层级、剪辑序列以及预览播放状态。\n\n```typescript\nimport { Studio } from 'openvideo';\n\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\nstudio.play();\n```\n\n资料来源：[README.md]()\n\n### Compositor（合成器）\n\nCompositor 是核心渲染引擎，负责处理视频帧的合成、编码输出和最终导出。它封装了 PixiJS 应用和 WebCodecs 视频编码器，提供统一的渲染接口。\n\n| 配置选项 | 类型 | 默认值 | 说明 |\n|---------|------|-------|------|\n| width | number | 1280 | 输出视频宽度 |\n| height | number | 720 | 输出视频高度 |\n| fps | number | 30 | 帧率 |\n| bgColor | string | '#000000' | 背景颜色 |\n| videoCodec | string | - | 视频编码器 |\n| bitrate | number | - | 比特率 |\n| audio | boolean | true | 是否包含音频 |\n\n资料来源：[packages/node/src/template.html:29-48]()\n\n### Clips（剪辑）\n\nClips 是各类媒体资源的抽象表示，包括以下类型：\n\n| 剪辑类型 | 文件 | 功能 |\n|---------|------|------|\n| VideoClip | video-clip.ts | 视频片段处理，支持 URL、Stream、OPFS 文件加载 |\n| TextClip | text-clip.ts | 文字渲染，支持样式、描边、阴影 |\n| CaptionClip | caption-clip.ts | 字幕处理，支持时间轴对齐和关键词高亮 |\n| AudioClip | - | 音频处理 |\n| ImageClip | - | 静态图像处理 |\n| SubtitleClip | - | 字幕轨道管理 |\n\n#### VideoClip 示例\n\n```typescript\nconst clip = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 100,\n  y: 200,\n  width: 640,\n  height: 480\n});\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:1-50]()\n\n#### TextClip 配置\n\nTextClip 支持丰富的文本样式配置：\n\n- fontFamily: 字体系列\n- fontSize: 字号\n- fontWeight: 字重\n- fontStyle: 斜体\n- fill: 填充颜色（支持渐变）\n- stroke: 描边效果\n- dropShadow: 阴影效果\n- align: 文本对齐\n- wordWrap: 自动换行\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:1-50]()\n\n## 动画系统\n\n### 动画预设\n\nOpenVideo 内置了丰富的动画预设，可在 `presets.ts` 中查看：\n\n| 预设名称 | 效果类型 |\n|---------|---------|\n| fadeIn | 淡入效果 |\n| fadeOut | 淡出效果 |\n| slideIn | 滑入动画 |\n| slideOut | 滑出动画 |\n| pulse | 脉冲动画 |\n| blurIn | 模糊淡入 |\n| blurOut | 模糊淡出 |\n\n```typescript\n// 动画配置结构\n{\n  \"0%\": {\n    x: 0,\n    y: 0,\n    opacity: 0,\n    scale: 1,\n    mirror: 0\n  },\n  \"100%\": {\n    x: 100,\n    y: 0,\n    opacity: 1,\n    scale: 1,\n    mirror: 0\n  }\n}\n```\n\n资料来源：[packages/openvideo/src/animation/presets.ts:1-80]()\n\n### 变换属性\n\nBaseSprite 提供了完整的变换控制：\n\n| 属性 | 说明 |\n|-----|------|\n| x, y | 位置坐标 |\n| width, height | 尺寸 |\n| scale, scaleX, scaleY | 缩放 |\n| angle | 旋转角度 |\n| opacity | 透明度 |\n| blur | 模糊程度 |\n| brightness | 亮度 |\n| mirror | 镜像模式 |\n| motionBlur | 运动模糊 |\n\n资料来源：[packages/openvideo/src/sprite/base-sprite.ts:1-50]()\n\n## 转场效果\n\n### 支持的转场类型\n\nOpenVideo 实现了超过 30 种 GLSL 着色器转场效果：\n\n| 转场名称 | 说明 |\n|---------|------|\n| GridFlip | 网格翻转 |\n| Circle | 圆形展开 |\n| Directional | 方向擦除 |\n| UndulatingBurnOut | 波纹燃烧 |\n| SquaresWire | 方块线条 |\n| RotateScaleFade | 旋转缩放淡入 |\n| RandomSquares | 随机方块 |\n| PolarFunction | 极坐标变换 |\n| Hexagonalize | 六边形化 |\n| Heart | 心形展开 |\n| Displacement | 置换变形 |\n| DirectionalWipe | 方向擦除 |\n| DirectionalWarp | 方向扭曲 |\n| Crosshatch | 网格线 |\n| CircleOpen | 圆环展开 |\n| CannabisLeaf | 叶片形状 |\n| StereoViewer | 立体视差 |\n| GlitchDisplace | 故障艺术 |\n| CrossZoom | 交叉缩放 |\n| BowTieHorizontal | 蝴蝶结水平 |\n| PolkaDotsCurtain | 波点帘幕 |\n| Pixelize | 像素化 |\n\n转场效果的实现通过 GLSL 片段着色器完成，支持自定义 uniform 参数配置。\n\n资料来源：[packages/openvideo/src/transition/transition.ts:1-100]()\n\n## 渲染流程\n\n### 服务端渲染\n\nNode.js 包提供了无头浏览器环境下的视频渲染能力：\n\n```mermaid\ngraph TD\n    A[创建 Renderer 实例] --> B[启动本地服务器]\n    B --> C[Playwright 打开浏览器]\n    C --> D[加载 HTML 模板]\n    D --> E[注入 JSON 配置]\n    E --> F[Compositor 初始化]\n    F --> G[逐帧渲染]\n    G --> H[WebCodecs 编码]\n    H --> I[MP4 封装]\n    I --> J[保存输出文件]\n```\n\n### 渲染器配置\n\n```typescript\nconst renderer = new Renderer({\n  json: videoConfig,      // 视频配置 JSON\n  outputPath: './out.mp4', // 输出路径\n  browserOptions: {\n    headless: true,       // 无头模式\n    timeout: 600000       // 10 分钟超时\n  }\n});\n\nrenderer.on('progress', ({ phase, progress }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n});\n\nawait renderer.render();\n```\n\n### 渲染进度事件\n\n| 阶段 | 说明 |\n|-----|------|\n| initializing | 初始化中 |\n| loading | 加载资源 |\n| rendering | 渲染中 |\n| saving | 保存文件 |\n| complete | 完成 |\n\n资料来源：[packages/node/README.md:60-90]()\n\n## 工具模块\n\n### MP4 工具\n\n`mp4-utils` 提供了 MP4 容器级别的操作能力，包括样本注入、时间戳规范化、轨道管理等功能。\n\n```typescript\n// 时间戳规范化处理\nsamples.forEach((s) => {\n  if (firstVDTS === null) {\n    firstVDTS = s.dts;\n    firstVCTS = s.cts;\n  }\n  const normalizedDTS = s.dts - firstVDTS;\n  const normalizedCTS = s.cts - (firstVCTS ?? 0);\n  \n  outfile.addSample(trackId, new Uint8Array(s.data), {\n    duration: s.duration,\n    dts: normalizedDTS + offsetDTS,\n    cts: normalizedCTS + offsetCTS,\n    is_sync: s.is_sync\n  });\n});\n```\n\n资料来源：[packages/openvideo/src/mp4-utils/index.ts:1-50]()\n\n### 绿幕抠像\n\n`chromakey` 模块提供了颜色键抠像功能：\n\n```typescript\nimport { createChromakey } from 'openvideo/utils/chromakey';\n\nconst chromakeyFilter = createChromakey({\n  keyColor: [0, 255, 0],  // 绿色\n  similarity: 0.4,\n  smoothness: 0.1\n});\n\n// 用于 VideoClip 的处理管道\nvideoClip.setFilter(chromakeyFilter);\n```\n\n资料来源：[packages/openvideo/src/utils/chromakey.ts:1-50]()\n\n## 使用方式\n\n### 前端使用\n\n```typescript\nimport { Studio, Compositor, Video, TextClip } from 'openvideo';\n\n// 1. 创建工作室\nconst studio = new Studio({\n  canvas: document.getElementById('canvas'),\n  width: 1920,\n  height: 1080\n});\n\n// 2. 添加视频\nconst video = await Video.fromUrl('input.mp4');\nstudio.addClip(video);\n\n// 3. 添加文字\nconst text = new TextClip('Hello World', {\n  fontSize: 48,\n  fontFamily: 'Arial'\n});\nstudio.addClip(text);\n\n// 4. 预览播放\nstudio.play();\n```\n\n### 服务端渲染\n\n```bash\n# 安装依赖\npnpm install\n\n# 构建项目\npnpm build\n\n# 运行示例\ncd packages/node\npnpm render\n```\n\n## 环境要求\n\n| 环境 | 版本要求 |\n|-----|---------|\n| Node.js | >= 18 |\n| 浏览器 | 支持 WebCodecs（Chrome 94+, Edge 94+） |\n| Playwright | Chromium 已安装 |\n\n## 许可证\n\nOpenVideo 采用 MIT 许可证开源。详情请参阅 [LICENSE](LICENSE) 文件。\n\n## 联系方式\n\n如有问题或合作意向，可通过以下方式联系：\n\n- 邮箱：hello@openvideo.dev\n- 官网：https://openvideo.dev\n\n---\n\n<a id='page-installation'></a>\n\n## 安装与配置\n\n### 相关页面\n\n相关主题：[项目介绍](#page-introduction), [快速开始](#page-quick-start)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [docs/content/docs/installation.mdx](https://github.com/openvideodev/openvideo/blob/main/docs/content/docs/installation.mdx)\n- [packages/openvideo/package.json](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/package.json)\n- [package.json](https://github.com/openvideodev/openvideo/blob/main/package.json)\n- [packages/node/README.md](https://github.com/openvideodev/openvideo/blob/main/packages/node/README.md)\n- [packages/openvideo/README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n- [packages/node/package.json](https://github.com/openvideodev/openvideo/blob/main/packages/node/package.json)\n</details>\n\n# 安装与配置\n\nOpenVideo 是一个基于 WebCodecs API 的高性能视频处理和渲染库，支持在浏览器和 Node.js 环境中进行视频合成、编辑和导出。本页面详细介绍 OpenVideo 项目的安装流程、依赖要求以及各平台的配置方法。\n\n## 系统要求\n\n### 浏览器环境要求\n\nOpenVideo 核心库依赖 WebCodecs API 进行硬件加速的视频编解码处理。根据 `packages/openvideo/package.json` 中的信息，浏览器环境需要满足以下要求：\n\n| 组件 | 最低要求 | 说明 |\n|------|---------|------|\n| WebCodecs API | 必须支持 | 用于视频编码和解码的核心 API |\n| 浏览器版本 | Chrome 94+ / Edge 94+ / Opera 80+ | 主流浏览器需开启相关特性标志 |\n| ES Modules | 必须支持 | 包使用 ES Module 格式发布 |\n| OPFS API | 推荐支持 | 用于本地大文件存储，提升性能 |\n\nWebCodecs API 在部分浏览器中可能需要手动启用特性标志。Chromium 内核浏览器可通过以下方式启用：\n\n```javascript\n// 启用 WebCodecs API\nawait navigator.mediaCapabilities.decodingInfo({\n  type: 'file',\n  video: { type: 'video/mp4', width: 1920, height: 1080, bitrate: 5000000 }\n});\n```\n\n资料来源：[packages/openvideo/package.json:1-35]()\n\n### Node.js 环境要求\n\n当使用 `@combo/node` 包进行服务端视频渲染时，需要满足以下条件：\n\n| 要求 | 版本 | 说明 |\n|------|------|------|\n| Node.js | >= 18 | 需要支持 ES Modules 和部分 Web API |\n| Playwright | 最新版 | 用于无头浏览器环境运行渲染 |\n| 操作系统 | Windows/macOS/Linux | 支持 Playwright 运行的所有平台 |\n\n资料来源：[packages/node/README.md:1-100]()\n\n## 安装方式\n\n### 使用 pnpm（推荐）\n\nOpenVideo 采用 Monorepo 结构管理多个包，推荐使用 pnpm 进行安装：\n\n```bash\n# 安装根依赖\npnpm install\n\n# 安装 openvideo 核心包\npnpm --filter openvideo build\n\n# 安装 Node.js 渲染包\npnpm --filter @combo/node build\n```\n\n资料来源：[packages/openvideo/package.json:1-40]()\n\n### 使用 npm\n\n```bash\n# 安装核心库\nnpm install openvideo\n\n# 安装 Node.js 渲染包\nnpm install @combo/node\n```\n\n### 使用 yarn\n\n```bash\n# 安装核心库\nyarn add openvideo\n\n# 安装 Node.js 渲染包\nyarn add @combo/node\n```\n\n### CDN 引入\n\n对于浏览器环境，可以直接通过 CDN 引入 OpenVideo：\n\n```html\n<script type=\"importmap\">\n{\n  \"imports\": {\n    \"openvideo\": \"https://unpkg.com/openvideo/dist/index.es.js\"\n  }\n}\n</script>\n<script type=\"module\">\n  import { Compositor, Studio } from 'openvideo';\n  // 使用 OpenVideo API\n</script>\n```\n\n资料来源：[packages/node/src/template.html:1-20]()\n\n## 包结构说明\n\nOpenVideo 项目包含多个子包，每个包承担特定功能：\n\n### 核心包 (openvideo)\n\n| 属性 | 值 | 说明 |\n|------|---|------|\n| 包名 | openvideo | 核心视频处理库 |\n| 版本 | 0.2.18 | 当前稳定版本 |\n| 入口 (main) | dist/index.umd.js | UMD 格式，用于传统 script 标签 |\n| 入口 (module) | dist/index.es.js | ES Module 格式 |\n| 类型定义 | dist/index.d.ts | TypeScript 类型定义 |\n\n```json\n{\n  \"name\": \"openvideo\",\n  \"version\": \"0.2.18\",\n  \"main\": \"dist/index.umd.js\",\n  \"module\": \"dist/index.es.js\",\n  \"types\": \"dist/index.d.ts\"\n}\n```\n\n资料来源：[packages/openvideo/package.json:1-20]()\n\n### Node.js 渲染包 (@combo/node)\n\n用于在 Node.js 环境中进行服务端视频渲染，通过 Playwright 控制无头浏览器执行渲染任务：\n\n```json\n{\n  \"name\": \"@combo/node\",\n  \"dependencies\": {\n    \"playwright\": \"latest\"\n  }\n}\n```\n\n资料来源：[packages/node/package.json]()\n\n## 核心组件导入\n\n### 浏览器环境导入\n\n```typescript\n// 方式一：从完整包导入\nimport { Studio, Compositor, Video, Audio, Text, Image } from 'openvideo';\n\n// 方式二：按需导入（Tree-shaking 友好）\nimport { Studio } from 'openvideo';\nimport { Compositor } from 'openvideo';\nimport { Video } from 'openvideo/clips/video-clip';\n```\n\n### Node.js 环境导入\n\n```typescript\nimport { Renderer } from '@combo/node';\n\nconst renderer = new Renderer({\n  json: videoConfig,\n  outputPath: './output.mp4'\n});\n\nrenderer.on('progress', ({ phase, progress }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n});\n\nawait renderer.render();\n```\n\n资料来源：[packages/node/README.md:80-120]()\n\n## 构建配置\n\n### 浏览器端构建\n\nOpenVideo 使用 Vite 进行构建，生成 UMD 和 ES Module 两种格式：\n\n```bash\n# 在 packages/openvideo 目录下\npnpm build\n```\n\n构建产物包含：\n\n| 文件 | 格式 | 用途 |\n|------|------|------|\n| dist/index.umd.js | UMD | 兼容 AMD/CommonJS/全局变量 |\n| dist/index.es.js | ES Module | 现代浏览器和打包工具 |\n| dist/index.d.ts | TypeScript | 类型定义 |\n\n资料来源：[packages/openvideo/package.json:20-35]()\n\n### Node.js 包构建\n\n```bash\n# 构建 Node.js 渲染包\npnpm --filter @combo/node build\n```\n\n构建后需复制 HTML 模板到 dist 目录：\n\n```bash\n# 复制模板文件\ncp src/template.html dist/template.html\n```\n\n资料来源：[packages/node/README.md:40-80]()\n\n## 渲染器配置\n\n### Compositor 配置选项\n\n在浏览器环境中，Compositor 是核心渲染引擎：\n\n```typescript\nconst compositorOpts = {\n  width: 1920,           // 视频宽度\n  height: 1080,          // 视频高度\n  fps: 30,               // 帧率\n  bgColor: '#000000',    // 背景颜色\n  videoCodec: 'avc1.64001f',  // 视频编码器（可选）\n  bitrate: 5000000,      // 比特率（可选）\n  audio: true,           // 是否包含音频\n  metaDataTags: {        // 元数据标签（可选）\n    title: 'My Video',\n    author: 'Creator'\n  }\n};\n\nconst compositor = new Compositor(compositorOpts);\nawait compositor.initPixiApp();\n```\n\n资料来源：[packages/node/src/template.html:30-60]()\n\n### Renderer 配置选项（Node.js）\n\n| 选项 | 类型 | 必填 | 默认值 | 说明 |\n|------|------|------|--------|------|\n| json | object | 是 | - | 视频配置 JSON 对象 |\n| outputPath | string | 是 | - | 输出文件路径 |\n| browserOptions | object | 否 | 见下文 | 浏览器配置 |\n\n**browserOptions 子选项：**\n\n| 选项 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| headless | boolean | true | 是否使用无头模式 |\n| timeout | number | 300000 | 超时时间（毫秒） |\n\n```typescript\nconst renderer = new Renderer({\n  json: videoConfig,\n  outputPath: './output.mp4',\n  browserOptions: {\n    headless: true,\n    timeout: 600000  // 10 分钟\n  }\n});\n```\n\n资料来源：[packages/node/README.md:100-140]()\n\n## 快速开始示例\n\n### 浏览器端视频编辑\n\n```typescript\nimport { Studio, Video, Audio } from 'openvideo';\n\n// 1. 创建 Studio 实例\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\n// 2. 加载并添加视频片段\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 3. 添加音频\nconst audio = await Audio.fromUrl('https://example.com/audio.mp3');\nawait studio.addClip(audio);\n\n// 4. 开始预览\nstudio.play();\n```\n\n资料来源：[README.md:1-50]()\n\n### 服务端批量渲染\n\n```typescript\nimport { Renderer } from '@combo/node';\n\n// 批量渲染配置\nconst videos = [\n  { config: videoConfig1, output: 'output1.mp4' },\n  { config: videoConfig2, output: 'output2.mp4' }\n];\n\nfor (const { config, output } of videos) {\n  const renderer = new Renderer({\n    json: config,\n    outputPath: output\n  });\n  \n  renderer.on('progress', ({ phase, progress }) => {\n    console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n  });\n  \n  await renderer.render();\n  console.log(`✅ 已生成: ${output}`);\n}\n```\n\n## 开发环境配置\n\n### TypeScript 配置\n\n确保 tsconfig.json 正确配置模块解析：\n\n```json\n{\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"target\": \"ES2020\",\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"]\n  }\n}\n```\n\n### 开发工作流\n\n```mermaid\ngraph TD\n    A[修改源代码] --> B[运行构建命令]\n    B --> C{目标平台}\n    C -->|浏览器| D[pnpm --filter openvideo build]\n    C -->|Node.js| E[pnpm --filter @combo/node build]\n    D --> F[测试功能]\n    E --> F\n    F --> G{验证通过?}\n    G -->|是| H[提交代码]\n    G -->|否| A\n```\n\n开发调试步骤：\n\n1. **修改源代码** - 在 `packages/openvideo/src/` 或 `packages/node/src/` 目录下修改代码\n2. **重新构建** - 运行相应的构建命令\n3. **运行测试** - 执行 `pnpm test` 验证功能\n4. **调试运行** - 在 Node.js 中测试 `node dist/sample.js`\n\n资料来源：[packages/node/README.md:60-90]()\n\n## 常见问题排查\n\n### Playwright 安装失败\n\n```bash\n# 手动安装 Chromium\nnpx playwright install chromium\n```\n\n### 模块解析错误\n\n确保 openvideo 包已构建：\n\n```bash\npnpm --filter openvideo build\n```\n\n### 渲染超时\n\n增加浏览器超时时间：\n\n```typescript\nbrowserOptions: {\n  timeout: 600000  // 10 分钟\n}\n```\n\n### WebCodecs 不可用\n\n检查浏览器是否支持 WebCodecs：\n\n```javascript\nif ('VideoDecoder' in window) {\n  console.log('WebCodecs API 支持正常');\n} else {\n  console.error('浏览器不支持 WebCodecs API');\n}\n```\n\n## 技术栈依赖\n\nOpenVideo 基于以下核心技术构建：\n\n| 技术 | 用途 | 版本要求 |\n|------|------|----------|\n| WebCodecs | 硬件加速视频编解码 | 现代浏览器 |\n| PixiJS | 2D 渲染引擎 | 最新稳定版 |\n| wrapbox | MP4 容器操作 | 内置工具库 |\n| Playwright | 无头浏览器控制 | Node.js 环境 |\n\n核心组件架构：\n\n```mermaid\ngraph TB\n    subgraph \"用户层\"\n        A[Studio API]\n        B[Compositor API]\n        C[Clip API]\n    end\n    \n    subgraph \"渲染引擎层\"\n        D[PixiJS Renderer]\n        E[WebCodecs Encoder]\n        F[WebCodecs Decoder]\n    end\n    \n    subgraph \"文件处理层\"\n        G[MP4 Muxer]\n        H[wrapbox]\n        I[OPFS Manager]\n    end\n    \n    A --> D\n    B --> E\n    C --> F\n    D --> G\n    E --> G\n    F --> I\n    G --> H\n```\n\n资料来源：[README.md:50-80]()\n\n## 下一步\n\n完成安装配置后，建议继续阅读以下文档：\n\n- [快速开始指南](./quickstart.mdx) - 了解核心使用流程\n- [API 参考](./api-reference.mdx) - 完整的 API 文档\n- [示例项目](../examples/index.md) - 实际应用案例\n\n---\n\n<a id='page-quick-start'></a>\n\n## 快速开始\n\n### 相关页面\n\n相关主题：[安装与配置](#page-installation), [Studio - 项目状态管理](#page-studio)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio.ts)\n- [examples/src/App.tsx](https://github.com/openvideodev/openvideo/blob/main/examples/src/App.tsx)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/package.json](https://github.com/openvideov/openvideo/blob/main/packages/openvideo/package.json)\n- [README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n</details>\n\n# 快速开始\n\n本文档将帮助你在 5 分钟内快速上手 OpenVideo，掌握视频渲染项目的基本创建、剪辑添加和预览播放流程。\n\n---\n\n## 环境要求\n\n| 要求 | 版本说明 |\n|------|----------|\n| Node.js | >= 18 |\n| 包管理器 | pnpm（推荐） |\n| 浏览器 | 支持 WebCodecs API 的现代浏览器（Chrome、Edge、Firefox） |\n\n**安装依赖：**\n\n```bash\n# 克隆项目\ngit clone https://github.com/openvideodev/openvideo.git\ncd openvideo\n\n# 安装项目依赖\npnpm install\n\n# 构建核心包\npnpm --filter openvideo build\n```\n\n资料来源：[README.md:1-50]()\n\n---\n\n## 核心概念\n\nOpenVideo 的架构围绕三个核心组件展开：**Studio**（工作室）、**Compositor**（合成器）和 **Clips**（剪辑片段）。\n\n### 组件架构图\n\n```mermaid\ngraph TD\n    A[Studio] --> B[Compositor]\n    A --> C[Clips]\n    C --> D[Video]\n    C --> E[Audio]\n    C --> F[Text]\n    C --> G[Image]\n    C --> H[Caption]\n    B --> I[WebCodecs]\n    B --> J[PixiJS]\n    I --> K[MP4 Output]\n```\n\n| 组件 | 职责 |\n|------|------|\n| **Studio** | 管理项目状态、时间轴、轨道和剪辑 |\n| **Compositor** | 渲染引擎，处理播放、seek 和最终导出 |\n| **Clips** | 不同媒体类型的专用对象 |\n\n资料来源：[README.md:50-80]()\n\n---\n\n## 基本使用流程\n\n### 1. 创建 Studio 实例\n\n首先，需要在 HTML 中创建一个 `<canvas>` 元素用于渲染：\n\n```html\n<canvas id=\"preview-canvas\"></canvas>\n```\n\n然后在 JavaScript/TypeScript 中初始化 Studio：\n\n```typescript\nimport { Studio } from 'openvideo';\n\n// 获取 canvas 元素\nconst canvas = document.getElementById('preview-canvas') as HTMLCanvasElement;\n\n// 创建 Studio 实例\nconst studio = new Studio({\n  canvas,\n  width: 1280,\n  height: 720,\n  spacing: 20  // 可选：剪辑间距\n});\n\n// 等待初始化完成\nawait studio.ready;\n```\n\n资料来源：[examples/src/App.tsx:1-30]()\n\n### 2. 添加视频剪辑\n\n使用 `Video.fromUrl()` 从 URL 加载视频并添加到时间轴：\n\n```typescript\nimport { Studio, Video } from 'openvideo';\n\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\n// 加载并添加视频剪辑\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 也可以设置位置和尺寸\nconst video2 = await Video.fromUrl('https://example.com/video2.mp4', {\n  x: 100,\n  y: 200,\n  width: 640,\n  height: 360\n});\nawait studio.addClip(video2);\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:80-120]()\n\n### 3. 添加文本剪辑\n\n使用 `Text` 类创建文本覆盖层：\n\n```typescript\nimport { Studio, Text } from 'openvideo';\n\nconst text = new Text('Hello World');\ntext.duration = 5000000;  // 5秒（微秒单位）\nawait studio.addClip(text);\n```\n\n资料来源：[packages/openvideo/src/studio.ts:1-50]()\n\n### 4. 启动预览播放\n\n```typescript\n// 开始播放\nstudio.play();\n\n// 暂停\nstudio.pause();\n\n// 跳转时间\nstudio.seek(2000000);  // 2秒位置\n```\n\n---\n\n## 完整示例代码\n\n以下是一个完整的快速开始示例：\n\n```typescript\nimport { Studio, Video, Text } from 'openvideo';\n\n// 1. 初始化 Studio\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\n// 2. 加载并添加视频\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 3. 添加文本叠加\nconst title = new Text('OpenVideo Quick Start');\ntitle.duration = 5000000;  // 5秒\nawait studio.addClip(title);\n\n// 4. 开始预览\nstudio.play();\n```\n\n---\n\n## 项目结构\n\n```\nopenvideo/\n├── packages/\n│   ├── openvideo/              # 核心渲染库\n│   │   ├── src/\n│   │   │   ├── studio.ts       # Studio 主类\n│   │   │   ├── compositor.ts  # 渲染引擎\n│   │   │   └── clips/          # 各类剪辑\n│   │   └── dist/               # 构建输出\n│   └── node/                   # Node.js 渲染包\n├── examples/                   # 示例应用\n└── docs/                       # 文档\n```\n\n资料来源：[README.md:1-30]()\n\n---\n\n## 核心 API 概览\n\n### Studio 类\n\n| 方法 | 说明 |\n|------|------|\n| `addClip(clip)` | 添加剪辑到时间轴 |\n| `removeClip(id)` | 从时间轴移除剪辑 |\n| `play()` | 开始播放 |\n| `pause()` | 暂停播放 |\n| `seek(time)` | 跳转到指定时间（微秒） |\n| `destroy()` | 销毁实例，释放资源 |\n\n### 可用剪辑类型\n\n| 类型 | 类名 | 说明 |\n|------|------|------|\n| 视频 | `Video` | 加载和播放视频文件 |\n| 音频 | `Audio` | 加载和播放音频文件 |\n| 文本 | `Text` | 文本叠加层 |\n| 图片 | `Image` | 静态图像 |\n| 字幕 | `Caption` | 带动画的字幕 |\n| 特效 | `Effect` | 视频特效 |\n\n资料来源：[packages/openvideo/src/studio.ts:50-100]()\n\n---\n\n## 下一步\n\n- **深入学习**：查看 [基础用法文档](./basic-usage.mdx) 了解更多高级功能\n- **技术栈**：OpenVideo 基于 [WebCodecs](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API)（硬件加速视频处理）和 [PixiJS](https://pixijs.com/)（2D/3D 渲染引擎）\n- **示例项目**：参考 `examples/` 目录中的完整示例\n\n资料来源：[README.md:80-100]()\n\n---\n\n<a id='page-architecture'></a>\n\n## 系统架构\n\n### 相关页面\n\n相关主题：[Studio - 项目状态管理](#page-studio), [Compositor - 渲染引擎](#page-compositor)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio.ts)\n- [packages/openvideo/src/compositor.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/compositor.ts)\n- [packages/openvideo/src/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/index.ts)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/transition/transition.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/transition/transition.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n- [packages/node/src/template.html](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/template.html)\n- [packages/node/src/renderer.ts](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/renderer.ts)\n- [README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n</details>\n\n# 系统架构\n\n## 概述\n\nOpenVideo 是一个基于 Web 技术的视频渲染和处理库，其核心设计围绕**客户端视频合成**展开。该项目利用现代浏览器原生 API（主要是 WebCodecs）实现硬件加速的视频编解码，并通过 PixiJS 提供高性能的 2D/3D 渲染能力。 资料来源：[README.md]()\n\n系统的设计目标是提供一个纯前端实现的视频编辑框架，使开发者能够在浏览器环境中完成从素材加载、合成编辑到最终 MP4 输出的完整流程。架构上采用分层设计，核心层负责渲染引擎与媒体处理，节点层提供服务端自动化渲染能力。 资料来源：[packages/openvideo/package.json:1-14]()\n\n## 核心架构分层\n\nOpenVideo 系统采用三层架构设计，从上至下分别为：\n\n| 层级 | 组件 | 职责 |\n|------|------|------|\n| 应用层 | Studio | 项目状态管理、时间线编排、轨道与剪辑管理 |\n| 渲染层 | Compositor | PixiJS 应用初始化、帧渲染、播放控制、导出编码 |\n| 媒体层 | Clips、MP4 Utils | 视频/音频/文本等素材解码、MP4 封装与解封装 |\n\n```mermaid\ngraph TD\n    A[用户应用] --> B[Studio<br/>项目状态管理层]\n    B --> C[Compositor<br/>渲染引擎]\n    C --> D[PixiJS 渲染器]\n    C --> E[WebCodecs 编码器]\n    D --> F[Canvas 2D/WebGL]\n    E --> G[MP4 文件输出]\n    H[Clips 素材层] --> B\n    I[Node Renderer<br/>服务端自动化] --> E\n```\n\n资料来源：[README.md:30-45]()\n\n## 核心组件详解\n\n### Studio（项目状态管理）\n\nStudio 是整个系统的状态管理中心，负责管理项目配置、轨道布局、剪辑排列以及时间线相关的逻辑。它维护着项目中所有的轨道（Track）和剪辑（Clip）对象，并协调它们与 Compositor 之间的数据交互。\n\n主要职责包括：\n\n- **项目配置管理**：存储和管理视频的全局设置（如分辨率、帧率、背景色等）\n- **轨道管理**：维护多个轨道的层级关系，处理轨道的添加、删除、排序\n- **剪辑调度**：管理每个轨道上的剪辑对象，处理剪辑之间的对齐、重叠逻辑\n- **播放控制**：协调 Compositor 的播放、暂停、寻址操作\n\nStudio 的设计使得开发者可以通过声明式的方式定义视频结构，然后交由下层的渲染引擎执行具体的画面合成。 资料来源：[packages/openvideo/src/studio.ts]()\n\n### Compositor（渲染引擎）\n\nCompositor 是整个系统的核心渲染引擎，负责将 Studio 管理的轨道和剪辑数据转换为可视化的帧序列，并最终输出为 MP4 文件。它是衔接上层业务逻辑与底层媒体 API 的关键桥梁。\n\n```mermaid\ngraph LR\n    A[轨道数据] --> B[Compositor]\n    B --> C[PixiJS 应用]\n    C --> D[Canvas 渲染]\n    B --> E[VideoFrame]\n    E --> F[WebCodecs<br/>VideoEncoder]\n    F --> G[MP4 Muxer]\n    G --> H[output.mp4]\n```\n\nCompositor 的初始化过程如下：\n\n1. 创建 WebCodecs VideoEncoder 和 AudioEncoder 实例\n2. 初始化 PixiJS Application 作为 2D 渲染上下文\n3. 加载并解析所有轨道上的剪辑资源\n4. 设置事件监听器用于进度报告和错误处理\n\n渲染流程中，Compositor 按照指定帧率（默认 30fps）驱动 PixiJS 渲染每一帧画面，同时将 VideoFrame 数据送入 VideoEncoder 进行编码。编码后的样本（Sample）被传递给 MP4 封装器生成最终的输出文件。 资料来源：[packages/openvideo/src/compositor.ts]()\n\nCompositor 的核心配置选项：\n\n| 参数 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| width | number | 1280 | 输出视频宽度（像素） |\n| height | number | 720 | 输出视频高度（像素） |\n| fps | number | 30 | 输出帧率 |\n| bgColor | string | '#000000' | 背景颜色 |\n| videoCodec | string | - | 视频编码器标识 |\n| bitrate | number | - | 视频码率（bps） |\n| audio | boolean | true | 是否包含音频轨道 |\n| metaDataTags | object | - | MP4 元数据标签 |\n\n资料来源：[packages/node/src/template.html:20-40]()\n\n### Clips（素材剪辑）\n\nClips 是处理各类媒体素材的专门对象体系，每种媒体类型对应一个独立的 Clip 类。Clip 对象负责素材的加载、解码、以及在渲染时向 Compositor 提供对应的画面数据。\n\n#### 剪辑类型体系\n\n| 剪辑类型 | 类名 | 功能描述 |\n|----------|------|----------|\n| 视频剪辑 | Video | 加载并解码 MP4/WebM 视频流 |\n| 音频剪辑 | Audio | 处理音频轨道和音量控制 |\n| 文本剪辑 | Text | 渲染文字内容，支持样式和动画 |\n| 图像剪辑 | Image | 加载并显示静态图片 |\n| 字幕剪辑 | Caption | 时间轴驱动的字幕渲染 |\n\n#### Video Clip 实现\n\nVideo Clip 是最复杂的剪辑类型，它整合了资源加载、流解码和帧提取三个环节。核心逻辑位于 `video-clip.ts`：\n\n```mermaid\ngraph TD\n    A[Video.fromUrl<br/>静态工厂方法] --> B[ResourceManager<br/>获取可读流]\n    B --> C[new Video<br/>实例化剪辑]\n    C --> D[write<br/>写入 OPFS]\n    D --> E[ready promise<br/>等待解码完成]\n    E --> F[本地文件引用]\n```\n\n构造函数接受三种数据源类型：\n\n1. `ReadableStream<Uint8Array>` - 直接传入的流数据\n2. `OPFSToolFile` - 已存在于 OPFS（Origin Private File System）中的文件\n3. `MPClipCloneArgs` - 用于克隆已有剪辑状态的参数对象\n\n音频处理通过 `opts.audio` 参数控制，支持布尔值和对象两种配置方式。当为对象时，可通过 `volume` 属性独立控制音量。 资料来源：[packages/openvideo/src/clips/video-clip.ts:50-80]()\n\n#### Text Clip 实现\n\nText Clip 负责文字内容的渲染，其样式系统基于 PixiJS 的 TextStyle 构建，支持丰富的排版选项：\n\n- **字体样式**：fontFamily、fontWeight、fontStyle\n- **颜色填充**：支持纯色和渐变填充（gradient）\n- **描边效果**：stroke 对象定义描边颜色、宽度、连接方式和尖角样式\n- **阴影效果**：dropShadow 配置阴影颜色、透明度、模糊度和偏移\n\n渐变填充需要使用 `FillGradient` 类创建，通过 `x0`、`y0`、`x1`、`y1` 定义渐变向量方向，色彩数组通过 `ratio` 和 `color` 指定各节点的位置和颜色。 资料来源：[packages/openvideo/src/clips/text-clip.ts:60-100]()\n\n### 过渡效果系统（Transitions）\n\nTransition 系统负责处理轨道之间的画面切换效果。该系统支持多种内置过渡类型，每种过渡都有对应的 GLSL 着色器实现。\n\n#### 支持的过渡效果\n\n| 过渡名称 | 说明 | 匹配变体 |\n|----------|------|----------|\n| GridFlip | 网格翻转 | gridflip、GridFlip、grid_flip |\n| Circle | 圆形展开 | circle、circle_open |\n| Directional | 方向性擦除 | directional、directional_wipe |\n| UndulatingBurnOut | 波动燃烧 | undulatingburnout、UndulatingBurnOut |\n| SquaresWire | 方形线框 | squareswire、SquaresWire |\n| RotateScaleFade | 旋转缩放淡入淡出 | rotateScaleFade、rotatescalefade |\n| RandomSquares | 随机方块 | randomSquares、RandomSquares |\n| PolkaDotsCurtain | 圆点幕布 | polkadotscurtain、PolkaDotsCurtain |\n| Pixelize | 像素化 | pixelize、Pixelize |\n\n过渡名称的解析采用宽松匹配策略，支持驼峰命名、下划线分隔、全大写等多种变体形式。解析流程首先在用户传入的过渡对象中查找，然后搜索内置过渡注册表，最后尝试各种命名变体。 资料来源：[packages/openvideo/src/transition/transition.ts:1-80]()\n\n### 动画预设系统（Animation Presets）\n\n动画预设提供预定义的补间动画（tween）模式，可应用于剪辑的位置、缩放、透明度等属性变化。\n\n#### 支持的预设动画\n\n| 预设名称 | 描述 | 关键帧示例 |\n|----------|------|------------|\n| slideIn | 从指定方向滑入 | 0%: 外部位置 → 100%: 目标位置 |\n| slideOut | 向指定方向滑出 | 0%: 当前位置 → 100%: 外部位置 |\n| pulse | 脉冲缩放效果 | 0%→25%→50%→75%→100% 循环缩放 |\n| blurIn | 模糊淡入 | 0%: 高模糊低透明度 → 100%: 无模糊完全透明 |\n\n动画参数通过 `normalized` 对象自定义，slideIn/slideOut 预设支持：\n\n- `direction`: 方向（left、right、top、bottom）\n- `distance`: 移动距离（像素）\n- `duration`: 持续时间（毫秒，由调用方控制） 资料来源：[packages/openvideo/src/animation/presets.ts:20-60]()\n\n## 媒体封装与解封装\n\n### MP4 Utils 模块\n\nMP4 Utils 模块（位于 `src/mp4-utils/index.ts`）负责 MP4 文件格式的解析和生成，是实现视频导入和导出的底层基础设施。\n\n#### 时间戳规范化\n\n视频和音频样本的时间戳（ DTS / CTS ）在封装前需要经过规范化处理，确保时间线从零开始：\n\n1. 记录第一个视频样本和音频样本的时间戳作为基准\n2. 所有后续样本的 DTS 和 CTS 减去对应基准值\n3. 加上调用方指定的偏移量（offsetDTS / offsetCTS）\n\n这种处理方式保证了多轨道合成的正确性，使得音频和视频能够精确同步。 资料来源：[packages/openvideo/src/mp4-utils/index.ts:80-120]()\n\n#### 样本数据结构\n\n样本数据通过 `addSample` 方法添加到 MP4 文件中，每个样本包含：\n\n| 属性 | 类型 | 说明 |\n|------|------|------|\n| trackId | number | 所属轨道 ID |\n| data | Uint8Array | 编码后的样本数据 |\n| duration | number | 样本持续时间 |\n| dts | number | 解码时间戳 |\n| cts | number | composition 时间戳 |\n| is_sync | boolean | 是否为同步帧（关键帧） |\n\n### Thumbnail 生成器\n\n视频剪辑包含独立的缩略图生成功能，使用独立的 VideoDecoder 实例进行解码。解码器支持软件降级模式（`downgrade = true`），当硬件加速不可用时自动回退到软件解码以提高兼容性。\n\n错误处理机制会捕获解码器状态、队列长度和输入输出计数，便于诊断缩略图生成失败的原因。 资料来源：[packages/openvideo/src/clips/video-clip.ts:120-160]()\n\n## Node.js 渲染层\n\n### Renderer 类架构\n\nNode.js 包（`@combo/node`）提供了服务端自动化渲染能力，通过 Playwright 控制无头浏览器执行 HTML 模板中的渲染逻辑。\n\n```mermaid\ngraph TD\n    A[new Renderer<br/>配置初始化] --> B[render<br/>开始渲染]\n    B --> C[启动本地 HTTP 服务器]\n    C --> D[Playwright 启动 Chromium]\n    D --> E[加载 template.html]\n    E --> F[注入 RENDER_CONFIG]\n    F --> G[执行 Compositor<br/>WebCodecs 编码]\n    G --> H[触发 download 事件]\n    H --> I[保存文件到 outputPath]\n    I --> J[返回输出路径]\n```\n\nRenderer 继承自 EventEmitter，暴露三个事件：\n\n| 事件名称 | 回调参数 | 触发时机 |\n|----------|----------|----------|\n| progress | `{ phase, progress, message }` | 各阶段进度更新 |\n| error | `Error` | 渲染过程中发生错误 |\n| complete | `string` | 渲染完成，返回输出文件路径 |\n\n进度报告的阶段（phase）包括：initializing、loading、rendering、saving、complete。 资料来源：[packages/node/src/renderer.ts]()\n\n### HTML 渲染模板\n\n渲染模板（`template.html`）运行在浏览器环境中，负责：\n\n1. 从 `window.RENDER_CONFIG` 获取渲染配置\n2. 创建 Compositor 实例并初始化 PixiJS 应用\n3. 监听 Compositor 事件并向父进程报告进度\n4. 触发视频文件下载\n\n模板使用 Import Maps 解析 `openvideo` 包，确保模块能够正确加载：\n\n```html\n<script type=\"importmap\">\n{\n    \"imports\": {\n        \"openvideo\": \"/node_modules/openvideo/dist/index.es.js\"\n    }\n}\n</script>\n```\n\n配置参数通过 JSON 注入，支持设置分辨率、帧率、背景色、视频编码器、码率和元数据标签。 资料来源：[packages/node/src/template.html:1-50]()\n\n## 技术栈概览\n\n| 技术 | 用途 | 层级 |\n|------|------|------|\n| WebCodecs | 视频/音频编解码 | 媒体层 |\n| PixiJS | 2D 渲染引擎 | 渲染层 |\n| Compositor | 帧合成与导出 | 渲染层 |\n| wrapbox | MP4 Box 解析与写入 | 媒体层 |\n| Playwright | 浏览器自动化控制 | 节点层 |\n| TypeScript | 类型安全开发 | 全栈 |\n\nWebCodecs 提供硬件加速的视频编解码能力，是实现高性能渲染的关键技术。PixiJS 则负责处理文本、图像、过渡效果等视觉元素的渲染，两者的结合使得 OpenVideo 能够在浏览器环境中实现接近原生的视频处理性能。 资料来源：[README.md:45-55]()\n\n## 包导出结构\n\nOpenVideo 主包（`openvideo`）通过 `src/index.ts` 统一导出所有公共 API：\n\n| 导出项 | 来源 | 说明 |\n|--------|------|------|\n| Studio | studio.ts | 项目状态管理类 |\n| Compositor | compositor.ts | 渲染引擎类 |\n| Video | video-clip.ts | 视频剪辑类 |\n| Text | text-clip.ts | 文本剪辑类 |\n| Caption | caption-clip.ts | 字幕剪辑类 |\n| Image | image-clip.ts | 图像剪辑类 |\n| Audio | audio-clip.ts | 音频剪辑类 |\n| JsonSerialization | serialization.ts | JSON 序列化工具 |\n\n包的入口配置支持 ES Modules 和 CommonJS 两种模块系统：\n\n```json\n{\n  \"main\": \"dist/index.umd.js\",\n  \"module\": \"dist/index.es.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.es.js\",\n      \"require\": \"./dist/index.umd.js\"\n    }\n  }\n}\n```\n\n资料来源：[packages/openvideo/package.json:15-30]()\n\n## 数据流总览\n\n```mermaid\ngraph LR\n    A[视频素材<br/>MP4/WebM] --> B[Video Clip<br/>解码器]\n    B --> C[VideoFrame]\n    D[音频素材<br/>MP4/WAV] --> E[Audio Clip<br/>解码器]\n    E --> F[AudioFrame]\n    G[文本内容] --> H[Text Clip<br/>PixiJS 渲染]\n    H --> I[Sprite/Texture]\n    C --> J[Compositor<br/>帧合成]\n    F --> J\n    I --> J\n    J --> K[VideoEncoder<br/>WebCodecs]\n    K --> L[EncodedVideoChunk]\n    L --> M[MP4 Muxer<br/>wrapbox]\n    M --> N[output.mp4]\n```\n\n整个数据流从素材输入开始，视频和音频素材分别由对应的 Clip 对象负责解码。Text Clip 生成的纹理与解码后的视频帧一同送入 Compositor 进行帧合成。合成后的画面通过 VideoEncoder 编码为压缩的 Chunk，最后由 MP4 Muxer 按照 ISO Base Media File Format 规范封装为最终的 MP4 文件。\n\n---\n\n<a id='page-studio'></a>\n\n## Studio - 项目状态管理\n\n### 相关页面\n\n相关主题：[系统架构](#page-architecture), [Compositor - 渲染引擎](#page-compositor), [剪辑系统](#page-clips)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio.ts)\n- [packages/openvideo/src/studio/selection-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/selection-manager.ts)\n- [packages/openvideo/src/studio/transport.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/transport.ts)\n- [packages/openvideo/src/studio/timeline-model.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/timeline-model.ts)\n- [packages/openvideo/src/studio/resource-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/resource-manager.ts)\n- [packages/openvideo/src/studio/history-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/history-manager.ts)\n</details>\n\n# Studio - 项目状态管理\n\n## 概述\n\nStudio 是 OpenVideo 库的核心模块，负责管理整个视频编辑项目的状态、轨道、剪辑片段和时间线配置。它作为顶层协调器，整合了时间轴模型、资源管理、选择管理、历史记录管理和播放传输等多个子系统，为用户提供完整的视频编辑体验。\n\nStudio 模块的核心职责包括：管理项目中的所有剪辑片段、协调各子系统之间的通信、处理播放控制、以及维护项目状态的序列化与反序列化。通过 EventEmitter 模式，Studio 实现了模块间的松耦合通信，确保状态变更能够及时传播到所有监听者。\n\n## 架构概览\n\nStudio 的架构采用分层设计，每个子系统专注于特定的功能领域。这种设计使得代码职责清晰，便于维护和扩展。\n\n```mermaid\ngraph TD\n    A[Studio 核心] --> B[TimelineModel 时间轴模型]\n    A --> C[ResourceManager 资源管理]\n    A --> D[SelectionManager 选择管理]\n    A --> E[HistoryManager 历史管理]\n    A --> F[Transport 播放传输]\n    A --> G[PixiJS 渲染引擎]\n    \n    B --> H[Tracks 轨道]\n    B --> I[Clips 剪辑片段]\n    \n    C --> J[文件系统]\n    C --> K[媒体资源]\n    \n    F --> L[播放状态]\n    F --> M[帧控制]\n    \n    G --> N[Canvas 画布]\n    G --> O[Sprites 精灵]\n```\n\n## 核心组件\n\n### TimelineModel（时间轴模型）\n\nTimelineModel 是 Studio 中最核心的数据结构，负责管理项目的时间线和轨道系统。每个 Studio 实例都持有一个 TimelineModel 实例，通过它可以访问和操作项目中的所有轨道和剪辑片段。\n\nTimelineModel 的主要职责包括：创建和管理轨道、添加和删除剪辑片段、更新剪辑属性、以及处理时间相关的计算。轨道（Track）是组织剪辑片段的容器，支持视频轨道、音频轨道、文字轨道等多种类型。\n\n| 方法 | 描述 | 返回值 |\n|------|------|--------|\n| `addTrack(type)` | 添加指定类型的轨道 | `Promise<Track>` |\n| `removeTrack(id)` | 移除指定轨道 | `Promise<void>` |\n| `addClip(trackId, clip)` | 在轨道中添加剪辑 | `Promise<Clip>` |\n| `removeClip(clipId)` | 移除剪辑片段 | `Promise<void>` |\n| `updateSelected(updates)` | 更新选中的剪辑 | `Promise<void>` |\n| `clear()` | 清空所有轨道和剪辑 | `Promise<void>` |\n\n资料来源：[packages/openvideo/src/studio/timeline-model.ts]()\n\n### ResourceManager（资源管理）\n\nResourceManager 负责管理系统中的媒体资源，包括视频、音频、图片等文件的加载和缓存。它提供了统一的资源获取接口，支持从 URL、OPFS（Origin Private File System）以及其他来源加载媒体资源。\n\nResourceManager 使用流式加载机制，能够高效处理大型媒体文件。它还维护了一个资源缓存池，避免重复加载相同的资源。当项目序列化时，ResourceManager 负责将资源引用转换为可序列化的格式，并在反序列化时重建资源连接。\n\n```typescript\n// 从 URL 加载视频资源\nconst stream = await ResourceManager.getReadableStream(url);\n\n// 加载并配置视频剪辑\nconst clip = new Video(stream, {}, url);\n```\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts]()\n\n### HistoryManager（历史管理）\n\nHistoryManager 实现了撤销/重做功能，允许用户回退到之前的操作状态。它维护了一个操作历史栈，记录每次状态变更的快照。\n\n每次用户执行修改操作时（如移动剪辑、调整属性等），HistoryManager 会自动保存当前状态的快照。当用户请求撤销时，系统会从历史栈中弹出上一个状态并恢复。类似地，重做功能会重新应用被撤销的操作。\n\n| 属性 | 类型 | 描述 |\n|------|------|------|\n| `canUndo` | `boolean` | 是否可以执行撤销 |\n| `canRedo` | `boolean` | 是否可以执行重做 |\n| `historyStack` | `StateSnapshot[]` | 历史状态栈 |\n\n资料来源：[packages/openvideo/src/studio/history-manager.ts]()\n\n### SelectionManager（选择管理）\n\nSelectionManager 负责处理剪辑片段的选中状态和变换操作。当用户在画布上点击剪辑时，SelectionManager 会确定被选中的剪辑，并激活相应的变换控制器（Transformer）。\n\n变换控制器支持多种操作模式：移动（无手柄）、调整大小（四角和四边手柄）、旋转（角落外侧手柄）。SelectionManager 还实现了多选功能，通过 Shift 键可以同时选中多个剪辑，并对它们应用统一的变换操作。\n\n```typescript\n// 双击处理\nif (topmostClip.type === 'Text' || topmostClip.type === 'Caption') {\n    this.studio.emit('clip:dblclick', { clip: topmostClip });\n}\n\n// 多选支持\nthis.selectClip(topmostClip, e.shiftKey);\n```\n\n资料来源：[packages/openvideo/src/studio/selection-manager.ts:60-75]()\n\n### Transport（播放传输）\n\nTransport 模块控制项目的播放状态，包括播放、暂停、停止和跳转等操作。它维护了当前播放头位置，并负责协调渲染引擎按照指定的时间点进行画面渲染。\n\nTransport 提供了精细的帧级控制能力，支持逐帧前进和后退。这对于精确编辑和对齐剪辑片段非常有帮助。时间单位统一使用微秒（microseconds），确保时间计算的精度。\n\n| 方法 | 描述 |\n|------|------|\n| `play()` | 开始播放 |\n| `pause()` | 暂停播放 |\n| `stop()` | 停止播放并重置到开始位置 |\n| `seek(time)` | 跳转到指定时间（微秒） |\n| `frameNext()` | 前进一帧 |\n| `framePrev()` | 后退一帧 |\n\n资料来源：[packages/openvideo/src/studio/transport.ts]()\n\n## 状态管理机制\n\n### 事件驱动架构\n\nStudio 继承自 EventEmitter，实现了完整的事件驱动架构。所有状态变更都通过事件进行传播，监听者可以订阅感兴趣的事件并做出响应。\n\n```mermaid\ngraph LR\n    A[状态变更] --> B[emit 事件]\n    B --> C[EventEmitter]\n    C --> D[进度监听器]\n    C --> E[完成监听器]\n    C --> F[错误监听器]\n    C --> G[重置监听器]\n```\n\nStudio 核心事件列表：\n\n| 事件名 | 回调参数 | 描述 |\n|--------|----------|------|\n| `progress` | `{ phase, progress, message }` | 渲染进度更新 |\n| `complete` | `outputPath` | 渲染完成 |\n| `error` | `Error` | 错误发生 |\n| `reset` | - | 项目重置/清空 |\n| `clip:dblclick` | `{ clip }` | 剪辑片段双击 |\n\n### 状态重置流程\n\n当调用 `clear()` 方法时，Studio 会执行完整的状态重置流程。这包括清空时间轴、销毁 PixiJS 纹理资源、清理过渡渲染器等。\n\n```typescript\nasync clear(): Promise<void> {\n    // 清空时间轴\n    await this.timeline.clear();\n\n    // 销毁过渡纹理\n    if (this.transFromTexture) {\n        this.transFromTexture.destroy(true);\n        this.transFromTexture = null;\n    }\n    if (this.transToTexture) {\n        this.transToTexture.destroy(true);\n        this.transToTexture = null;\n    }\n    \n    // 销毁过渡渲染器和精灵\n    this.transitionRenderers.forEach((r: any) => r.destroy());\n    this.transitionRenderers.clear();\n    this.transitionSprites.forEach((s) => s.destroy());\n    this.transitionSprites.clear();\n\n    this.emit(\"reset\");\n}\n```\n\n资料来源：[packages/openvideo/src/studio.ts:280-302]()\n\n## PixiJS 渲染集成\n\nStudio 与 PixiJS 紧密集成，利用其强大的 2D 渲染能力来显示和操作项目中的视觉元素。每个剪辑片段都被渲染为 PixiJS 的 Sprite（精灵）对象，支持缩放、旋转、透明度等变换操作。\n\n渲染管道的主要组件包括：\n\n- **SpriteRenderers**：负责将每个剪辑渲染为对应的 Sprite\n- **TransitionRenderers**：处理过渡效果的专用渲染器\n- **ActiveTransformer**：用户交互时的变换控制器\n- **Artboard**：画布容器，承载所有视觉元素\n\n渲染状态通过 `pixiApp.render()` 方法触发更新，确保画面与数据状态保持同步。\n\n## 使用示例\n\n### 基础使用\n\n```typescript\nimport { Studio } from 'openvideo';\n\n// 创建 Studio 实例\nconst studio = new Studio({\n    previewCanvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n    spacing: 20\n});\n\n// 添加剪辑\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 开始预览\nstudio.play();\n```\n\n### 进度跟踪\n\n```typescript\nstudio.on('progress', ({ phase, progress, message }) => {\n    console.log(`[${phase}] ${Math.round(progress * 100)}% - ${message}`);\n});\n\nstudio.on('complete', (outputPath) => {\n    console.log(`✅ 视频保存至: ${outputPath}`);\n});\n\nstudio.on('error', (error) => {\n    console.error('渲染失败:', error);\n});\n```\n\n## 相关文档\n\n- [Compositor 渲染引擎](../compositor/overview)\n- [剪辑片段系统](../clips/overview)\n- [过渡效果系统](../transitions/overview)\n- [JSON 序列化](../serialization/overview)\n\n---\n\n<a id='page-compositor'></a>\n\n## Compositor - 渲染引擎\n\n### 相关页面\n\n相关主题：[系统架构](#page-architecture), [Studio - 项目状态管理](#page-studio)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/node/src/template.html](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/template.html)\n- [packages/openvideo/render.html](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/render.html)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/clips/caption-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/caption-clip.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n- [packages/openvideo/src/animation/presets.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/animation/presets.ts)\n- [packages/openvideo/src/transition/transition.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/transition/transition.ts)\n</details>\n\n# Compositor - 渲染引擎\n\n## 概述\n\nCompositor（合成器）是 OpenVideo 项目中的核心渲染引擎，负责视频的最终合成、编码和导出工作。它基于 WebCodecs API 实现硬件加速的视频编码，结合 PixiJS 进行 2D/3D 图形渲染，为开发者提供高性能的客户端视频渲染能力。\n\nCompositor 的核心职责包括：\n- 初始化 PixiJS 应用作为渲染画布\n- 接收来自 Studio 的视频帧数据进行合成\n- 使用 WebCodecs VideoEncoder 将帧编码为 MP4 格式\n- 管理音频轨道和音视频同步\n- 支持多种视频编码器和比特率配置\n\n资料来源：[packages/openvideo/render.html:42-60]()\n\n## 架构设计\n\n### 组件层级关系\n\nCompositor 在整个渲染管线中处于下游位置，接收来自 Studio 和各种 Clip（视频、文本、图像等）的渲染数据。\n\n```mermaid\ngraph TD\n    A[Studio 项目容器] --> B[Timeline 时间轴]\n    B --> C[Track 轨道]\n    C --> D[Clip 媒体片段]\n    \n    D --> E[VideoClip 视频片段]\n    D --> F[TextClip 文本片段]\n    D --> G[ImageClip 图像片段]\n    D --> H[CaptionClip 字幕片段]\n    D --> I[AudioClip 音频片段]\n    \n    E --> J[Compositor 渲染引擎]\n    F --> J\n    G --> J\n    H --> J\n    I --> J\n    \n    J --> K[PixiJS 渲染层]\n    J --> L[WebCodecs VideoEncoder]\n    J --> M[MP4 Muxer]\n    \n    K --> N[Canvas 画布渲染]\n    L --> O[Encoded Video Frames]\n    M --> P[output.mp4]\n```\n\n### 渲染流程\n\n```mermaid\nsequenceDiagram\n    participant User as 用户代码\n    participant Studio as Studio\n    participant Compositor as Compositor\n    participant PixiJS as PixiJS\n    participant Encoder as VideoEncoder\n    participant Muxer as MP4 Muxer\n\n    User->>Compositor: new Compositor(options)\n    Compositor->>PixiJS: initPixiApp()\n    PixiJS-->>Compositor: App initialized\n    \n    User->>Studio: addClip(clip)\n    Studio->>Compositor: 注册渲染任务\n    \n    User->>Compositor: 开始播放/render\n    Compositor->>PixiJS: 逐帧渲染\n    PixiJS-->>Compositor: VideoFrame\n    \n    Compositor->>Encoder: encode(frame)\n    Encoder-->>Compositor: EncodedChunk\n    \n    Compositor->>Muxer: addSample()\n    Muxer-->>Compositor: MP4 Container\n    \n    Compositor-->>User: 输出文件路径\n```\n\n## 初始化配置\n\n### 构造函数选项\n\n创建 Compositor 实例时需要传入配置对象，控制输出视频的基本参数。\n\n| 参数 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| `width` | `number` | `1280` | 输出视频宽度（像素） |\n| `height` | `number` | `720` | 输出视频高度（像素） |\n| `fps` | `number` | `30` | 输出帧率（fps） |\n| `bgColor` | `string` | `#000000` | 背景颜色（十六进制） |\n| `videoCodec` | `string` | - | 视频编码器标识符 |\n| `bitrate` | `number` | - | 视频比特率（bps） |\n| `audio` | `boolean` | `true` | 是否包含音频轨道 |\n| `metaDataTags` | `object` | - | MP4 元数据标签 |\n\n资料来源：[packages/openvideo/render.html:35-50]()\n\n### 初始化流程\n\n```typescript\n// 典型初始化代码\nconst compositorOpts = {\n  width: settings.width || 1280,\n  height: settings.height || 720,\n  fps: settings.fps || 30,\n  bgColor: settings.bgColor || '#000000',\n};\n\nif (settings.videoCodec) {\n  compositorOpts.videoCodec = settings.videoCodec;\n}\nif (settings.bitrate) {\n  compositorOpts.bitrate = settings.bitrate;\n}\nif (settings.audio === false) {\n  compositorOpts.audio = false;\n}\nif (settings.metaDataTags) {\n  compositorOpts.metaDataTags = settings.metaDataTags;\n}\n\nconst compositor = new Compositor(compositorOpts);\nawait compositor.initPixiApp();\n```\n\n资料来源：[packages/node/src/template.html:38-58]()\n\n## 事件系统\n\nCompositor 继承自 EventEmitter，提供了完善的事件机制用于监控渲染进度。\n\n### OutputProgress 事件\n\n用于追踪视频编码进度：\n\n```typescript\ncompositor.on('OutputProgress', (progress: {\n  progress: number;   // 0-1 之间的进度值\n  phase: string;      // 当前阶段\n  message?: string;   // 可选的状态消息\n}) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n});\n```\n\n### 渲染阶段\n\n| 阶段标识 | 说明 |\n|---------|------|\n| `initializing` | 初始化阶段 |\n| `loading` | 加载资源阶段 |\n| `rendering` | 正在渲染阶段 |\n| `saving` | 保存文件阶段 |\n| `complete` | 完成阶段 |\n\n## 视频编码底层实现\n\n### MP4 样本处理\n\nCompositor 内部使用 MP4-box 库处理 MP4 容器格式，核心功能包括：\n\n1. **时间戳归一化**：将所有样本的时间戳归一化到以 0 为起点\n2. **轨道管理**：分别为视频和音频创建独立的 track\n3. **样本交织**：正确处理 DTS（解码时间戳）和 CTS（组合时间戳）\n\n```typescript\n// 时间戳归一化逻辑\nif (firstVDTS === null) {\n  firstVDTS = s.dts;\n  firstVCTS = s.cts;\n}\n// 归一化到从 0 开始，然后加上偏移\nnormalizedDTS = s.dts - firstVDTS!;\nnormalizedCTS = s.cts - (firstVCTS ?? 0);\n```\n\n资料来源：[packages/openvideo/src/mp4-utils/index.ts:45-65]()\n\n### 视频解码与降级\n\n对于缩略图生成等场景，Compositor 依赖的解码器支持硬件加速降级：\n\n```typescript\nfunction createVideoDec(downgrade = false) {\n  const encoderConf = {\n    ...decConf,\n    ...(downgrade ? { hardwareAcceleration: \"prefer-software\" } : {}),\n  } as VideoDecoderConfig;\n  // 首次尝试硬件加速，失败后降级到软件解码\n}\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:89-105]()\n\n## 渲染模式与动画支持\n\n### 动画预设\n\nCompositor 支持丰富的动画预设，通过 PixiJS 实现平滑过渡效果：\n\n| 动画类型 | 效果说明 |\n|---------|---------|\n| `fadeIn` | 淡入效果 |\n| `fadeOut` | 淡出效果 |\n| `slideIn` | 滑入效果（支持方向和距离配置） |\n| `slideOut` | 滑出效果 |\n| `pulse` | 脉冲效果 |\n| `blurIn` | 模糊淡入 |\n| `blurOut` | 模糊淡出 |\n\n```typescript\n// 滑出动画配置示例\ncase \"slideOut\": {\n  const direction = normalized?.direction || \"left\";\n  const distance = normalized?.distance || 300;\n  return {\n    \"0%\": { x: xPositionInit ?? 0, opacity: opacityInit ?? 1 },\n    \"100%\": {\n      x: direction === \"left\" ? -distance : distance,\n      opacity: opacityEnd ?? 0,\n    },\n  };\n}\n```\n\n资料来源：[packages/openvideo/src/animation/presets.ts:45-70]()\n\n### 转场效果\n\nCompositor 支持多种转场效果，通过 GLSL Shader 实现：\n\n| 转场名称 | 类型标识 | 说明 |\n|---------|---------|------|\n| `GridFlip` | `gridflip` | 网格翻转 |\n| `CircleOpen` | `circleopen` | 圆形展开 |\n| `Directional` | `directional` | 方向性渐变 |\n| `UndulatingBurnOut` | `undulatingburnout` | 波浪燃烧 |\n| `SquaresWire` | `squareswire` | 方块线条 |\n| `RotateScaleFade` | `rotatescalefade` | 旋转缩放淡入淡出 |\n| `PolkaDotsCurtain` | `polkadotscurtain` | 圆点幕布 |\n| `Pixelize` | `pixelize` | 像素化 |\n| `Heart` | `heart` | 心形效果 |\n| `Displacement` | `displacement` | 置换效果 |\n| `DirectionalWipe` | `directionalwipe` | 方向性擦除 |\n| `Crosshatch` | `crosshatch` | 十字阴影 |\n\n```typescript\nif (transitionCircleOpen) {\n  transitionGlsl = CIRCLE_FRAGMENT;\n  transitionUniforms = {\n    ...uniforms.basics,\n    ...CIRCLEOPEN_UNIFORMS,\n  };\n}\n```\n\n资料来源：[packages/openvideo/src/transition/transition.ts:35-50]()\n\n## 文本渲染\n\nCompositor 通过 TextClip 支持丰富的文本样式配置：\n\n| 样式属性 | 类型 | 说明 |\n|---------|------|------|\n| `fontSize` | `number` | 字体大小 |\n| `fontFamily` | `string` | 字体系列 |\n| `fontWeight` | `string\\|number` | 字重 |\n| `fontStyle` | `string` | 字体样式（normal/italic） |\n| `fill` | `string\\|number` | 填充颜色 |\n| `align` | `string` | 文本对齐 |\n| `wordWrap` | `boolean` | 是否自动换行 |\n| `wordWrapWidth` | `number` | 换行宽度 |\n| `lineHeight` | `number` | 行高 |\n| `letterSpacing` | `number` | 字间距 |\n| `stroke` | `object` | 描边配置 |\n| `dropShadow` | `object` | 阴影配置 |\n\n```typescript\nif (this.originalOpts.stroke) {\n  if (typeof this.originalOpts.stroke === 'object') {\n    style.stroke = {\n      color: this.originalOpts.stroke.color,\n      width: this.originalOpts.stroke.width,\n      join: this.originalOpts.stroke.join,\n      cap: this.originalOpts.stroke.cap,\n      miterLimit: this.originalOpts.stroke.miterLimit,\n    };\n  }\n}\n```\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:85-105]()\n\n## 字幕支持\n\nCaptionClip 提供专业的字幕渲染功能，支持动态颜色变化和词动画：\n\n```typescript\n// 字幕颜色状态配置\nif (processedOpts.caption?.colors?.appeared !== undefined)\n  this.opts.appeared = processedOpts.caption.colors.appeared;\nif (processedOpts.caption?.colors?.active !== undefined)\n  this.opts.active = processedOpts.caption.colors.active;\nif (processedOpts.caption?.colors?.keyword !== undefined)\n  this.opts.keyword = processedOpts.caption.colors.keyword;\n```\n\n支持的功能包括：\n- 渐变色填充文本\n- 关键词高亮颜色保持\n- 单词级动画效果\n- 背景色和描边样式\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:50-75]()\n\n## 使用示例\n\n### 基础渲染流程\n\n```typescript\nimport { Compositor } from 'openvideo';\n\nasync function renderVideo() {\n  const compositor = new Compositor({\n    width: 1920,\n    height: 1080,\n    fps: 30,\n    bgColor: '#000000',\n    bitrate: 5_000_000,\n  });\n\n  await compositor.initPixiApp();\n\n  compositor.on('OutputProgress', (progress) => {\n    console.log(`[${progress.phase}] ${Math.round(progress.progress * 100)}%`);\n  });\n\n  // 添加片段并触发渲染...\n}\n```\n\n### 与 Renderer 集成\n\n在 Node.js 环境下，通常使用 Renderer 类包装 Compositor：\n\n```typescript\nimport { Renderer } from '@combo/node';\n\nconst renderer = new Renderer({\n  json: videoConfig,\n  outputPath: './output.mp4',\n});\n\nrenderer.on('progress', ({ phase, progress, message }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}% - ${message}`);\n});\n\nawait renderer.render();\nconsole.log('视频渲染完成！');\n```\n\n资料来源：[packages/node/README.md:90-120]()\n\n## 总结\n\nCompositor 是 OpenVideo 项目的核心渲染引擎，通过整合 WebCodecs 和 PixiJS 两大技术栈，为开发者提供了：\n\n- **高性能编码**：利用浏览器原生 WebCodecs API 实现硬件加速视频编码\n- **灵活配置**：支持多种分辨率、帧率、编码器和比特率组合\n- **丰富视觉效果**：内置大量动画预设和转场效果\n- **完善的事件系统**：实时反馈渲染进度，便于构建用户界面\n- **跨平台兼容**：基于 Web 标准，可在桌面和移动浏览器中运行\n\nCompositor 的设计遵循模块化原则，与上层的 Studio、Clip 系统松耦合，同时通过标准化的事件机制保证各组件间的有效通信。\n\n---\n\n<a id='page-clips'></a>\n\n## 剪辑系统\n\n### 相关页面\n\n相关主题：[视频与音频剪辑](#page-video-clip), [文字与字幕剪辑](#page-text-caption)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/clips/iclip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/iclip.ts)\n- [packages/openvideo/src/clips/base-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/base-clip.ts)\n- [packages/openvideo/src/clips/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/index.ts)\n- [packages/openvideo/src/clips/effect-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/effect-clip.ts)\n- [packages/openvideo/src/clips/transition-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/transition-clip.ts)\n</details>\n\n# 剪辑系统\n\n## 概述\n\n剪辑系统（Clip System）是 OpenVideo 项目的核心模块之一，负责管理和处理各种类型的媒体资源。该系统采用面向对象的设计思想，通过统一的接口定义和继承体系，支持视频、音频、文本、图像、字幕等多种媒体类型的剪辑操作。\n\n剪辑系统的设计目标是为开发者提供一个灵活、可扩展的媒体处理框架，使得创建复杂的视频编辑功能变得简单直观。系统通过抽象基类和接口定义，确保了不同类型剪辑之间的一致性，同时允许各类型保留其特有的属性和行为。\n\n## 架构设计\n\n### 类层次结构\n\n剪辑系统采用经典的继承层次结构，从顶层到底层依次为：接口层（IClip）、抽象基类层（BaseClip）、具体实现类层。每一层都有明确的职责划分，下层继承并扩展上层的功能。\n\n```mermaid\ngraph TD\n    A[IClip 接口] --> B[BaseClip 抽象基类]\n    B --> C[VideoClip 视频剪辑]\n    B --> D[AudioClip 音频剪辑]\n    B --> E[TextClip 文本剪辑]\n    B --> F[ImageClip 图像剪辑]\n    B --> G[CaptionClip 字幕剪辑]\n    B --> H[EffectClip 特效剪辑]\n    B --> I[TransitionClip 过渡剪辑]\n    \n    C --> C1[fromUrl 静态方法]\n    C --> C2[本地文件处理]\n    \n    H --> H1[内置特效]\n    H --> H2[自定义特效]\n    \n    I --> I1[过渡效果名称匹配]\n    I --> I2[GLSL着色器实现]\n```\n\n### 核心接口 IClip\n\nIClip 接口是整个剪辑系统的契约定义，所有剪辑类型都必须实现该接口规定的方法和属性。该接口定义了剪辑的基本行为规范，包括时间定位、状态管理、事件处理等核心功能。通过实现 IClip 接口，不同类型的剪辑可以在统一的方式下被 Studio 系统管理和调度。\n\n接口的设计遵循了最小化原则，仅包含最核心的方法签名，具体实现细节由各个子类自行决定。这种设计使得系统具有高度的灵活性，同时保持了接口的一致性和可预测性。\n\n### 抽象基类 BaseClip\n\nBaseClip 提供了所有剪辑类型的共同实现，是系统的核心基类。该类封装了剪辑共有的属性和方法，包括时间轴控制、位置尺寸设置、样式配置等通用功能。子类通过继承 BaseClip 自动获得这些基础能力，只需关注其特有的业务逻辑。\n\nBaseClip 的设计体现了代码复用原则，避免了子类之间的重复代码。同时，该基类预留了大量可扩展的钩子方法，允许子类在特定生命周期节点插入自定义逻辑。\n\n## 剪辑类型详解\n\n### 视频剪辑 VideoClip\n\n视频剪辑是系统中最重要的剪辑类型之一，负责处理视频媒体资源。该类型支持从网络 URL 创建实例，并自动下载和管理本地文件。VideoClip 提供了灵活的音视频控制选项，开发者可以独立控制音频的开关和音量大小。\n\n```typescript\n// 视频剪辑创建示例\nconst video = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 100,\n  y: 200,\n  width: 1280,\n  height: 720\n});\nstudio.addClip(video);\n```\n\n视频剪辑支持从 OPFS（Origin Private File System）文件、ReadableStream 或已存在的视频样本数据三种方式创建实例。这种多源支持的设计使得系统可以灵活应对不同的视频数据来源，无论是实时流、本地文件还是内存中的视频数据都能得到妥善处理。\n\n| 属性/方法 | 类型 | 说明 |\n|-----------|------|------|\n| fromUrl | 静态方法 | 从网络 URL 创建视频剪辑 |\n| src | string | 视频源路径 |\n| audio | boolean | 是否包含音频轨道 |\n| volume | number | 音量大小（0-1） |\n| localFile | OPFSToolFile | 本地缓存文件引用 |\n\n### 文本剪辑 TextClip\n\n文本剪辑用于在视频中添加文字内容。该类型支持丰富的样式配置，包括字体、字号、颜色、对齐方式、字间距、行高等属性。文本剪辑还支持文字换行功能，通过 wordWrapWidth 属性可以控制文字的最大宽度。\n\n文本剪辑的一个重要特性是支持文字描边（stroke）和投影（dropShadow）效果。描边可以通过颜色和宽度进行自定义配置，而投影效果则支持颜色、透明度、模糊度、距离和角度等多个参数的自由组合。\n\n### 字幕剪辑 CaptionClip\n\n字幕剪辑是专门为视频字幕场景设计的类型，它在 TextClip 的基础上增加了逐词高亮显示的动画功能。该类型支持词汇级别的颜色控制，可以为已显示词汇、当前活跃词汇、关键词等分别设置不同的颜色方案。\n\n| 颜色配置项 | 说明 |\n|-----------|------|\n| appeared | 已显示完成的词汇颜色 |\n| active | 当前正在播放的词汇颜色 |\n| activeFill | 当前词汇的填充颜色 |\n| background | 背景高亮颜色 |\n| keyword | 关键词颜色 |\n\n字幕剪辑还支持逐词动画效果（wordAnimation），可以为每个词汇的显示配置不同的动画样式。这种精细的控制能力使得字幕展示可以达到接近专业视频编辑软件的动态效果。\n\n### 特效剪辑 EffectClip\n\n特效剪辑用于在视频轨道上添加视觉特效。该类型支持多种内置特效，包括常见的淡入淡出、滑动、脉冲等预设动画。特效剪辑的设计允许开发者通过简单的配置参数快速应用复杂的视觉效果。\n\n```typescript\n// 预设特效配置示例\nconst presetAnimation = {\n  preset: \"blurIn\",\n  params: {\n    blurInit: 20,\n    blurEnd: 0,\n    opacityInit: 0,\n    opacityEnd: 1\n  }\n};\n```\n\n特效剪辑还支持多个方向的配置选项，包括左、右、上、下四个方向，以及不同的距离参数。这种灵活性使得特效的展示方式可以根据具体需求进行精确调整。\n\n### 过渡剪辑 TransitionClip\n\n过渡剪辑用于实现两个剪辑之间的切换效果。系统支持多种过渡类型，包括网格翻转、圆形展开、方向擦拭、不规则燃烧等多种视觉效果。过渡剪辑通过名称匹配机制识别所需的过渡效果，支持多种命名变体的识别。\n\n```mermaid\ngraph LR\n    A[剪辑 A] --> B[TransitionClip]\n    C[剪辑 B] --> B\n    B --> D[过渡效果输出]\n    \n    B --> E[名称匹配]\n    B --> F[GLSL 着色器]\n    B --> G[Uniform 参数]\n```\n\n过渡效果的实现依赖于 WebGL 着色器（Fragment Shader），每个过渡效果都有对应的 GLSL 代码和 Uniform 参数定义。这种基于着色器的实现方式确保了过渡效果的高性能和硬件加速支持。\n\n## 状态管理\n\n### 生命周期状态\n\n剪辑对象在运行时有多个生命周期状态，系统通过精细的状态转换机制确保对象在正确的时间执行相应的操作。状态转换遵循严格的规则，不允许跳跃式状态变更。\n\n```mermaid\nstateDiagram-v2\n    [*] --> 创建中: 构造函数\n    创建中 --> 已就绪: 初始化完成\n    已就绪 --> 播放中: play()\n    播放中 --> 已暂停: pause()\n    已暂停 --> 播放中: play()\n    播放中 --> 已结束: 时间到达终点\n    已结束 --> [*]: 销毁\n    已就绪 --> [*]: 销毁\n```\n\n### 事件系统\n\n剪辑系统使用事件发射器模式进行状态通知。主要事件包括进度事件（OutputProgress）、错误事件（error）和完成事件（complete）。开发者可以通过监听这些事件来跟踪剪辑的渲染进度或处理异常情况。\n\n```typescript\n// 事件监听示例\nclip.on('progress', ({ phase, progress, message }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}% - ${message}`);\n});\n\nclip.on('error', (error) => {\n  console.error('处理失败:', error);\n});\n\nclip.on('complete', () => {\n  console.log('剪辑处理完成');\n});\n```\n\n## 渲染流程\n\n### 渲染阶段划分\n\n视频渲染过程分为多个阶段，每个阶段都有明确的职责和输出：\n\n| 阶段名称 | 说明 | 典型耗时 |\n|---------|------|---------|\n| initializing | 初始化渲染器 | 1-5秒 |\n| loading | 加载媒体资源 | 取决于网络 |\n| rendering | 执行渲染计算 | 取决于视频时长 |\n| saving | 保存输出文件 | 取决于文件大小 |\n| complete | 渲染完成 | - |\n\n### 渲染配置选项\n\nCompositor 是实际执行渲染的核心类，它接收多种配置参数来控制输出视频的属性：\n\n```typescript\nconst compositorOpts = {\n  width: 1280,           // 输出宽度\n  height: 720,          // 输出高度\n  fps: 30,              // 帧率\n  bgColor: '#000000',    // 背景颜色\n  videoCodec: 'avc1.640028',  // 视频编码器\n  bitrate: 5000000,      // 比特率\n  audio: true,           // 是否包含音频\n  metaDataTags: {        // 元数据标签\n    title: 'My Video',\n    author: 'Creator'\n  }\n};\n```\n\n## 样式配置系统\n\n### 文字样式\n\n文字样式的配置采用分层设计，从基类继承通用样式属性，同时允许子类添加特定样式选项。主要的文字样式属性包括：\n\n- fontFamily：字体家族\n- fontSize：字号大小\n- fontWeight：字重粗细\n- fontStyle：斜体/正常\n- fill：填充颜色\n- align：对齐方式\n- letterSpacing：字间距\n- lineHeight：行高\n- wordWrap：自动换行\n- wordWrapWidth：换行宽度\n\n### 颜色系统\n\n系统支持多种颜色表示方式，包括十六进制颜色代码和数字格式。在字幕剪辑中，颜色配置被组织为嵌套结构，支持默认颜色、活跃颜色、背景颜色等多个维度的独立控制。\n\n### 渐变填充\n\n文本填充除了支持纯色外，还支持渐变色填充。渐变通过起点坐标（x0, y0）和终点坐标（x1, y1）定义方向，通过颜色数组和对应的比例值定义渐变色分布。\n\n## 与 Studio 的集成\n\n### 添加和移除剪辑\n\nStudio 类提供了 addClip 和 removeClip 方法用于管理项目中的剪辑。添加的剪辑会被自动编排到时间轴上，并根据其时间属性决定播放顺序。\n\n```typescript\n// 剪辑添加示例\nconst text = new Text(\"Hello World\");\ntext.duration = 5e6;  // 5秒（微秒单位）\nawait studio.addClip(text);\n\n// 移除剪辑\nawait studio.removeClip(text.id);\n```\n\n### 时间轴控制\n\nStudio 负责管理整个项目的时间轴配置，包括总时长、帧率等参数。每个添加到 Studio 的剪辑都会继承项目级的时间轴设置，同时保留覆盖这些设置的能力。\n\n## 扩展机制\n\n### 自定义特效\n\n系统提供了扩展接口允许开发者添加自定义特效。通过实现 EffectClip 的扩展接口，可以注册新的预设动画效果，这些效果会自动出现在可用的特效列表中。\n\n### 自定义过渡\n\n类似地，开发者可以通过扩展 TransitionClip 添加新的过渡效果。新的过渡效果需要提供对应的 GLSL 着色器代码和 Uniform 参数定义，完成注册后即可通过名称在项目中使用。\n\n## 总结\n\n剪辑系统是 OpenVideo 项目的基础模块，通过精心设计的类层次结构和接口规范，实现了多类型媒体的统一管理。该系统提供了从基础的视频、音频剪辑到高级的字幕、特效、过渡等多种功能，覆盖了视频编辑的核心需求。\n\n系统的架构设计充分考虑了扩展性和性能要求，通过基于 WebCodecs 和 WebGL 的底层实现，确保了视频处理的效率和跨平台兼容性。事件驱动的设计模式使得渲染进度的监控和错误处理变得简单可靠。\n\n---\n\n<a id='page-video-clip'></a>\n\n## 视频与音频剪辑\n\n### 相关页面\n\n相关主题：[剪辑系统](#page-clips), [Compositor - 渲染引擎](#page-compositor)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/audio-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/audio-clip.ts)\n- [packages/openvideo/src/clips/image-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/image-clip.ts)\n- [packages/openvideo/src/json-serialization.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/json-serialization.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n</details>\n\n# 视频与音频剪辑\n\n## 概述\n\n视频与音频剪辑是 openvideo 项目的核心功能模块，负责管理和处理各类媒体资源。该模块基于 WebCodecs API 实现硬件加速的视频解码与编码，支持从远程 URL 或本地文件系统加载媒体文件，并通过 PixiJS 渲染引擎实现高性能的 2D/3D 合成。\n\n剪辑系统采用面向对象的设计模式，定义了统一的 `BaseClip` 基类，所有具体剪辑类型（如 Video、Audio、Image、Text、Caption）都继承自该基类。这种设计确保了统一的接口规范和一致的渲染行为。\n\n## 核心类架构\n\n### 类继承体系\n\n```mermaid\ngraph TD\n    A[IClip 接口] --> B[BaseClip]\n    B --> C[Video]\n    B --> D[Audio]\n    B --> E[Image]\n    B --> F[Text]\n    B --> G[Caption]\n    B --> H[Placeholder]\n    \n    C -.->|实现| I[IPlaybackCapable]\n    \n    J[Compositor] --> K[渲染引擎]\n    C --> K\n    D --> K\n    E --> K\n    F --> K\n    G --> K\n```\n\n### 主要类说明\n\n| 类名 | 职责 | 源码位置 |\n|------|------|----------|\n| `Video` | 视频解码、帧提取、缩略图生成 | `video-clip.ts:1-100` |\n| `Audio` | 音频解码、音量控制 | `audio-clip.ts` |\n| `Image` | 静态图像加载与渲染 | `image-clip.ts` |\n| `Text` | 文本渲染与排版 | `text-clip.ts` |\n| `Caption` | 字幕样式与动画 | `caption-clip.ts` |\n\n## Video 剪辑详解\n\n### 基本用法\n\n`Video` 类是视频处理的核心组件，支持从 URL 异步加载 MP4 文件，并提供精确的帧级控制。\n\n```typescript\n// 从 URL 加载视频\nconst videoClip = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 0,\n  y: 0,\n  width: 1920,\n  height: 1080,\n});\n\n// 设置时间轴位置\nvideoClip.set({\n  display: {\n    from: 150,  // 起始帧\n    to: 450,    // 结束帧（30fps 下为 10 秒）\n  },\n});\n```\n\n### 构造函数参数\n\n```typescript\nconstructor(\n  source: OPFSToolFile | ReadableStream<Uint8Array> | MPClipCloneArgs,\n  opts: IMP4ClipOpts = {},\n  src?: string,\n)\n```\n\n| 参数 | 类型 | 说明 | 默认值 |\n|------|------|------|--------|\n| `source` | `OPFSToolFile \\| ReadableStream \\| MPClipCloneArgs` | 视频数据源 | 必需 |\n| `opts` | `IMP4ClipOpts` | 配置选项 | `{}` |\n| `src` | `string` | 视频源 URL | `\"\"` |\n\n### 配置选项 (IMP4ClipOpts)\n\n```typescript\ninterface IMP4ClipOpts {\n  audio?: boolean | { volume: number };\n  __unsafe_hardwareAcceleration__?: HardwarePreference;\n}\n```\n\n| 选项 | 类型 | 说明 |\n|------|------|------|\n| `audio` | `boolean \\| { volume: number }` | 音频开关或音量配置（0-1） |\n| `__unsafe_hardwareAcceleration__` | `HardwarePreference` | 硬件加速偏好设置 |\n\n资料来源：[video-clip.ts:50-70]()\n\n### 核心属性\n\n| 属性 | 类型 | 说明 |\n|------|------|------|\n| `type` | `\"Video\"` | 剪辑类型标识 |\n| `src` | `string` | 视频源 URL |\n| `audio` | `boolean` | 是否启用音频 |\n| `volume` | `number` | 音频音量（0-1） |\n| `ready` | `Promise<void>` | 加载完成状态 |\n| `_meta` | `object` | 元数据（duration, width, height） |\n\n### 帧数据处理流程\n\n```mermaid\nsequenceDiagram\n    participant User as 用户\n    participant Video as Video 类\n    participant ResourceManager as ResourceManager\n    participant Compositor as Compositor\n    \n    User->>Video: fromUrl(url)\n    Video->>ResourceManager: getReadableStream(url)\n    ResourceManager-->>Video: ReadableStream\n    Video->>Video: write(localFile, stream)\n    Video->>Video: await ready\n    Video->>Compositor: 渲染帧\n    Compositor-->>User: 显示视频\n```\n\n视频帧数据经过以下处理流程：\n\n1. **加载阶段**：通过 `ResourceManager.getReadableStream()` 获取可读流\n2. **存储阶段**：写入本地 OPFS 文件系统\n3. **解码阶段**：使用 WebCodecs VideoDecoder 进行 MP4 解析\n4. **渲染阶段**：通过 Compositor 和 PixiJS 渲染到画布\n\n资料来源：[mp4-utils/index.ts:20-60]()\n\n## Audio 剪辑\n\n### 音频配置\n\n音频剪辑支持灵活的音量控制和播放参数：\n\n```typescript\n// 启用音频\nconst video = await Video.fromUrl('video.mp4', {\n  audio: true,\n});\n\n// 音量控制\nconst videoWithVolume = await Video.fromUrl('video.mp4', {\n  audio: {\n    volume: 0.5,  // 50% 音量\n  },\n});\n\n// 禁用音频\nconst videoNoAudio = await Video.fromUrl('video.mp4', {\n  audio: false,\n});\n```\n\n音频参数处理逻辑如下：\n\n```typescript\nthis.audio = typeof this.opts.audio === \"boolean\" \n  ? this.opts.audio \n  : true;\n\nthis.volume = typeof opts.audio === \"object\" && \"volume\" in opts.audio\n  ? opts.audio.volume\n  : ((opts as any).volume ?? 1);\n```\n\n资料来源：[video-clip.ts:75-90]()\n\n## Image 剪辑\n\n### 图像加载\n\n`Image` 类支持从 URL 或 data URI 加载静态图像：\n\n```typescript\n// 从 URL 加载\nconst image = await ImageClip.fromUrl('https://example.com/image.png');\n\n// 设置位置和尺寸\nconst imageWithOpts = await ImageClip.fromUrl('image.png', {\n  x: 100,\n  y: 200,\n  width: 800,\n  height: 600,\n});\n```\n\n### 支持的图像格式\n\n| 格式 | MIME 类型 | 支持情况 |\n|------|-----------|----------|\n| PNG | `image/png` | 完全支持 |\n| JPEG | `image/jpeg` | 完全支持 |\n| WebP | `image/webp` | 完全支持 |\n| SVG | `image/svg+xml` | 需测试 |\n| Base64 | data URI | 完全支持 |\n\n## 剪辑通用属性\n\n所有剪辑类型共享以下核心属性：\n\n| 属性 | 类型 | 说明 | 适用剪辑 |\n|------|------|------|----------|\n| `id` | `string` | 唯一标识 | 全部 |\n| `src` | `string` | 资源路径 | Video, Audio, Image |\n| `left` | `number` | X 坐标 | 全部 |\n| `top` | `number` | Y 坐标 | 全部 |\n| `width` | `number` | 宽度 | 全部 |\n| `height` | `number` | 高度 | 全部 |\n| `angle` | `number` | 旋转角度 | 全部 |\n| `zIndex` | `number` | 层级 | 全部 |\n| `opacity` | `number` | 透明度 | 全部 |\n| `flip` | `\"horizontal\" \\| \"vertical\" \\| null` | 翻转方向 | 全部 |\n| `duration` | `number` | 时长（微秒） | 全部 |\n| `playbackRate` | `number` | 播放速率 | 全部 |\n\n资料来源：[json-serialization.ts:15-50]()\n\n## 时间轴与显示配置\n\n### display 属性\n\n```typescript\ndisplay: {\n  from: number;  // 起始帧\n  to: number;    // 结束帧\n};\n```\n\n```typescript\n// 设置 5 秒时长的剪辑\ntext.duration = 5e6;  // 5000000 微秒\n```\n\n### trim 属性（可选）\n\n```typescript\ntrim?: {\n  from: number;  // 裁剪起始点\n  to: number;    // 裁剪结束点\n};\n```\n\n## 特效与动画\n\n### 特效配置\n\n```typescript\neffects?: Array<{\n  id: string;\n  key: string;\n  startTime: number;\n  duration: number;\n  targets?: number[];\n}>;\n```\n\n### 动画配置\n\n```typescript\nanimation?: {\n  keyFrames: Record<string, Partial<{\n    x: number;\n    y: number;\n    w: number;\n    h: number;\n    angle: number;\n    opacity: number;\n  }>>;\n  opts: {\n    duration: number;\n    delay?: number;\n    iterCount?: number;\n  };\n};\n```\n\n资料来源：[json-serialization.ts:50-75]()\n\n## JSON 序列化\n\n### BaseClipJSON 接口\n\n```typescript\ninterface BaseClipJSON {\n  id?: string;\n  name?: string;\n  metadata?: Record<string, any>;\n  effects?: Array<{...}>;\n  src: string;\n  display: {\n    from: number;\n    to: number;\n  };\n  playbackRate: number;\n  duration: number;\n  left: number;\n  top: number;\n  width: number;\n  height: number;\n  angle: number;\n  zIndex: number;\n  opacity: number;\n  flip: \"horizontal\" | \"vertical\" | null;\n  trim?: { from: number; to: number };\n  transition?: ITransitionInfo;\n  style?: any;\n  locked?: boolean;\n  colorAdjustment?: ColorAdjustment;\n  animation?: {...};\n  animations?: Array<{...}>;\n}\n```\n\n### 导出示例\n\n```typescript\nimport { JsonSerialization } from 'openvideo';\n\nconst projectJson = JsonSerialization.toJSON(studio);\nconsole.log(JSON.stringify(projectJson, null, 2));\n```\n\n## 在 Studio 中使用剪辑\n\n### 添加剪辑到时间轴\n\n```typescript\nconst studio = new Studio({\n  canvas: document.getElementById('canvas'),\n  width: 1920,\n  height: 1080,\n});\n\nawait studio.ready;\n\n// 添加视频剪辑\nconst video = await Video.fromUrl('video.mp4');\nawait studio.addClip(video);\n\n// 添加图像剪辑\nconst image = await ImageClip.fromUrl('image.png');\nawait studio.addClip(image);\n```\n\n### 移除剪辑\n\n```typescript\nawait studio.removeClip(video.id);\n```\n\n### 替换剪辑\n\n```typescript\nawait studio.timeline.replaceClipsBySource(\n  'old-video.mp4',\n  async (oldClip) => {\n    return await Video.fromUrl('new-video.mp4');\n  }\n);\n```\n\n资料来源：[studio.spec.ts:30-60]()\n\n## 工作流程图\n\n```mermaid\ngraph LR\n    A[加载媒体] --> B[解析 MP4/图像]\n    B --> C[创建 Clip 实例]\n    C --> D[添加到 Studio]\n    D --> E[配置 Timeline]\n    E --> F[Compositor 渲染]\n    F --> G[输出视频]\n    \n    H[JSON 序列化] -.-> C\n    I[反序列化] -.-> C\n```\n\n## 最佳实践\n\n### 1. 异步加载\n\n始终使用 `await` 等待资源加载完成：\n\n```typescript\nconst video = await Video.fromUrl('video.mp4');\nawait studio.addClip(video);\nawait studio.ready;\n```\n\n### 2. 资源清理\n\n使用完剪辑后及时销毁释放内存：\n\n```typescript\nvideo.destroy();\nstudio.destroy();\n```\n\n### 3. 缩略图生成\n\n使用 `ThumbnailOpts` 生成视频缩略图：\n\n```typescript\nconst thumbnails = await video.getThumbnails({\n  start: 0,\n  end: video.duration,\n  step: 300,  // 每 10 秒一帧（30fps）\n});\n```\n\n### 4. 批量替换\n\n使用 `replaceClipsBySource` 进行批量替换：\n\n```typescript\nawait studio.timeline.replaceClipsBySource(\n  'old.mp4',\n  async (oldClip) => Video.fromUrl('new.mp4')\n);\n```\n\n## 总结\n\nopenvideo 的视频与音频剪辑模块提供了完整的媒体处理能力，支持从 URL 加载各类媒体资源，并通过统一的接口规范实现灵活的剪辑管理。开发者可以通过继承 `BaseClip` 创建自定义剪辑类型，通过 Compositor 实现高性能渲染，并通过 JSON 序列化实现项目持久化存储。该模块充分利用 WebCodecs API 和 PixiJS 渲染引擎，为 Web 环境下的专业视频编辑提供了坚实的技术基础。\n\n---\n\n<a id='page-text-caption'></a>\n\n## 文字与字幕剪辑\n\n### 相关页面\n\n相关主题：[剪辑系统](#page-clips)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/clips/caption-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/caption-clip.ts)\n- [packages/openvideo/src/utils/fonts.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/fonts.ts)\n- [packages/openvideo/src/utils/srt-parser.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/srt-parser.ts)\n- [packages/openvideo/src/studio/timeline-model.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/timeline-model.ts)\n- [packages/openvideo/src/animation/presets.ts](https://github.com/openvideov/openvideo/blob/main/packages/openvideo/src/animation/presets.ts)\n</details>\n\n# 文字与字幕剪辑\n\n## 概述\n\n文字与字幕剪辑是 OpenVideo 视频编辑器中的核心功能模块，负责处理视频中的文字渲染和字幕显示。该模块包含两个主要组件：**TextClip（文字剪辑）** 和 **CaptionClip（字幕剪辑）**，它们共享底层的 PixiJS 渲染引擎，但面向不同的使用场景。\n\n**TextClip** 适用于静态或动态文字叠加，如标题、水印、动态文字效果；**CaptionClip** 则专注于字幕功能，支持逐字高亮、词动画、SRT 格式解析等高级特性。\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:1-50]()\n\n## 架构设计\n\n### 组件关系图\n\n```mermaid\ngraph TD\n    A[Studio] --> B[TextClip]\n    A --> C[CaptionClip]\n    B --> D[SplitBitmapText]\n    C --> E[Word-Level Animation]\n    B --> F[PixiJS Container]\n    C --> F\n    D --> G[CanvasTextMetrics]\n    F --> H[PixiJS Renderer]\n    I[SRT Parser] --> C\n    J[FontManager] --> B\n    J --> C\n```\n\n### 核心职责划分\n\n| 组件 | 职责 | 继承关系 |\n|------|------|----------|\n| `TextClip` | 基础文字渲染，支持 stroke、shadow、wordWrap | ClipBase |\n| `CaptionClip` | 字幕渲染，支持逐词动画、颜色状态 | ClipBase |\n| `SplitBitmapText` | 文字分词渲染单元 | PIXI.Text |\n| `FontManager` | 字体加载与管理 | - |\n| `SRTParser` | SRT 字幕格式解析 | - |\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:1-30]()\n\n## TextClip 文字剪辑\n\n### 功能特性\n\nTextClip 提供了丰富的文字渲染能力，支持以下特性：\n\n- **字体样式**：fontFamily、fontSize、fontWeight、fontStyle\n- **文本装饰**：stroke（描边）、dropShadow（阴影）\n- **布局控制**：align、wordWrap、wordWrapWidth、lineHeight、letterSpacing\n- **颜色填充**：支持纯色和渐变填充\n- **文字分词**：将文本拆分为独立的单词进行渲染\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:100-180]()\n\n### 渲染流程\n\n```mermaid\nsequenceDiagram\n    participant User as 用户\n    participant TextClip as TextClip\n    participant Container as PixiJS Container\n    participant WordTexts as SplitBitmapText[]\n    \n    User->>TextClip: 设置文本内容\n    TextClip->>TextClip: 解析样式选项\n    TextClip->>TextClip: 拆分单词数组\n    TextClip->>TextClip: 计算行布局\n    TextClip->>Container: 创建/更新容器\n    Loop 每个单词\n        TextClip->>WordTexts: 创建 SplitBitmapText\n        Container->>WordTexts: 添加到容器\n    end\n    TextClip->>Container: 应用变换和动画\n```\n\n### 样式配置\n\nTextClip 支持从多种来源读取样式配置，包括剪辑自身的选项和外部传入的样式对象：\n\n```typescript\ninterface ITextOpts {\n  // 基础样式\n  text?: string;\n  fontFamily?: string;\n  fontSize?: number;\n  fontWeight?: string | number;\n  fontStyle?: 'normal' | 'italic';\n  fill?: number | string | FillGradient;\n  \n  // 布局\n  align?: 'left' | 'center' | 'right';\n  wordWrap?: boolean;\n  wordWrapWidth?: number;\n  lineHeight?: number;\n  letterSpacing?: number;\n  \n  // 装饰\n  stroke?: string | { color: string; width: number; join?: string; cap?: string; miterLimit?: number };\n  strokeWidth?: number;\n  dropShadow?: {\n    color?: string;\n    alpha?: number;\n    blur?: number;\n    distance?: number;\n    angle?: number;\n  };\n  \n  // 垂直对齐\n  verticalAlign?: 'top' | 'middle' | 'bottom';\n}\n```\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:80-150]()\n\n### 文本布局算法\n\nTextClip 使用智能换行算法来计算文字布局：\n\n1. **空格宽度计算**：使用 CanvasTextMetrics 和 SplitBitmapText 两种方式计算空格宽度，取较大值\n2. **换行宽度判断**：根据 wordWrapWidth 确定是否需要换行\n3. **行分配**：将单词依次分配到各行，计算每行的总宽度和高度\n4. **垂直对齐处理**：根据 verticalAlign 调整行在容器中的位置\n\n```typescript\n// 行宽计算逻辑\nconst wrapWidth = style.wordWrap && style.wordWrapWidth > 0 \n  ? style.wordWrapWidth \n  : 1e5;\n\nconst lines: { words: SplitBitmapText[]; width: number; height: number }[] = [];\nlet currentLineWords: SplitBitmapText[] = [];\nlet currentLineWidth = 0;\n```\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:200-280]()\n\n## CaptionClip 字幕剪辑\n\n### 功能特性\n\nCaptionClip 是专为字幕场景设计的剪辑类型，提供了比 TextClip 更丰富的字幕功能：\n\n- **逐词动画**：支持每个单词独立的动画效果\n- **颜色状态**：区分\"已出现(appeared)\"、\"激活(active)\"、\"背景(background)\"等状态\n- **关键词高亮**：支持特定关键词的颜色标记\n- **SRT 解析**：内置 SRT 字幕文件解析器\n- **保留关键词颜色**：在动画过程中保持关键词颜色不变\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:50-120]()\n\n### 字幕颜色系统\n\nCaptionClip 维护了一套完整的颜色状态系统：\n\n| 状态 | 说明 | 配置键 |\n|------|------|--------|\n| appeared | 已显示完成的单词 | colors.appeared |\n| active | 当前正在高亮的单词 | colors.active |\n| activeFill | 激活单词的填充色 | colors.activeFill |\n| background | 未激活单词的颜色 | colors.background |\n| keyword | 关键词的特殊颜色 | colors.keyword |\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:80-110]()\n\n### 颜色配置示例\n\n```typescript\nconst captionClip = new CaptionClip({\n  text: \"Hello world\",\n  colors: {\n    appeared: 0x888888,    // 已显示文字灰色\n    active: 0xFFFFFF,      // 当前高亮白色\n    activeFill: 0xFFFF00,  // 高亮填充黄色\n    background: 0x333333,  // 背景色深灰\n    keyword: 0x00FF00      // 关键词绿色\n  },\n  preserveKeywordColor: true // 保持关键词颜色\n});\n```\n\n### 渐变填充支持\n\nCaptionClip 支持使用 FillGradient 实现渐变文字效果：\n\n```typescript\nif (this.opts.fill && typeof this.opts.fill === 'object' && this.opts.fill.type === 'gradient') {\n  const gradient = new FillGradient(\n    this.opts.fill.x0,\n    this.opts.fill.y0,\n    this.opts.fill.x1,\n    this.opts.fill.y1\n  );\n  this.opts.fill.colors.forEach(\n    ({ ratio, color }: { ratio: number; color: string | number }) => {\n      const colorNumber = typeof color === 'number' \n        ? color \n        : (parseColor(color) ?? 0xffffff);\n      gradient.addColorStop(ratio, colorNumber);\n    }\n  );\n}\n```\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:150-200]()\n\n## SRT 字幕解析\n\n### SRTParser 模块\n\nOpenVideo 提供了内置的 SRT 格式解析器，可以将标准 SRT 字幕文件转换为内部格式：\n\n```mermaid\ngraph LR\n    A[SRT 文件] --> B[SRTParser]\n    B --> C[字幕片段数组]\n    C --> D[startTime, endTime]\n    C --> E[text]\n    D --> F[CaptionClip]\n```\n\n### 解析流程\n\n1. **时间码解析**：将 `00:00:01,000 --> 00:00:05,000` 格式转换为微秒时间戳\n2. **文本提取**：获取字幕片段中的文字内容\n3. **片段组合**：将多个连续片段合并为单个字幕项\n4. **格式输出**：输出符合 CaptionClip 输入格式的数据\n\n资料来源：[packages/openvideo/src/utils/srt-parser.ts]()\n\n## 字体管理\n\n### FontManager\n\n字体管理模块负责动态加载自定义字体，确保文字渲染使用正确的字形：\n\n```mermaid\ngraph TD\n    A[TimelineModel] --> B[FontManager]\n    B --> C{字体已缓存?}\n    C -->|是| D[直接使用]\n    C -->|否| E[加载字体]\n    E --> F[FontFace API]\n    F --> G[添加到 document.fonts]\n    G --> D\n    D --> H[渲染文字]\n```\n\n### 字体加载策略\n\nFontManager 会扫描所有剪辑中的字体引用，统一进行加载：\n\n```typescript\n// 检查普通文字样式中的字体\nif (clip.style?.fontUrl || (clip as any).fontUrl) {\n  fontsToLoad.set(fontUrl, {\n    name: clip.style?.fontFamily || (clip as any).fontFamily || \"CustomFont\",\n    url: fontUrl,\n  });\n}\n\n// 检查字幕样式中的字体\nif (clip.type === \"Caption\") {\n  const fontUrl = clip.style?.fontUrl || (clip as any).fontUrl;\n  if (fontUrl) {\n    fontsToLoad.set(fontUrl, { ... });\n  }\n}\n```\n\n资料来源：[packages/openvideo/src/studio/timeline-model.ts:200-260]()\n\n## 动画预设\n\n### 内置动画类型\n\nOpenVideo 为文字和字幕剪辑提供了丰富的预设动画：\n\n| 动画类型 | 说明 | 参数 |\n|----------|------|------|\n| fadeIn | 淡入效果 | opacityInit, opacityEnd |\n| slideIn | 滑入效果 | direction, distance |\n| slideOut | 滑出效果 | direction, distance |\n| pulse | 脉冲效果 | scaleInit, scaleEnd |\n| blurIn | 模糊淡入 | blurInit, opacityInit |\n\n### 动画配置示例\n\n```typescript\n// 淡入动画\ncase \"fadeIn\":\n  return {\n    \"0%\": { opacity: opacityInit ?? 0, mirror: defaultMirror },\n    \"100%\": { opacity: opacityEnd ?? 1, mirror: defaultMirror },\n  };\n\n// 滑入动画\ncase \"slideIn\": {\n  const direction = normalized?.direction || \"left\";\n  const distance = normalized?.distance || 300;\n  return {\n    \"0%\": {\n      x: direction === \"left\" ? -distance : direction === \"right\" ? distance : 0,\n      opacity: opacityInit ?? 0,\n      mirror: defaultMirror,\n    },\n    \"100%\": {\n      x: 0,\n      opacity: opacityEnd ?? 1,\n      mirror: defaultMirror,\n    },\n  };\n}\n```\n\n资料来源：[packages/openvideo/src/animation/presets.ts:50-120]()\n\n## JSON 序列化\n\n### 序列化格式\n\nTextClip 和 CaptionClip 都支持完整的 JSON 序列化，便于项目保存和加载：\n\n```typescript\ninterface CaptionDataJSON {\n  words?: string[];              // 单词数组\n  colors?: CaptionColorsJSON;    // 颜色配置\n  appearedColor?: number;        // 已显示颜色（向后兼容）\n  activeColor?: number;          // 激活颜色（向后兼容）\n  activeFillColor?: number;      // 激活填充色（向后兼容）\n  backgroundColor?: number;      // 背景色（向后兼容）\n  isKeyWordColor?: number;       // 关键词色（向后兼容）\n  bottomOffset?: number;         // 底部偏移\n  videoWidth?: number;           // 视频宽度\n  videoHeight?: number;          // 视频高度\n  wordsPerLine?: number;         // 每行词数\n  fontUrl?: string;              // 字体 URL\n  preserveKeywordColor?: boolean; // 保留关键词颜色\n  style?: TextStyleJSON;         // 文字样式\n}\n```\n\n### 向后兼容性\n\nCaptionClip 的序列化模块实现了向后兼容处理，支持旧版本的扁平化数据结构：\n\n```typescript\n// 旧扁平结构（向后兼容）\nif (json.appearedColor !== undefined) {\n  captionOpts.colors = captionOpts.colors || {};\n  captionOpts.colors.appeared = json.appearedColor;\n}\n\n// 新嵌套结构\nif (this.originalOpts?.caption?.colors?.appeared !== undefined) {\n  this.opts.appeared = this.originalOpts.caption.colors.appeared;\n}\n```\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:300-400]()\n\n## 使用示例\n\n### 创建文字剪辑\n\n```typescript\nimport { Studio, Text } from 'openvideo';\n\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas'),\n  width: 1280,\n  height: 720,\n});\n\nconst title = new Text('Hello World');\ntitle.duration = 5e6;  // 5秒\ntitle.fontSize = 48;\ntitle.fontFamily = 'Arial';\ntitle.fontWeight = 'bold';\ntitle.fill = '#FFFFFF';\ntitle.stroke = { color: '#000000', width: 2 };\ntitle.dropShadow = {\n  color: '#000000',\n  alpha: 0.5,\n  blur: 4,\n  distance: 2,\n  angle: Math.PI / 4\n};\n\nawait studio.addClip(title);\n```\n\n### 创建字幕剪辑\n\n```typescript\nimport { CaptionClip } from 'openvideo';\n\nconst caption = new CaptionClip({\n  text: 'This is a subtitle example',\n  fontSize: 32,\n  fontFamily: 'Microsoft YaHei',\n  colors: {\n    appeared: 0x888888,\n    active: 0xFFFFFF,\n    activeFill: 0xFFFF00,\n    background: 0x333333\n  },\n  wordAnimation: 'fadeIn',\n  verticalAlign: 'bottom',\n  bottomOffset: 50\n});\n\nawait studio.addClip(caption);\n```\n\n### 从 SRT 文件加载\n\n```typescript\nimport { SRTParser } from 'openvideo';\n\nconst srtContent = await fetch('/path/to/subtitle.srt').then(r => r.text());\nconst parsed = SRTParser.parse(srtContent);\n\nfor (const segment of parsed) {\n  const caption = new CaptionClip({\n    startTime: segment.startTime,\n    endTime: segment.endTime,\n    text: segment.text,\n    fontSize: 28,\n    colors: {\n      appeared: 0xAAAAAA,\n      active: 0xFFFFFF,\n      activeFill: 0x00FF00\n    }\n  });\n  await studio.addClip(caption);\n}\n```\n\n## 最佳实践\n\n### 性能优化\n\n1. **避免频繁创建文字对象**：TextClip 会为每个单词创建独立的 SplitBitmapText，过多的单词会影响性能\n2. **合理设置 wordWrapWidth**：过小的换行宽度会导致行数增加，增加渲染负担\n3. **使用缓存的字体**：确保字体只加载一次，避免重复加载\n\n### 兼容性注意\n\n1. **使用标准字体**：跨平台渲染时，优先使用系统自带字体\n2. **提供回退字体**：在 fontFamily 中指定多个字体作为回退\n3. **SRT 时间码格式**：确保 SRT 文件使用标准格式 `HH:MM:SS,mmm`\n\n## 相关模块\n\n| 模块 | 文件路径 | 用途 |\n|------|----------|------|\n| 核心剪辑 | `src/clips/clip.ts` | 剪辑基类 |\n| 文字剪辑 | `src/clips/text-clip.ts` | 文字渲染实现 |\n| 字幕剪辑 | `src/clips/caption-clip.ts` | 字幕渲染实现 |\n| 字体管理 | `src/utils/fonts.ts` | 字体加载管理 |\n| SRT 解析 | `src/utils/srt-parser.ts` | SRT 格式解析 |\n| 动画预设 | `src/animation/presets.ts` | 内置动画效果 |\n| 时间轴模型 | `src/studio/timeline-model.ts` | 时间轴数据管理 |\n\n---\n\n<a id='page-resources'></a>\n\n## 资源管理\n\n### 相关页面\n\n相关主题：[Studio - 项目状态管理](#page-studio), [视频与音频剪辑](#page-video-clip)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio/resource-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/resource-manager.ts)\n- [packages/openvideo/src/utils/asset-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/asset-manager.ts)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/utils/chromakey.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/chromakey.ts)\n- [packages/openvideo/render.html](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/render.html)\n</details>\n\n# 资源管理\n\n## 概述\n\nOpenVideo 的资源管理模块是整个视频处理工作流的基础组件，负责媒体资源的加载、存储、流式传输和生命周期管理。该模块由 `ResourceManager` 和 `AssetManager` 两个核心类构成，支持从远程 URL 获取资源并将数据持久化到本地 OPFS（Origin Private File System）文件系统。\n\n资源管理的核心设计目标包括：\n\n- **统一资源获取**：提供一致的接口获取各类媒体资源（视频、音频、图片等）\n- **本地缓存**：通过 OPFS 实现资源的本地持久化存储，减少重复网络请求\n- **流式处理**：支持 ReadableStream 流式读取，适配大文件处理场景\n- **异步操作**：所有资源操作均为异步执行，确保主线程不被阻塞\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts:1-50]()\n\n## 核心架构\n\n### 类结构\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                    ResourceManager                          │\n│  - getReadableStream(url): Promise<ReadableStream>          │\n│  - 静态方法，提供统一的资源获取入口                           │\n└─────────────────────────────────────────────────────────────┘\n                              │\n                              ▼\n┌─────────────────────────────────────────────────────────────┐\n│                    AssetManager                             │\n│  - 管理资源缓存和生命周期                                    │\n│  - 提供资源加载、释放、状态追踪                              │\n└─────────────────────────────────────────────────────────────┘\n                              │\n                              ▼\n┌─────────────────────────────────────────────────────────────┐\n│                    OPFS (Origin Private File System)         │\n│  - 本地文件系统存储                                          │\n│  - 支持大文件持久化                                          │\n└─────────────────────────────────────────────────────────────┘\n```\n\n资料来源：[packages/openvideo/src/utils/asset-manager.ts:1-30]()\n\n### 资源加载流程\n\n```mermaid\ngraph TD\n    A[请求资源 URL] --> B{检查缓存}\n    B -->|命中缓存| C[从 OPFS 读取本地文件]\n    B -->|未命中| D[发起网络请求]\n    D --> E[获取 ReadableStream]\n    E --> F[写入 OPFS 本地文件]\n    F --> G[返回本地文件引用]\n    C --> G\n    G --> H[创建 Video/Audio/Image Clip]\n```\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts:20-40]()\n\n## ResourceManager\n\n### 核心方法\n\n`ResourceManager` 是静态工具类，提供资源获取的核心接口。\n\n#### getReadableStream(url: string): Promise<ReadableStream<Uint8Array>>\n\n从指定 URL 获取资源的可读流。\n\n| 参数 | 类型 | 说明 |\n|------|------|------|\n| url | string | 资源 URL，支持 HTTP/HTTPS 协议 |\n\n| 返回值 | 说明 |\n|--------|------|\n| Promise<ReadableStream<Uint8Array>> | 资源的可读字节流 |\n\n```typescript\n// 获取视频资源的流\nconst stream = await ResourceManager.getReadableStream('https://example.com/video.mp4');\n```\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts:30-45]()\n\n## AssetManager\n\n### 资源缓存机制\n\n`AssetManager` 负责管理资源缓存状态和生命周期，确保内存资源得到正确释放。\n\n### 资源类型支持\n\n| 类型 | 说明 | 适用场景 |\n|------|------|----------|\n| 视频资源 | 通过 Video Clip 加载的 MP4/WebM 等格式 | 视频轨道编辑 |\n| 音频资源 | 独立的音频流 | 音频混合处理 |\n| 图片资源 | PNG/JPG/WebP 等静态图像 | 封面、字幕背景 |\n\n资料来源：[packages/openvideo/src/utils/asset-manager.ts:25-40]()\n\n## Video Clip 中的资源集成\n\n### fromUrl 静态工厂方法\n\n`Video.fromUrl()` 是创建视频剪辑的便捷入口，内部自动调用 `ResourceManager` 获取资源。\n\n```typescript\nstatic async fromUrl(\n  url: string,\n  opts: {\n    x?: number;\n    y?: number;\n    width?: number;\n    height?: number;\n  } = {}\n): Promise<Video>\n```\n\n| 参数 | 类型 | 必填 | 说明 |\n|------|------|------|------|\n| url | string | 是 | 视频资源 URL |\n| opts.x | number | 否 | 剪辑在画布中的 X 坐标 |\n| opts.y | number | 否 | 剪辑在画布中的 Y 坐标 |\n| opts.width | number | 否 | 剪辑显示宽度 |\n| opts.height | number | 否 | 剪辑显示高度 |\n\n```typescript\n// 加载远程视频并设置位置\nconst video = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 100,\n  y: 50,\n  width: 1280,\n  height: 720\n});\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:50-80]()\n\n### localFile 本地文件管理\n\n视频资源下载后会存储在 OPFS 中，`localFile` 属性保存本地文件引用。\n\n```typescript\n// Video Clip 构造函数中的本地文件初始化\nconst initByStream = async (s: ReadableStream) => {\n  await write(this.localFile, s);\n  return this.localFile;\n};\n\nthis.localFile = isOTFile(source)\n  ? source\n  : \"localFileFinder\"; // 使用 OPFS 存储\n```\n\n| 属性 | 类型 | 说明 |\n|------|------|------|\n| localFile | OPFSToolFile | OPFS 中的本地文件句柄 |\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:75-85]()\n\n## 图像处理中的资源管理\n\n### 图像源接口\n\n`ImgSource` 类型用于统一不同来源的图像数据：\n\n```typescript\ntype ImgSource = ImageBitmap | HTMLImageElement | \n                  HTMLCanvasElement | OffscreenCanvas | \n                  VideoFrame;\n```\n\n### Chromakey（色键抠像）资源处理\n\n`createChromakey` 函数展示了图像资源的流式处理模式：\n\n```typescript\nexport const createChromakey = (\n  opts: Omit<IChromakeyOpts, 'keyColor'> & {\n    keyColor?: [number, number, number];\n  }\n) => {\n  let canvas: HTMLCanvasElement | OffscreenCanvas | null = null;\n  let gl: WebGLRenderingContext | null = null;\n  let keyColor = opts.keyColor;\n  let texture: WebGLTexture | null = null;\n\n  return async (imgSource: ImgSource) => {\n    if (canvas == null || gl == null || texture == null) {\n      if (keyColor == null) keyColor = getKeyColor(imgSource);\n      // 初始化 canvas 和 WebGL 上下文\n    }\n    // 更新纹理并返回处理后的 VideoFrame\n  };\n};\n```\n\n| 组件 | 类型 | 生命周期 |\n|------|------|----------|\n| canvas | HTMLCanvasElement \\| OffscreenCanvas | 首次调用时创建 |\n| gl | WebGLRenderingContext | 首次调用时初始化 |\n| texture | WebGLTexture | 按需创建和更新 |\n\n资料来源：[packages/openvideo/src/utils/chromakey.ts:20-60]()\n\n## 渲染模板中的资源注入\n\nOpenVideo 在服务端渲染场景中使用 Playwright 注入配置，HTML 模板通过 `window.RENDER_CONFIG` 获取渲染参数。\n\n```javascript\n// 获取 JSON 配置\nconst jsonConfig = window.RENDER_CONFIG;\n\nif (!jsonConfig) {\n  throw new Error('No render configuration provided');\n}\n\n// 从配置中提取设置\nconst settings = jsonConfig.settings || {};\nconst compositorOpts = {\n  width: settings.width || 1280,\n  height: settings.height || 720,\n  fps: settings.fps || 30,\n  bgColor: settings.bgColor || '#000000',\n};\n```\n\n| 配置项 | 默认值 | 说明 |\n|--------|--------|------|\n| width | 1280 | 输出视频宽度 |\n| height | 720 | 输出视频高度 |\n| fps | 30 | 帧率 |\n| bgColor | #000000 | 背景颜色 |\n| videoCodec | - | 视频编码器 |\n| bitrate | - | 比特率 |\n| audio | true | 是否包含音频 |\n\n资料来源：[packages/openvideo/render.html:25-50]()\n\n## 最佳实践\n\n### 资源加载建议\n\n1. **使用 fromUrl 工厂方法**：优先使用 `Video.fromUrl()` 而非直接操作流，确保资源正确缓存\n2. **指定尺寸参数**：在 `fromUrl` 中指定 `width`/`height` 可避免布局抖动\n3. **检查资源就绪状态**：调用 `await clip.ready` 确保媒体元数据加载完成\n\n### 内存管理\n\n```typescript\n// 正确的异步初始化模式\nconst video = await Video.fromUrl('video.mp4');\nawait video.ready; // 等待元数据加载\nawait video.thumbnails(100); // 生成缩略图\n```\n\n### 异常处理\n\n```typescript\ntry {\n  const stream = await ResourceManager.getReadableStream(url);\n  if (!stream) {\n    throw new Error('Failed to get readable stream');\n  }\n} catch (error) {\n  console.error('Resource loading failed:', error);\n}\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:60-75]()\n\n## 总结\n\nOpenVideo 的资源管理模块通过 `ResourceManager` 和 `AssetManager` 提供了完整的资源获取和生命周期管理能力。结合 OPFS 本地存储和流式处理机制，该系统能够高效处理远程媒体资源，同时保持较低的内存占用。开发者应遵循工厂方法优先、异步操作必检、资源释放及时的原则，以确保应用的稳定性和性能。\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：openvideodev/openvideo\n\n摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1125747446 | https://github.com/openvideodev/openvideo | README/documentation is current enough for a first validation pass.\n\n## 2. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | last_activity_observed missing\n\n## 3. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n\n## 4. 安全/权限坑 · 存在安全注意事项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：No sandbox install has been executed yet; downstream must verify before user use.\n- 对用户的影响：用户安装前需要知道权限边界和敏感操作。\n- 建议检查：转成明确权限清单和安全审查提示。\n- 防护动作：安全注意事项必须面向用户前置展示。\n- 证据：risks.safety_notes | github_repo:1125747446 | https://github.com/openvideodev/openvideo | No sandbox install has been executed yet; downstream must verify before user use.\n\n## 5. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n\n## 6. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | issue_or_pr_quality=unknown\n\n## 7. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | release_recency=unknown\n\n<!-- canonical_name: openvideodev/openvideo; human_manual_source: deepwiki_human_wiki -->\n",
      "markdown_key": "openvideo",
      "pages": "draft",
      "source_refs": [
        {
          "evidence_id": "github_repo:1125747446",
          "kind": "repo",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/openvideodev/openvideo"
        },
        {
          "evidence_id": "art_036db05cb59c422e8be9fa667545a55e",
          "kind": "docs",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/openvideodev/openvideo#readme"
        }
      ],
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "openvideo 说明书",
      "toc": [
        "https://github.com/openvideodev/openvideo 项目说明书",
        "目录",
        "项目介绍",
        "概述",
        "核心功能",
        "技术架构",
        "项目结构",
        "核心组件",
        "Doramagic 踩坑日志"
      ]
    }
  },
  "quality_gate": {
    "blocking_gaps": [],
    "category_confidence": "medium",
    "compile_status": "ready_for_review",
    "five_assets_present": true,
    "install_sandbox_verified": true,
    "missing_evidence": [],
    "next_action": "publish to Doramagic.ai project surfaces",
    "prompt_preview_boundary_ok": true,
    "publish_status": "publishable",
    "quick_start_verified": true,
    "repo_clone_verified": true,
    "repo_commit": "3da37ee6b83a5a25aaa15bbf79f87adc9c8aff07",
    "repo_inspection_error": null,
    "repo_inspection_files": [
      "pnpm-lock.yaml",
      "package.json",
      "README.md",
      "docs/source.config.ts",
      "docs/package.json",
      "docs/README.md",
      "docs/tsconfig.json",
      "docs/src/lib/cn.ts",
      "docs/src/lib/source.ts",
      "docs/src/app/sitemap.ts",
      "docs/src/app/robots.ts",
      "docs/src/app/llms-full.txt/route.ts",
      "docs/src/app/api/search/route.ts",
      "docs/src/app/llms.mdx/docs/[[...slug]]/route.ts",
      "docs/content/docs/meta.json",
      "docs/content/docs/effects.mdx",
      "docs/content/docs/clips.mdx",
      "docs/content/docs/studio.mdx",
      "docs/content/docs/events.mdx",
      "docs/content/docs/index.mdx",
      "docs/content/docs/chroma-key.mdx",
      "docs/content/docs/serialization.mdx",
      "docs/content/docs/api-reference.mdx",
      "docs/content/docs/installation.mdx",
      "docs/content/docs/transitions.mdx",
      "docs/content/docs/rendering.mdx",
      "docs/content/docs/animations.mdx",
      "docs/content/docs/changelog.mdx",
      "docs/content/docs/basic-usage.mdx",
      "docs/content/docs/tracks.mdx",
      "examples/package-lock.json",
      "examples/vite.config.ts",
      "examples/tsconfig.node.json",
      "examples/eslint.config.js",
      "examples/tsconfig.app.json",
      "examples/package.json",
      "examples/README.md",
      "examples/tsconfig.json",
      "examples/components.json",
      "examples/src/lib/utils.ts"
    ],
    "repo_inspection_verified": true,
    "review_reasons": [
      "community_discussion_evidence_below_public_threshold"
    ],
    "tag_count_ok": true,
    "unsupported_claims": []
  },
  "schema_version": "0.1",
  "user_assets": {
    "ai_context_pack": {
      "asset_id": "ai_context_pack",
      "filename": "AI_CONTEXT_PACK.md",
      "markdown": "# combo - Doramagic AI Context Pack\n\n> 定位：安装前体验与判断资产。它帮助宿主 AI 有一个好的开始，但不代表已经安装、执行或验证目标项目。\n\n## 充分原则\n\n- **充分原则，不是压缩原则**：AI Context Pack 应该充分到让宿主 AI 在开工前理解项目价值、能力边界、使用入口、风险和证据来源；它可以分层组织，但不以最短摘要为目标。\n- **压缩策略**：只压缩噪声和重复内容，不压缩会影响判断和开工质量的上下文。\n\n## 给宿主 AI 的使用方式\n\n你正在读取 Doramagic 为 combo 编译的 AI Context Pack。请把它当作开工前上下文：帮助用户理解适合谁、能做什么、如何开始、哪些必须安装后验证、风险在哪里。不要声称你已经安装、运行或执行了目标项目。\n\n## Claim 消费规则\n\n- **事实来源**：Repo Evidence + Claim/Evidence Graph；Human Wiki 只提供显著性、术语和叙事结构。\n- **事实最低状态**：`supported`\n- `supported`：可以作为项目事实使用，但回答中必须引用 claim_id 和证据路径。\n- `weak`：只能作为低置信度线索，必须要求用户继续核实。\n- `inferred`：只能用于风险提示或待确认问题，不能包装成项目事实。\n- `unverified`：不得作为事实使用，应明确说证据不足。\n- `contradicted`：必须展示冲突来源，不得替用户强行选择一个版本。\n\n## 它最适合谁\n\n- **想在安装前理解开源项目价值和边界的用户**：当前证据主要来自项目文档。 证据：`README.md` Claim：`clm_0002` supported 0.86\n\n## 它能做什么\n\n- **命令行启动或安装流程**（需要安装后验证）：项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 证据：`README.md`, `packages/node/README.md` Claim：`clm_0001` supported 0.86\n\n## 怎么开始\n\n- `npm install openvideo` 证据：`README.md` Claim：`clm_0003` supported 0.86\n- `pnpm add @openvideo/node openvideo` 证据：`packages/node/README.md` Claim：`clm_0004` supported 0.86\n- `git clone <repository-url>` 证据：`packages/node/README.md` Claim：`clm_0005` supported 0.86\n- `npx playwright install chromium` 证据：`packages/node/README.md` Claim：`clm_0006` supported 0.86\n\n## 继续前判断卡\n\n- **当前建议**：仅建议沙盒试装\n- **为什么**：项目存在安装命令、宿主配置或本地写入线索，不建议直接进入主力环境，应先在隔离环境试装。\n\n### 30 秒判断\n\n- **现在怎么做**：仅建议沙盒试装\n- **最小安全下一步**：先跑 Prompt Preview；若仍要安装，只在隔离环境试装\n- **先别相信**：真实输出质量不能在安装前相信。\n- **继续会触碰**：命令执行、本地环境或项目文件、宿主 AI 上下文\n\n### 现在可以相信\n\n- **适合人群线索：想在安装前理解开源项目价值和边界的用户**（supported）：有 supported claim 或项目证据支撑，但仍不等于真实安装效果。 证据：`README.md` Claim：`clm_0002` supported 0.86\n- **能力存在：命令行启动或安装流程**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`README.md`, `packages/node/README.md` Claim：`clm_0001` supported 0.86\n- **存在 Quick Start / 安装命令线索**（supported）：可以相信项目文档出现过启动或安装入口；不要因此直接在主力环境运行。 证据：`README.md` Claim：`clm_0003` supported 0.86\n\n### 现在还不能相信\n\n- **真实输出质量不能在安装前相信。**（unverified）：Prompt Preview 只能展示引导方式，不能证明真实项目中的结果质量。\n- **宿主 AI 版本兼容性不能在安装前相信。**（unverified）：Claude、Cursor、Codex、Gemini 等宿主加载规则和版本差异必须在真实环境验证。\n- **不会污染现有宿主 AI 行为，不能直接相信。**（inferred）：Skill、plugin、AGENTS/CLAUDE/GEMINI 指令可能改变宿主 AI 的默认行为。\n- **可安全回滚不能默认相信。**（unverified）：除非项目明确提供卸载和恢复说明，否则必须先在隔离环境验证。\n- **真实安装后是否与用户当前宿主 AI 版本兼容？**（unverified）：兼容性只能通过实际宿主环境验证。\n- **项目输出质量是否满足用户具体任务？**（unverified）：安装前预览只能展示流程和边界，不能替代真实评测。\n- **安装命令是否需要网络、权限或全局写入？**（unverified）：这影响企业环境和个人环境的安装风险。 证据：`README.md`\n\n### 继续会触碰什么\n\n- **命令执行**：包管理器、网络下载、本地插件目录、项目配置或用户主目录。 原因：运行第一条命令就可能产生环境改动；必须先判断是否值得跑。 证据：`README.md`, `packages/node/README.md`\n- **本地环境或项目文件**：安装结果、插件缓存、项目配置或本地依赖目录。 原因：安装前无法证明写入范围和回滚方式，需要隔离验证。 证据：`README.md`, `packages/node/README.md`\n- **宿主 AI 上下文**：AI Context Pack、Prompt Preview、Skill 路由、风险规则和项目事实。 原因：导入上下文会影响宿主 AI 后续判断，必须避免把未验证项包装成事实。\n\n### 最小安全下一步\n\n- **先跑 Prompt Preview**：用安装前交互式试用判断工作方式是否匹配，不需要授权或改环境。（适用：任何项目都适用，尤其是输出质量未知时。）\n- **只在隔离目录或测试账号试装**：避免安装命令污染主力宿主 AI、真实项目或用户主目录。（适用：存在命令执行、插件配置或本地写入线索时。）\n- **安装后只验证一个最小任务**：先验证加载、兼容、输出质量和回滚，再决定是否深用。（适用：准备从试用进入真实工作流时。）\n\n### 退出方式\n\n- **保留安装前状态**：记录原始宿主配置和项目状态，后续才能判断是否可恢复。\n- **记录安装命令和写入路径**：没有明确卸载说明时，至少要知道哪些目录或配置需要手动清理。\n- **如果没有回滚路径，不进入主力环境**：不可回滚是继续前阻断项，不应靠信任或运气继续。\n\n## 哪些只能预览\n\n- 解释项目适合谁和能做什么\n- 基于项目文档演示典型对话流程\n- 帮助用户判断是否值得安装或继续研究\n\n## 哪些必须安装后验证\n\n- 真实安装 Skill、插件或 CLI\n- 执行脚本、修改本地文件或访问外部服务\n- 验证真实输出质量、性能和兼容性\n\n## 边界与风险判断卡\n\n- **把安装前预览误认为真实运行**：用户可能高估项目已经完成的配置、权限和兼容性验证。 处理方式：明确区分 prompt_preview_can_do 与 runtime_required。 Claim：`clm_0007` inferred 0.45\n- **命令执行会修改本地环境**：安装命令可能写入用户主目录、宿主插件目录或项目配置。 处理方式：先在隔离环境或测试账号中运行。 证据：`README.md`, `packages/node/README.md` Claim：`clm_0008` supported 0.86\n- **待确认**：真实安装后是否与用户当前宿主 AI 版本兼容？。原因：兼容性只能通过实际宿主环境验证。\n- **待确认**：项目输出质量是否满足用户具体任务？。原因：安装前预览只能展示流程和边界，不能替代真实评测。\n- **待确认**：安装命令是否需要网络、权限或全局写入？。原因：这影响企业环境和个人环境的安装风险。\n\n## 开工前工作上下文\n\n### 加载顺序\n\n- 先读取 how_to_use.host_ai_instruction，建立安装前判断资产的边界。\n- 读取 claim_graph_summary，确认事实来自 Claim/Evidence Graph，而不是 Human Wiki 叙事。\n- 再读取 intended_users、capabilities 和 quick_start_candidates，判断用户是否匹配。\n- 需要执行具体任务时，优先查 role_skill_index，再查 evidence_index。\n- 遇到真实安装、文件修改、网络访问、性能或兼容性问题时，转入 risk_card 和 boundaries.runtime_required。\n\n### 任务路由\n\n- **命令行启动或安装流程**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`README.md`, `packages/node/README.md` Claim：`clm_0001` supported 0.86\n\n### 上下文规模\n\n- 文件总数：170\n- 重要文件覆盖：40/170\n- 证据索引条目：40\n- 角色 / Skill 条目：5\n\n### 证据不足时的处理\n\n- **missing_evidence**：说明证据不足，要求用户提供目标文件、README 段落或安装后验证记录；不要补全事实。\n- **out_of_scope_request**：说明该任务超出当前 AI Context Pack 证据范围，并建议用户先查看 Human Manual 或真实安装后验证。\n- **runtime_request**：给出安装前检查清单和命令来源，但不要替用户执行命令或声称已执行。\n- **source_conflict**：同时展示冲突来源，标记为待核实，不要强行选择一个版本。\n\n## Prompt Recipes\n\n### 适配判断\n\n- 目标：判断这个项目是否适合用户当前任务。\n- 预期输出：适配结论、关键理由、证据引用、安装前可预览内容、必须安装后验证内容、下一步建议。\n\n```text\n请基于 combo 的 AI Context Pack，先问我 3 个必要问题，然后判断它是否适合我的任务。回答必须包含：适合谁、能做什么、不能做什么、是否值得安装、证据来自哪里。所有项目事实必须引用 evidence_refs、source_paths 或 claim_id。\n```\n\n### 安装前体验\n\n- 目标：让用户在安装前感受核心工作流，同时避免把预览包装成真实能力或营销承诺。\n- 预期输出：一段带边界标签的体验剧本、安装后验证清单和谨慎建议；不含真实运行承诺或强营销表述。\n\n```text\n请把 combo 当作安装前体验资产，而不是已安装工具或真实运行环境。\n\n请严格输出四段：\n1. 先问我 3 个必要问题。\n2. 给出一段“体验剧本”：用 [安装前可预览]、[必须安装后验证]、[证据不足] 三种标签展示它可能如何引导工作流。\n3. 给出安装后验证清单：列出哪些能力只有真实安装、真实宿主加载、真实项目运行后才能确认。\n4. 给出谨慎建议：只能说“值得继续研究/试装”“先补充信息后再判断”或“不建议继续”，不得替项目背书。\n\n硬性边界：\n- 不要声称已经安装、运行、执行测试、修改文件或产生真实结果。\n- 不要写“自动适配”“确保通过”“完美适配”“强烈建议安装”等承诺性表达。\n- 如果描述安装后的工作方式，必须使用“如果安装成功且宿主正确加载 Skill，它可能会……”这种条件句。\n- 体验剧本只能写成“示例台词/假设流程”：使用“可能会询问/可能会建议/可能会展示”，不要写“已写入、已生成、已通过、正在运行、正在生成”。\n- Prompt Preview 不负责给安装命令；如用户准备试装，只能提示先阅读 Quick Start 和 Risk Card，并在隔离环境验证。\n- 所有项目事实必须来自 supported claim、evidence_refs 或 source_paths；inferred/unverified 只能作风险或待确认项。\n\n```\n\n### 角色 / Skill 选择\n\n- 目标：从项目里的角色或 Skill 中挑选最匹配的资产。\n- 预期输出：候选角色或 Skill 列表，每项包含适用场景、证据路径、风险边界和是否需要安装后验证。\n\n```text\n请读取 role_skill_index，根据我的目标任务推荐 3-5 个最相关的角色或 Skill。每个推荐都要说明适用场景、可能输出、风险边界和 evidence_refs。\n```\n\n### 风险预检\n\n- 目标：安装或引入前识别环境、权限、规则冲突和质量风险。\n- 预期输出：环境、权限、依赖、许可、宿主冲突、质量风险和未知项的检查清单。\n\n```text\n请基于 risk_card、boundaries 和 quick_start_candidates，给我一份安装前风险预检清单。不要替我执行命令，只说明我应该检查什么、为什么检查、失败会有什么影响。\n```\n\n### 宿主 AI 开工指令\n\n- 目标：把项目上下文转成一次对话开始前的宿主 AI 指令。\n- 预期输出：一段边界明确、证据引用明确、适合复制给宿主 AI 的开工前指令。\n\n```text\n请基于 combo 的 AI Context Pack，生成一段我可以粘贴给宿主 AI 的开工前指令。这段指令必须遵守 not_runtime=true，不能声称项目已经安装、运行或产生真实结果。\n```\n\n\n## 角色 / Skill 索引\n\n- 共索引 5 个角色 / Skill / 项目文档条目。\n\n- **docs**（project_doc）：This is a Next.js application generated with Create Fumadocs https://github.com/fuma-nama/fumadocs . 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/README.md`\n- **Official Editors**（project_doc）：A high-performance video rendering and processing library for the web, built with WebCodecs and PixiJS. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`README.md`\n- **React + TypeScript + Vite**（project_doc）：This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`examples/README.md`\n- **@designcombo/node**（project_doc）：Node.js video renderer for Combo using Playwright and WebCodecs. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`packages/node/README.md`\n- **Preamble**（project_doc）：GNU Affero General Public License ================================= 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`LICENSE-AGPL3.md`\n\n## 证据索引\n\n- 共索引 40 条证据。\n\n- **docs**（documentation）：This is a Next.js application generated with Create Fumadocs https://github.com/fuma-nama/fumadocs . 证据：`docs/README.md`\n- **Official Editors**（documentation）：A high-performance video rendering and processing library for the web, built with WebCodecs and PixiJS. 证据：`README.md`\n- **React + TypeScript + Vite**（documentation）：This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 证据：`examples/README.md`\n- **@designcombo/node**（documentation）：Node.js video renderer for Combo using Playwright and WebCodecs. 证据：`packages/node/README.md`\n- **Package**（package_manifest）：{ \"name\": \"docs\", \"version\": \"0.0.0\", \"private\": true, \"scripts\": { \"build\": \"next build\", \"dev\": \"next dev\", \"start\": \"next start\", \"types:check\": \"fumadocs-mdx && next typegen && tsc --noEmit\", \"postinstall\": \"fumadocs-mdx\" }, \"dependencies\": { \"fumadocs-core\": \"16.4.7\", \"fumadocs-mdx\": \"14.2.5\", \"fumadocs-ui\": \"16.4.7\", \"lucide-react\": \"^0.562.0\", \"next\": \"16.1.1\", \"react\": \"^19.2.3\", \"react-dom\": \"^19.2.3\", \"tailwind-merge\": \"^3.4.0\" }, \"devDependencies\": { \"@tailwindcss/postcss\": \"^4.1.18\", \"@types/mdx\": \"^2.0.13\", \"@types/node\": \"^25.0.5\", \"@types/react\": \"^19.2.8\", \"@types/react-dom\": \"^19.2.3\", \"postcss\": \"^8.5.6\", \"tailwindcss\": \"^4.1.18\", \"typescript\": \"^5.9.3\" } } 证据：`docs/package.json`\n- **Package**（package_manifest）：{ \"name\": \"examples\", \"private\": true, \"version\": \"0.0.0\", \"type\": \"module\", \"scripts\": { \"dev\": \"vite\", \"build\": \"tsc -b && vite build\", \"lint\": \"eslint .\", \"preview\": \"vite preview\" }, \"dependencies\": { \"@tailwindcss/vite\": \"^4.2.1\", \"class-variance-authority\": \"^0.7.1\", \"clsx\": \"^2.1.1\", \"lucide-react\": \"^0.575.0\", \"openvideo\": \"workspace: \", \"radix-ui\": \"^1.4.3\", \"react\": \"^19.2.0\", \"react-dom\": \"^19.2.0\", \"react-router-dom\": \"^7.13.1\", \"tailwind-merge\": \"^3.5.0\" }, \"devDependencies\": { \"@eslint/js\": \"^9.39.1\", \"@types/node\": \"^24.10.1\", \"@types/react\": \"^19.2.7\", \"@types/react-dom\": \"^19.2.3\", \"@vitejs/plugin-react\": \"^5.1.1\", \"autoprefixer\": \"^10.4.27\", \"eslint\": \"^9.39.1\", \"eslint-pl… 证据：`examples/package.json`\n- **Package**（package_manifest）：{ \"name\": \"combo\", \"private\": true, \"scripts\": { \"build\": \"turbo run build\", \"dev\": \"turbo run dev\", \"lint\": \"biome lint .\", \"lint:fix\": \"biome lint --apply .\", \"format\": \"biome format --write .\", \"format:check\": \"biome format .\", \"check\": \"biome check .\", \"check:fix\": \"biome check --write .\", \"check-types\": \"turbo run check-types\", \"prepare\": \"husky\" }, \"devDependencies\": { \"@biomejs/biome\": \"^2.2.5\", \"husky\": \"^9.1.7\", \"lint-staged\": \"^16.2.7\", \"turbo\": \"^2.5.8\", \"typescript\": \"5.9.2\" }, \"packageManager\": \"pnpm@9.15.4\", \"engines\": { \"node\": \" =18\" }, \"lint-staged\": { \" \": \"biome check --write --no-errors-on-unmatched --files-ignore-unknown=true\" }, \"pnpm\": { \"overrides\": { \"@types/react\":… 证据：`package.json`\n- **Package**（package_manifest）：{ \"scripts\": { \"example\": \"tsx examples/basic.ts\" }, \"devDependencies\": { \"tsx\": \"^4.19.2\" } } 证据：`packages/node/examples/package.json`\n- **Package**（package_manifest）：{ \"name\": \"@designcombo/node\", \"version\": \"0.0.1\", \"description\": \"Node.js video renderer for Combo using Playwright\", \"type\": \"module\", \"main\": \"./dist/index.js\", \"types\": \"./dist/index.d.ts\", \"exports\": { \".\": { \"import\": \"./dist/index.js\", \"types\": \"./dist/index.d.ts\" } }, \"files\": \"dist\", \"src\" , \"scripts\": { \"build\": \"tsc && npm run copy-template\", \"copy-template\": \"cp src/template.html dist/template.html\", \"render\": \"npm run build && cp src/sample.json dist/sample.json && node dist/sample.js\", \"dev\": \"tsc --watch\", \"check-types\": \"tsc --noEmit\" }, \"dependencies\": { \"openvideo\": \"workspace: \", \"express\": \"^4.18.2\", \"playwright\": \"^1.49.0\" }, \"devDependencies\": { \"@types/express\": \"^4.1… 证据：`packages/node/package.json`\n- **Package**（package_manifest）：{ \"name\": \"openvideo\", \"version\": \"0.2.18\", \"description\": \"Video rendering and processing library\", \"type\": \"module\", \"publishConfig\": { \"access\": \"public\" }, \"repository\": { \"type\": \"git\", \"url\": \"https://github.com/openvideodev/openvideo.git\" }, \"keywords\": \"video\", \"rendering\", \"webcodecs\", \"mp4\" , \"author\": \"OpenVideoDev\", \"license\": \"SEE LICENSE IN LICENSE\", \"files\": \"dist\" , \"main\": \"dist/index.umd.js\", \"module\": \"dist/index.es.js\", \"types\": \"dist/index.d.ts\", \"exports\": { \".\": { \"types\": \"./dist/index.d.ts\", \"import\": \"./dist/index.es.js\", \"require\": \"./dist/index.umd.js\" } }, \"scripts\": { \"test\": \"vitest\", \"test:browser\": \"vitest run --project unit-chromium\", \"build\": \"vite build\"… 证据：`packages/openvideo/package.json`\n- **License**（source_file）：This project is licensed under a dual license : 证据：`LICENSE`\n- **OpenVideo License**（source_file）：OpenVideo is a framework-agnostic video editor SDK built on WebCodecs API, designed to make video editing accessible across different web frameworks and platforms. 证据：`packages/openvideo/LICENSE`\n- **Preamble**（documentation）：GNU Affero General Public License ================================= 证据：`LICENSE-AGPL3.md`\n- **Biome**（structured_config）：{ \"$schema\": \"https://biomejs.dev/schemas/2.3.8/schema.json\", \"vcs\": { \"enabled\": true, \"clientKind\": \"git\", \"useIgnoreFile\": true }, \"files\": { \"ignoreUnknown\": false, \"includes\": \" / .ts\", \" / .tsx\", \" / .js\", \" / .jsx\", \" / .json\" , \"experimentalScannerIgnores\": \" /node modules/ \", \" /dist/ \", \" /build/ \", \" /.next/ \", \" /coverage/ \", \" / .d.ts\", \" /pnpm-lock.yaml\", \" /turbo.json\" }, \"formatter\": { \"enabled\": true, \"indentStyle\": \"space\", \"indentWidth\": 2 }, 证据：`biome.json`\n- **Tsconfig**（structured_config）：{ \"compilerOptions\": { \"baseUrl\": \".\", \"target\": \"ESNext\", \"lib\": \"dom\", \"dom.iterable\", \"esnext\" , \"allowJs\": true, \"skipLibCheck\": true, \"strict\": true, \"forceConsistentCasingInFileNames\": true, \"noEmit\": true, \"esModuleInterop\": true, \"module\": \"esnext\", \"moduleResolution\": \"bundler\", \"resolveJsonModule\": true, \"isolatedModules\": true, \"jsx\": \"react-jsx\", \"incremental\": true, \"paths\": { \"@/ \": \"./src/ \" , \"fumadocs-mdx:collections/ \": \".source/ \" }, \"plugins\": { \"name\": \"next\" } }, \"include\": \"next-env.d.ts\", \" / .ts\", \" / .tsx\", \".next/types/ / .ts\", \".next/dev/types/ / .ts\" , \"exclude\": \"node modules\" } 证据：`docs/tsconfig.json`\n- **Components**（structured_config）：{ \"$schema\": \"https://ui.shadcn.com/schema.json\", \"style\": \"new-york\", \"rsc\": false, \"tsx\": true, \"tailwind\": { \"config\": \"\", \"css\": \"src/index.css\", \"baseColor\": \"neutral\", \"cssVariables\": true, \"prefix\": \"\" }, \"iconLibrary\": \"lucide\", \"rtl\": false, \"aliases\": { \"components\": \"@/components\", \"utils\": \"@/lib/utils\", \"ui\": \"@/components/ui\", \"lib\": \"@/lib\", \"hooks\": \"@/hooks\" }, \"registries\": {} } 证据：`examples/components.json`\n- **Tsconfig.App**（structured_config）：{ \"compilerOptions\": { \"tsBuildInfoFile\": \"./node modules/.tmp/tsconfig.app.tsbuildinfo\", \"target\": \"ES2022\", \"useDefineForClassFields\": true, \"lib\": \"ES2022\", \"DOM\", \"DOM.Iterable\" , \"module\": \"ESNext\", \"types\": \"vite/client\" , \"skipLibCheck\": true, \"baseUrl\": \".\", \"paths\": { \"@/ \": \"./src/ \" }, 证据：`examples/tsconfig.app.json`\n- **Tsconfig**（structured_config）：{ \"files\": , \"references\": { \"path\": \"./tsconfig.app.json\" }, { \"path\": \"./tsconfig.node.json\" } , \"compilerOptions\": { \"baseUrl\": \".\", \"paths\": { \"@/ \": \"./src/ \" , \"openvideo\": \"../packages/openvideo/src/index.ts\" } } } 证据：`examples/tsconfig.json`\n- **Tsconfig.Node**（structured_config）：{ \"compilerOptions\": { \"tsBuildInfoFile\": \"./node modules/.tmp/tsconfig.node.tsbuildinfo\", \"target\": \"ES2023\", \"lib\": \"ES2023\" , \"module\": \"ESNext\", \"types\": \"node\" , \"skipLibCheck\": true, 证据：`examples/tsconfig.node.json`\n- **Turbo**（structured_config）：{ \"$schema\": \"https://turborepo.com/schema.json\", \"ui\": \"tui\", \"tasks\": { \"build\": { \"dependsOn\": \"^build\" , \"inputs\": \"$TURBO DEFAULT$\", \".env \" , \"outputs\": \".next/ \", \"!.next/cache/ \" }, \"lint\": { \"dependsOn\": \"^lint\" }, \"check-types\": { \"dependsOn\": \"^check-types\" }, \"dev\": { \"cache\": false, \"persistent\": true } } } 证据：`turbo.json`\n- **Meta**（structured_config）：{ \"title\": \"Documentation\", \"pages\": \"index\", \"changelog\", \"---Getting Started---\", \"installation\", \"basic-usage\", \"---Core Concepts---\", \"studio\", \"tracks\", \"events\", \"---Media & Effects---\", \"clips\", \"animations\", \"transitions\", \"effects\", \"chroma-key\", \"---Export & Persistence---\", \"serialization\", \"rendering\", \"---Reference---\", \"api-reference\" } 证据：`docs/content/docs/meta.json`\n- **Animations**（structured_config）：{ \"tracks\": { \"id\": \"track 1772252042089 9iw860cfe\", \"name\": \"Track 1\", \"type\": \"Image\", \"clipIds\": \"clip 1772252042088 1eu5k9pvm\" } , \"clips\": { \"type\": \"Image\", \"id\": \"clip 1772252042088 1eu5k9pvm\", \"name\": \"Photo by Zak Mogel\", \"src\": \"https://images.pexels.com/photos/35762815/pexels-photo-35762815.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940\", \"display\": { \"from\": 0, \"to\": 3040000 }, \"playbackRate\": 1, \"duration\": 3040000, \"left\": -153.77027027027646, \"top\": -48.216216216219664, \"width\": 1387.5405405405495, \"height\": 2016.4324324324389, \"angle\": 0, \"zIndex\": 10, \"opacity\": 1, \"flip\": null, \"style\": {}, \"trim\": { \"from\": 0, \"to\": 0 }, \"animations\": { \"type\": \"pulse\", \"opts\": { \"durat… 证据：`examples/src/constants/json/animations.json`\n- **Chromakey**（structured_config）：{ \"tracks\": { \"id\": \"track 1772241122294 5m91ibtz9\", \"name\": \"Track 2\", \"type\": \"Video\", \"clipIds\": \"clip 1772241122183 c5kl1om1l\" }, { \"id\": \"track 1772241099713 wi7994tbs\", \"name\": \"Track 1\", \"type\": \"Video\", \"clipIds\": \"clip 1772241099584 ncqkfzve4\" } , \"clips\": { \"type\": \"Video\", \"id\": \"clip 1772241099584 ncqkfzve4\", \"name\": \"videoVerde.mp4\", \"src\": \"https://cdn.scenify.io/mockuser/1eaf7ec0-9a07-4817-b561-54f4102d1987-videoVerde.mp4\", \"display\": { \"from\": 0, \"to\": 12040000 }, \"playbackRate\": 1, \"duration\": 12040000, \"left\": 242.06332222700536, \"top\": -2.7289127089912313, \"width\": 631.2911064998888, \"height\": 962.7289127089863, \"angle\": 0, \"zIndex\": 10, \"opacity\": 1, \"flip\": null, \"style… 证据：`examples/src/constants/json/chromaKey.json`\n- **Effects**（structured_config）：{ \"tracks\": { \"id\": \"track 1772251820638 wduvy3trx\", \"name\": \"Track 2\", \"type\": \"Effect\", \"clipIds\": \"clip 1772251820638 cg52nmek9\" }, { \"id\": \"track 1772251728903 uj9k84vmo\", \"name\": \"Track 2\", \"type\": \"Image\", \"clipIds\": \"clip 1772251728903 sjn1utsaa\" } , \"clips\": { \"type\": \"Image\", \"id\": \"clip 1772251728903 sjn1utsaa\", \"name\": \"Photo by Osman Arabacı\", \"src\": \"https://images.pexels.com/photos/35828557/pexels-photo-35828557.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940\", \"display\": { \"from\": 0, \"to\": 5300000 }, \"playbackRate\": 1, \"duration\": 5300000, \"left\": -203.93243243243933, \"top\": -29.837837837843722, \"width\": 1428.8783783783822, \"height\": 1979.6756756756802, \"angle\": 0, \"zIndex\":… 证据：`examples/src/constants/json/effects.json`\n- **Transitions**（structured_config）：{ \"tracks\": { \"id\": \"track 1772252592307 7jtc8geh2\", \"name\": \"Track 1\", \"type\": \"Image\", \"clipIds\": \"clip 1772252592307 o0gpzccct\", \"clip 1772252601445 pqnurox3c\", \"clip 1772252617678 l0h3i67zl\" } , \"clips\": { \"type\": \"Image\", \"id\": \"clip 1772252592307 o0gpzccct\", \"name\": \"Photo by Stephen Leonardi\", \"src\": \"https://images.pexels.com/photos/35554037/pexels-photo-35554037.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940\", \"display\": { \"from\": 0, \"to\": 5000000 }, \"playbackRate\": 1, \"duration\": 5000000, \"left\": -147.79594723201978, \"top\": -33.520454828209495, \"width\": 1375.5918944640378, \"height\": 1987.0409096564154, \"angle\": 0, \"zIndex\": 10, \"opacity\": 1, \"flip\": null, \"style\": {}, \"trim\": {… 证据：`examples/src/constants/json/transitions.json`\n- **Tsconfig**（structured_config）：{ \"compilerOptions\": { \"target\": \"ES2022\", \"module\": \"ES2022\", \"lib\": \"ES2022\" , \"moduleResolution\": \"bundler\", \"esModuleInterop\": true, \"skipLibCheck\": true, \"forceConsistentCasingInFileNames\": true, \"resolveJsonModule\": true, \"allowSyntheticDefaultImports\": true }, \"include\": \"examples/ / \" } 证据：`packages/node/examples/tsconfig.json`\n- **Sample**（structured_config）：{ \"clips\": { \"type\": \"Text\", \"src\": \"\", \"display\": { \"from\": 0, \"to\": 5000000 }, \"playbackRate\": 1, \"duration\": 5000000, \"left\": 535.9696350097656, \"top\": 293.62639547141936, \"width\": 239, \"height\": 83, \"angle\": 0, \"zIndex\": 0, \"opacity\": 1, \"flip\": null, \"text\": \"Scenify\", \"style\": { \"fontSize\": 64, \"fontFamily\": \"Arial\", \"fontWeight\": \"bold\", \"fontStyle\": \"italic\", \"color\": { \"type\": \"gradient\", \"x0\": 0, \"y0\": 0, \"x1\": 0, \"y1\": 10, \"colors\": { \"ratio\": 0, \"color\": 16777215 }, { \"ratio\": 1, \"color\": 65433 } }, \"align\": \"center\", \"stroke\": { \"color\": \" ffffff\", \"width\": 5 }, \"shadow\": { \"color\": \" ffffff\", \"alpha\": 0.5, \"blur\": 4, \"offsetX\": 5.999749463958002, \"offsetY\": 0.05483037238305627… 证据：`packages/node/src/sample.json`\n- **Tsconfig**（structured_config）：{ \"compilerOptions\": { \"target\": \"ES2022\", \"module\": \"ES2022\", \"lib\": \"ES2022\" , \"moduleResolution\": \"bundler\", \"declaration\": true, \"declarationMap\": true, \"outDir\": \"./dist\", \"rootDir\": \"./src\", \"strict\": true, \"esModuleInterop\": true, \"skipLibCheck\": true, \"forceConsistentCasingInFileNames\": true, \"resolveJsonModule\": true, \"allowSyntheticDefaultImports\": true, \"types\": \"node\" }, \"include\": \"src/ / \" , \"exclude\": \"node modules\", \"dist\", \"examples\" } 证据：`packages/node/tsconfig.json`\n- **Tsconfig**（structured_config）：{ \"compilerOptions\": { \"target\": \"es2022\", \"useDefineForClassFields\": true, \"module\": \"esnext\", \"types\": \"@types/dom-webcodecs\" , \"lib\": \"ES2022\", \"DOM\", \"DOM.Iterable\" , \"skipLibCheck\": true, / Bundler mode / \"moduleResolution\": \"bundler\", \"allowImportingTsExtensions\": true, \"isolatedModules\": true, \"moduleDetection\": \"force\", \"noEmit\": true, / Linting / \"strict\": true, \"noUnusedLocals\": true, \"noUnusedParameters\": true, \"noFallthroughCasesInSwitch\": true, \"noUncheckedSideEffectImports\": true }, \"include\": \"src\" } 证据：`packages/openvideo/tsconfig.json`\n- **See https://help.github.com/articles/ignoring-files/ for more about ignoring files.**（source_file）：See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 证据：`.gitignore`\n- **Pre Commit**（source_file）：npx lint-staged 证据：`.husky/pre-commit`\n- **deps**（source_file）：test & build /coverage /.next/ /out/ /build .tsbuildinfo 证据：`docs/.gitignore`\n- **Next.Config**（source_file）：import { createMDX } from 'fumadocs-mdx/next'; 证据：`docs/next.config.mjs`\n- **Postcss.Config**（source_file）：export default { plugins: { '@tailwindcss/postcss': {}, }, }; 证据：`docs/postcss.config.mjs`\n- **Source.Config**（source_file）：import { defineConfig, defineDocs, frontmatterSchema, metaSchema, } from 'fumadocs-mdx/config'; 证据：`docs/source.config.ts`\n- **Logs**（source_file）：Logs logs .log npm-debug.log yarn-debug.log yarn-error.log pnpm-debug.log lerna-debug.log 证据：`examples/.gitignore`\n- **Eslint.Config**（source_file）：import js from '@eslint/js'; import globals from 'globals'; import reactHooks from 'eslint-plugin-react-hooks'; import reactRefresh from 'eslint-plugin-react-refresh'; import tseslint from 'typescript-eslint'; import { defineConfig, globalIgnores } from 'eslint/config'; 证据：`examples/eslint.config.js`\n- **Index**（source_file）：examples 证据：`examples/index.html`\n- **Vite.Config**（source_file）：import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import tailwindcss from '@tailwindcss/vite'; import path from 'path'; 证据：`examples/vite.config.ts`\n- **Pnpm Workspace**（source_file）：packages: - \"editor\" - \"packages/ \" - \"docs\" - \"examples\" 证据：`pnpm-workspace.yaml`\n\n## 宿主 AI 必须遵守的规则\n\n- **把本资产当作开工前上下文，而不是运行环境。**：AI Context Pack 只包含证据化项目理解，不包含目标项目的可执行状态。 证据：`docs/README.md`, `README.md`, `examples/README.md`\n- **回答用户时区分可预览内容与必须安装后才能验证的内容。**：安装前体验的消费者价值来自降低误装和误判，而不是伪装成真实运行。 证据：`docs/README.md`, `README.md`, `examples/README.md`\n\n## 用户开工前应该回答的问题\n\n- 你准备在哪个宿主 AI 或本地环境中使用它？\n- 你只是想先体验工作流，还是准备真实安装？\n- 你最在意的是安装成本、输出质量、还是和现有规则的冲突？\n\n## 验收标准\n\n- 所有能力声明都能回指到 evidence_refs 中的文件路径。\n- AI_CONTEXT_PACK.md 没有把预览包装成真实运行。\n- 用户能在 3 分钟内看懂适合谁、能做什么、如何开始和风险边界。\n\n---\n\n## Doramagic Context Augmentation\n\n下面内容用于强化 Repomix/AI Context Pack 主体。Human Manual 只提供阅读骨架；踩坑日志会被转成宿主 AI 必须遵守的工作约束。\n\n## Human Manual 骨架\n\n使用规则：这里只是项目阅读路线和显著性信号，不是事实权威。具体事实仍必须回到 repo evidence / Claim Graph。\n\n宿主 AI 硬性规则：\n- 不得把页标题、章节顺序、摘要或 importance 当作项目事实证据。\n- 解释 Human Manual 骨架时，必须明确说它只是阅读路线/显著性信号。\n- 能力、安装、兼容性、运行状态和风险判断必须引用 repo evidence、source path 或 Claim Graph。\n\n- **项目介绍**：importance `high`\n  - source_paths: README.md, packages/openvideo/src/index.ts\n- **安装与配置**：importance `high`\n  - source_paths: docs/content/docs/installation.mdx, packages/openvideo/package.json, package.json\n- **快速开始**：importance `high`\n  - source_paths: docs/content/docs/basic-usage.mdx, packages/openvideo/src/studio.ts, examples/src/App.tsx\n- **系统架构**：importance `high`\n  - source_paths: packages/openvideo/src/studio.ts, packages/openvideo/src/compositor.ts, packages/openvideo/src/index.ts\n- **Studio - 项目状态管理**：importance `high`\n  - source_paths: packages/openvideo/src/studio.ts, packages/openvideo/src/studio/timeline-model.ts, packages/openvideo/src/studio/resource-manager.ts, packages/openvideo/src/studio/history-manager.ts, packages/openvideo/src/studio/selection-manager.ts\n- **Compositor - 渲染引擎**：importance `high`\n  - source_paths: packages/openvideo/src/compositor.ts, packages/openvideo/src/mp4-utils/mp4box-utils.ts, packages/openvideo/src/mp4-utils/sample-transform.ts\n- **剪辑系统**：importance `high`\n  - source_paths: packages/openvideo/src/clips/iclip.ts, packages/openvideo/src/clips/base-clip.ts, packages/openvideo/src/clips/index.ts, packages/openvideo/src/clips/effect-clip.ts, packages/openvideo/src/clips/transition-clip.ts\n- **视频与音频剪辑**：importance `high`\n  - source_paths: packages/openvideo/src/clips/video-clip.ts, packages/openvideo/src/clips/audio-clip.ts, packages/openvideo/src/clips/image-clip.ts, packages/openvideo/src/utils/video.ts, packages/openvideo/src/utils/audio.ts\n\n## Repo Inspection Evidence / 源码检查证据\n\n- repo_clone_verified: true\n- repo_inspection_verified: true\n- repo_commit: `3da37ee6b83a5a25aaa15bbf79f87adc9c8aff07`\n- inspected_files: `pnpm-lock.yaml`, `package.json`, `README.md`, `docs/source.config.ts`, `docs/package.json`, `docs/README.md`, `docs/tsconfig.json`, `docs/src/lib/cn.ts`, `docs/src/lib/source.ts`, `docs/src/app/sitemap.ts`, `docs/src/app/robots.ts`, `docs/src/app/llms-full.txt/route.ts`, `docs/src/app/api/search/route.ts`, `docs/src/app/llms.mdx/docs/[[...slug]]/route.ts`, `docs/content/docs/meta.json`, `docs/content/docs/effects.mdx`, `docs/content/docs/clips.mdx`, `docs/content/docs/studio.mdx`, `docs/content/docs/events.mdx`, `docs/content/docs/index.mdx`\n\n宿主 AI 硬性规则：\n- 没有 repo_clone_verified=true 时，不得声称已经读过源码。\n- 没有 repo_inspection_verified=true 时，不得把 README/docs/package 文件判断写成事实。\n- 没有 quick_start_verified=true 时，不得声称 Quick Start 已跑通。\n\n## Doramagic Pitfall Constraints / 踩坑约束\n\n这些规则来自 Doramagic 发现、验证或编译过程中的项目专属坑点。宿主 AI 必须把它们当作工作约束，而不是普通说明文字。\n\n### Constraint 1: 能力判断依赖假设\n\n- Trigger: README/documentation is current enough for a first validation pass.\n- Host AI rule: 将假设转成下游验证清单。\n- Why it matters: 假设不成立时，用户拿不到承诺的能力。\n- Evidence: capability.assumptions | github_repo:1125747446 | https://github.com/openvideodev/openvideo | README/documentation is current enough for a first validation pass.\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 2: 维护活跃度未知\n\n- Trigger: 未记录 last_activity_observed。\n- Host AI rule: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Why it matters: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Evidence: evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | last_activity_observed missing\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 3: 下游验证发现风险项\n\n- Trigger: no_demo\n- Host AI rule: 进入安全/权限治理复核队列。\n- Why it matters: 下游已经要求复核，不能在页面中弱化。\n- Evidence: downstream_validation.risk_items | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 4: 存在安全注意事项\n\n- Trigger: No sandbox install has been executed yet; downstream must verify before user use.\n- Host AI rule: 转成明确权限清单和安全审查提示。\n- Why it matters: 用户安装前需要知道权限边界和敏感操作。\n- Evidence: risks.safety_notes | github_repo:1125747446 | https://github.com/openvideodev/openvideo | No sandbox install has been executed yet; downstream must verify before user use.\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 5: 存在评分风险\n\n- Trigger: no_demo\n- Host AI rule: 把风险写入边界卡，并确认是否需要人工复核。\n- Why it matters: 风险会影响是否适合普通用户安装。\n- Evidence: risks.scoring_risks | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 6: issue/PR 响应质量未知\n\n- Trigger: issue_or_pr_quality=unknown。\n- Host AI rule: 抽样最近 issue/PR，判断是否长期无人处理。\n- Why it matters: 用户无法判断遇到问题后是否有人维护。\n- Evidence: evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | issue_or_pr_quality=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 7: 发布节奏不明确\n\n- Trigger: release_recency=unknown。\n- Host AI rule: 确认最近 release/tag 和 README 安装命令是否一致。\n- Why it matters: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Evidence: evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | release_recency=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n",
      "summary": "给宿主 AI 的上下文和工作边界。",
      "title": "AI Context Pack / 带给我的 AI"
    },
    "boundary_risk_card": {
      "asset_id": "boundary_risk_card",
      "filename": "BOUNDARY_RISK_CARD.md",
      "markdown": "# Boundary & Risk Card / 安装前决策卡\n\n项目：openvideodev/openvideo\n\n## Doramagic 试用结论\n\n当前结论：可以进入发布前推荐检查；首次使用仍应从最小权限、临时目录和可回滚配置开始。\n\n## 用户现在可以做\n\n- 可以先阅读 Human Manual，理解项目目的和主要工作流。\n- 可以复制 Prompt Preview 做安装前体验；这只验证交互感，不代表真实运行。\n- 可以把官方 Quick Start 命令放到隔离环境中验证，不要直接进主力环境。\n\n## 现在不要做\n\n- 不要把 Prompt Preview 当成项目实际运行结果。\n- 不要把 metadata-only validation 当成沙箱安装验证。\n- 不要把未验证能力写成“已支持、已跑通、可放心安装”。\n- 不要在首次试用时交出生产数据、私人文件、真实密钥或主力配置目录。\n\n## 安装前检查\n\n- 宿主 AI 是否匹配：local_cli\n- 官方安装入口状态：已发现官方入口\n- 是否在临时目录、临时宿主或容器中验证：必须是\n- 是否能回滚配置改动：必须能\n- 是否需要 API Key、网络访问、读写文件或修改宿主配置：未确认前按高风险处理\n- 是否记录了安装命令、实际输出和失败日志：必须记录\n\n## 当前阻塞项\n\n- review_required: community_discussion_evidence_below_public_threshold\n\n## 项目专属踩坑\n\n- 能力判断依赖假设（medium）：假设不成立时，用户拿不到承诺的能力。 建议检查：将假设转成下游验证清单。\n- 维护活跃度未知（medium）：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 下游验证发现风险项（medium）：下游已经要求复核，不能在页面中弱化。 建议检查：进入安全/权限治理复核队列。\n- 存在安全注意事项（medium）：用户安装前需要知道权限边界和敏感操作。 建议检查：转成明确权限清单和安全审查提示。\n- 存在评分风险（medium）：风险会影响是否适合普通用户安装。 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n\n## 风险与权限提示\n\n- no_demo: medium\n\n## 证据缺口\n\n- 暂未发现结构化证据缺口。\n",
      "summary": "安装、权限、验证和推荐前风险。",
      "title": "Boundary & Risk Card / 边界与风险卡"
    },
    "human_manual": {
      "asset_id": "human_manual",
      "filename": "HUMAN_MANUAL.md",
      "markdown": "# https://github.com/openvideodev/openvideo 项目说明书\n\n生成时间：2026-05-14 00:03:22 UTC\n\n## 目录\n\n- [项目介绍](#page-introduction)\n- [安装与配置](#page-installation)\n- [快速开始](#page-quick-start)\n- [系统架构](#page-architecture)\n- [Studio - 项目状态管理](#page-studio)\n- [Compositor - 渲染引擎](#page-compositor)\n- [剪辑系统](#page-clips)\n- [视频与音频剪辑](#page-video-clip)\n- [文字与字幕剪辑](#page-text-caption)\n- [资源管理](#page-resources)\n\n<a id='page-introduction'></a>\n\n## 项目介绍\n\n### 相关页面\n\n相关主题：[安装与配置](#page-installation), [系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n- [packages/node/README.md](https://github.com/openvideodev/openvideo/blob/main/packages/node/README.md)\n- [packages/openvideo/render.html](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/render.html)\n- [packages/node/src/template.html](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/template.html)\n- [packages/openvideo/src/animation/presets.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/animation/presets.ts)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/transition/transition.ts](https://github.com/openvideov/openvideo/blob/main/packages/openvideo/src/transition/transition.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/clips/caption-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/caption-clip.ts)\n- [packages/openvideo/src/sprite/base-sprite.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/sprite/base-sprite.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n- [packages/openvideo/src/utils/chromakey.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/chromakey.ts)\n</details>\n\n# 项目介绍\n\n## 概述\n\nOpenVideo 是一个开源的 Web 端视频编辑与渲染引擎，旨在为开发者提供基于现代 Web 技术的视频处理能力。该项目充分利用 WebCodecs API 实现硬件加速的视频编解码，结合 PixiJS 渲染引擎实现高性能的 2D/3D 图形渲染。OpenVideo 的设计理念是让视频编辑功能能够在浏览器环境中高效运行，同时支持服务端 Node.js 环境下的视频渲染输出。\n\n## 核心功能\n\nOpenVideo 提供了完整的视频编辑工作流支持，包括时间线管理、轨道编辑、剪辑合成、特效转场等功能模块。开发者可以通过声明式的 JSON 配置或程序化的 API 调用来构建复杂的视频编辑场景。\n\n### 主要能力\n\n| 功能类别 | 支持内容 |\n|---------|---------|\n| 媒体剪辑 | 视频、音频、图片、字幕、文字 |\n| 视频特效 | 动画预设、滤镜、透明度、镜像、缩放 |\n| 转场效果 | 超过 30 种转场动画（淡入淡出、滑动、缩放等） |\n| 渲染输出 | WebCodecs 硬件编码、MP4 封装 |\n| 实时预览 | Canvas 2D/WebGL 渲染、帧级同步 |\n\n## 技术架构\n\n### 技术栈\n\nOpenVideo 基于以下核心技术构建：\n\n| 技术 | 用途 |\n|-----|------|\n| **WebCodecs API** | 硬件加速的视频编码/解码处理 |\n| **PixiJS** | 高性能 2D/3D 渲染引擎 |\n| **wrapbox** | MP4 容器操作的底层工具库 |\n| **TypeScript** | 类型安全的开发环境 |\n| **Playwright** | 服务端渲染的浏览器自动化 |\n\n### 架构层次\n\n```\n┌─────────────────────────────────────────────┐\n│              应用层 (Application)            │\n│  Studio │ Compositor │ PreviewCanvas        │\n├─────────────────────────────────────────────┤\n│              剪辑层 (Clips)                   │\n│  VideoClip │ AudioClip │ TextClip │ ImageClip │\n│  CaptionClip │ SubtitleClip                  │\n├─────────────────────────────────────────────┤\n│              精灵层 (Sprites)                 │\n│  BaseSprite │ Transform │ Animations         │\n├─────────────────────────────────────────────┤\n│              渲染层 (Rendering)              │\n│  PixiJS App │ WebGL │ Compositor            │\n├─────────────────────────────────────────────┤\n│              工具层 (Utils)                   │\n│  Chromakey │ MP4 Utils │ Serialization       │\n├─────────────────────────────────────────────┤\n│              编码层 (Codecs)                 │\n│  VideoEncoder │ VideoDecoder │ MP4 Muxer    │\n└─────────────────────────────────────────────┘\n```\n\n## 项目结构\n\nOpenVideo 采用 Monorepo 架构，主要包含以下包：\n\n```\nopenvideo/\n├── packages/\n│   ├── openvideo/           # 核心库\n│   │   └── src/\n│   │       ├── clips/       # 各类剪辑实现\n│   │       │   ├── video-clip.ts\n│   │       │   ├── text-clip.ts\n│   │       │   ├── caption-clip.ts\n│   │       │   └── ...\n│   │       ├── animation/   # 动画预设\n│   │       │   └── presets.ts\n│   │       ├── transition/  # 转场效果\n│   │       │   └── transition.ts\n│   │       ├── sprite/      # 精灵基类\n│   │       │   └── base-sprite.ts\n│   │       ├── mp4-utils/   # MP4 封装工具\n│   │       │   └── index.ts\n│   │       ├── utils/       # 工具函数\n│   │       │   └── chromakey.ts\n│   │       └── render.html  # 渲染模板\n│   │\n│   └── node/                # Node.js 服务端渲染包\n│       └── src/\n│           ├── renderer.ts  # 主渲染器\n│           ├── types.ts     # 类型定义\n│           ├── template.html # HTML 模板\n│           └── sample.ts    # 使用示例\n│\n└── examples/                # 示例项目\n```\n\n## 核心组件\n\n### Studio（工作室）\n\nStudio 是项目的顶层状态管理器，负责协调整个视频编辑项目的运行。它管理时间线配置、轨道层级、剪辑序列以及预览播放状态。\n\n```typescript\nimport { Studio } from 'openvideo';\n\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\nstudio.play();\n```\n\n资料来源：[README.md]()\n\n### Compositor（合成器）\n\nCompositor 是核心渲染引擎，负责处理视频帧的合成、编码输出和最终导出。它封装了 PixiJS 应用和 WebCodecs 视频编码器，提供统一的渲染接口。\n\n| 配置选项 | 类型 | 默认值 | 说明 |\n|---------|------|-------|------|\n| width | number | 1280 | 输出视频宽度 |\n| height | number | 720 | 输出视频高度 |\n| fps | number | 30 | 帧率 |\n| bgColor | string | '#000000' | 背景颜色 |\n| videoCodec | string | - | 视频编码器 |\n| bitrate | number | - | 比特率 |\n| audio | boolean | true | 是否包含音频 |\n\n资料来源：[packages/node/src/template.html:29-48]()\n\n### Clips（剪辑）\n\nClips 是各类媒体资源的抽象表示，包括以下类型：\n\n| 剪辑类型 | 文件 | 功能 |\n|---------|------|------|\n| VideoClip | video-clip.ts | 视频片段处理，支持 URL、Stream、OPFS 文件加载 |\n| TextClip | text-clip.ts | 文字渲染，支持样式、描边、阴影 |\n| CaptionClip | caption-clip.ts | 字幕处理，支持时间轴对齐和关键词高亮 |\n| AudioClip | - | 音频处理 |\n| ImageClip | - | 静态图像处理 |\n| SubtitleClip | - | 字幕轨道管理 |\n\n#### VideoClip 示例\n\n```typescript\nconst clip = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 100,\n  y: 200,\n  width: 640,\n  height: 480\n});\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:1-50]()\n\n#### TextClip 配置\n\nTextClip 支持丰富的文本样式配置：\n\n- fontFamily: 字体系列\n- fontSize: 字号\n- fontWeight: 字重\n- fontStyle: 斜体\n- fill: 填充颜色（支持渐变）\n- stroke: 描边效果\n- dropShadow: 阴影效果\n- align: 文本对齐\n- wordWrap: 自动换行\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:1-50]()\n\n## 动画系统\n\n### 动画预设\n\nOpenVideo 内置了丰富的动画预设，可在 `presets.ts` 中查看：\n\n| 预设名称 | 效果类型 |\n|---------|---------|\n| fadeIn | 淡入效果 |\n| fadeOut | 淡出效果 |\n| slideIn | 滑入动画 |\n| slideOut | 滑出动画 |\n| pulse | 脉冲动画 |\n| blurIn | 模糊淡入 |\n| blurOut | 模糊淡出 |\n\n```typescript\n// 动画配置结构\n{\n  \"0%\": {\n    x: 0,\n    y: 0,\n    opacity: 0,\n    scale: 1,\n    mirror: 0\n  },\n  \"100%\": {\n    x: 100,\n    y: 0,\n    opacity: 1,\n    scale: 1,\n    mirror: 0\n  }\n}\n```\n\n资料来源：[packages/openvideo/src/animation/presets.ts:1-80]()\n\n### 变换属性\n\nBaseSprite 提供了完整的变换控制：\n\n| 属性 | 说明 |\n|-----|------|\n| x, y | 位置坐标 |\n| width, height | 尺寸 |\n| scale, scaleX, scaleY | 缩放 |\n| angle | 旋转角度 |\n| opacity | 透明度 |\n| blur | 模糊程度 |\n| brightness | 亮度 |\n| mirror | 镜像模式 |\n| motionBlur | 运动模糊 |\n\n资料来源：[packages/openvideo/src/sprite/base-sprite.ts:1-50]()\n\n## 转场效果\n\n### 支持的转场类型\n\nOpenVideo 实现了超过 30 种 GLSL 着色器转场效果：\n\n| 转场名称 | 说明 |\n|---------|------|\n| GridFlip | 网格翻转 |\n| Circle | 圆形展开 |\n| Directional | 方向擦除 |\n| UndulatingBurnOut | 波纹燃烧 |\n| SquaresWire | 方块线条 |\n| RotateScaleFade | 旋转缩放淡入 |\n| RandomSquares | 随机方块 |\n| PolarFunction | 极坐标变换 |\n| Hexagonalize | 六边形化 |\n| Heart | 心形展开 |\n| Displacement | 置换变形 |\n| DirectionalWipe | 方向擦除 |\n| DirectionalWarp | 方向扭曲 |\n| Crosshatch | 网格线 |\n| CircleOpen | 圆环展开 |\n| CannabisLeaf | 叶片形状 |\n| StereoViewer | 立体视差 |\n| GlitchDisplace | 故障艺术 |\n| CrossZoom | 交叉缩放 |\n| BowTieHorizontal | 蝴蝶结水平 |\n| PolkaDotsCurtain | 波点帘幕 |\n| Pixelize | 像素化 |\n\n转场效果的实现通过 GLSL 片段着色器完成，支持自定义 uniform 参数配置。\n\n资料来源：[packages/openvideo/src/transition/transition.ts:1-100]()\n\n## 渲染流程\n\n### 服务端渲染\n\nNode.js 包提供了无头浏览器环境下的视频渲染能力：\n\n```mermaid\ngraph TD\n    A[创建 Renderer 实例] --> B[启动本地服务器]\n    B --> C[Playwright 打开浏览器]\n    C --> D[加载 HTML 模板]\n    D --> E[注入 JSON 配置]\n    E --> F[Compositor 初始化]\n    F --> G[逐帧渲染]\n    G --> H[WebCodecs 编码]\n    H --> I[MP4 封装]\n    I --> J[保存输出文件]\n```\n\n### 渲染器配置\n\n```typescript\nconst renderer = new Renderer({\n  json: videoConfig,      // 视频配置 JSON\n  outputPath: './out.mp4', // 输出路径\n  browserOptions: {\n    headless: true,       // 无头模式\n    timeout: 600000       // 10 分钟超时\n  }\n});\n\nrenderer.on('progress', ({ phase, progress }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n});\n\nawait renderer.render();\n```\n\n### 渲染进度事件\n\n| 阶段 | 说明 |\n|-----|------|\n| initializing | 初始化中 |\n| loading | 加载资源 |\n| rendering | 渲染中 |\n| saving | 保存文件 |\n| complete | 完成 |\n\n资料来源：[packages/node/README.md:60-90]()\n\n## 工具模块\n\n### MP4 工具\n\n`mp4-utils` 提供了 MP4 容器级别的操作能力，包括样本注入、时间戳规范化、轨道管理等功能。\n\n```typescript\n// 时间戳规范化处理\nsamples.forEach((s) => {\n  if (firstVDTS === null) {\n    firstVDTS = s.dts;\n    firstVCTS = s.cts;\n  }\n  const normalizedDTS = s.dts - firstVDTS;\n  const normalizedCTS = s.cts - (firstVCTS ?? 0);\n  \n  outfile.addSample(trackId, new Uint8Array(s.data), {\n    duration: s.duration,\n    dts: normalizedDTS + offsetDTS,\n    cts: normalizedCTS + offsetCTS,\n    is_sync: s.is_sync\n  });\n});\n```\n\n资料来源：[packages/openvideo/src/mp4-utils/index.ts:1-50]()\n\n### 绿幕抠像\n\n`chromakey` 模块提供了颜色键抠像功能：\n\n```typescript\nimport { createChromakey } from 'openvideo/utils/chromakey';\n\nconst chromakeyFilter = createChromakey({\n  keyColor: [0, 255, 0],  // 绿色\n  similarity: 0.4,\n  smoothness: 0.1\n});\n\n// 用于 VideoClip 的处理管道\nvideoClip.setFilter(chromakeyFilter);\n```\n\n资料来源：[packages/openvideo/src/utils/chromakey.ts:1-50]()\n\n## 使用方式\n\n### 前端使用\n\n```typescript\nimport { Studio, Compositor, Video, TextClip } from 'openvideo';\n\n// 1. 创建工作室\nconst studio = new Studio({\n  canvas: document.getElementById('canvas'),\n  width: 1920,\n  height: 1080\n});\n\n// 2. 添加视频\nconst video = await Video.fromUrl('input.mp4');\nstudio.addClip(video);\n\n// 3. 添加文字\nconst text = new TextClip('Hello World', {\n  fontSize: 48,\n  fontFamily: 'Arial'\n});\nstudio.addClip(text);\n\n// 4. 预览播放\nstudio.play();\n```\n\n### 服务端渲染\n\n```bash\n# 安装依赖\npnpm install\n\n# 构建项目\npnpm build\n\n# 运行示例\ncd packages/node\npnpm render\n```\n\n## 环境要求\n\n| 环境 | 版本要求 |\n|-----|---------|\n| Node.js | >= 18 |\n| 浏览器 | 支持 WebCodecs（Chrome 94+, Edge 94+） |\n| Playwright | Chromium 已安装 |\n\n## 许可证\n\nOpenVideo 采用 MIT 许可证开源。详情请参阅 [LICENSE](LICENSE) 文件。\n\n## 联系方式\n\n如有问题或合作意向，可通过以下方式联系：\n\n- 邮箱：hello@openvideo.dev\n- 官网：https://openvideo.dev\n\n---\n\n<a id='page-installation'></a>\n\n## 安装与配置\n\n### 相关页面\n\n相关主题：[项目介绍](#page-introduction), [快速开始](#page-quick-start)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [docs/content/docs/installation.mdx](https://github.com/openvideodev/openvideo/blob/main/docs/content/docs/installation.mdx)\n- [packages/openvideo/package.json](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/package.json)\n- [package.json](https://github.com/openvideodev/openvideo/blob/main/package.json)\n- [packages/node/README.md](https://github.com/openvideodev/openvideo/blob/main/packages/node/README.md)\n- [packages/openvideo/README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n- [packages/node/package.json](https://github.com/openvideodev/openvideo/blob/main/packages/node/package.json)\n</details>\n\n# 安装与配置\n\nOpenVideo 是一个基于 WebCodecs API 的高性能视频处理和渲染库，支持在浏览器和 Node.js 环境中进行视频合成、编辑和导出。本页面详细介绍 OpenVideo 项目的安装流程、依赖要求以及各平台的配置方法。\n\n## 系统要求\n\n### 浏览器环境要求\n\nOpenVideo 核心库依赖 WebCodecs API 进行硬件加速的视频编解码处理。根据 `packages/openvideo/package.json` 中的信息，浏览器环境需要满足以下要求：\n\n| 组件 | 最低要求 | 说明 |\n|------|---------|------|\n| WebCodecs API | 必须支持 | 用于视频编码和解码的核心 API |\n| 浏览器版本 | Chrome 94+ / Edge 94+ / Opera 80+ | 主流浏览器需开启相关特性标志 |\n| ES Modules | 必须支持 | 包使用 ES Module 格式发布 |\n| OPFS API | 推荐支持 | 用于本地大文件存储，提升性能 |\n\nWebCodecs API 在部分浏览器中可能需要手动启用特性标志。Chromium 内核浏览器可通过以下方式启用：\n\n```javascript\n// 启用 WebCodecs API\nawait navigator.mediaCapabilities.decodingInfo({\n  type: 'file',\n  video: { type: 'video/mp4', width: 1920, height: 1080, bitrate: 5000000 }\n});\n```\n\n资料来源：[packages/openvideo/package.json:1-35]()\n\n### Node.js 环境要求\n\n当使用 `@combo/node` 包进行服务端视频渲染时，需要满足以下条件：\n\n| 要求 | 版本 | 说明 |\n|------|------|------|\n| Node.js | >= 18 | 需要支持 ES Modules 和部分 Web API |\n| Playwright | 最新版 | 用于无头浏览器环境运行渲染 |\n| 操作系统 | Windows/macOS/Linux | 支持 Playwright 运行的所有平台 |\n\n资料来源：[packages/node/README.md:1-100]()\n\n## 安装方式\n\n### 使用 pnpm（推荐）\n\nOpenVideo 采用 Monorepo 结构管理多个包，推荐使用 pnpm 进行安装：\n\n```bash\n# 安装根依赖\npnpm install\n\n# 安装 openvideo 核心包\npnpm --filter openvideo build\n\n# 安装 Node.js 渲染包\npnpm --filter @combo/node build\n```\n\n资料来源：[packages/openvideo/package.json:1-40]()\n\n### 使用 npm\n\n```bash\n# 安装核心库\nnpm install openvideo\n\n# 安装 Node.js 渲染包\nnpm install @combo/node\n```\n\n### 使用 yarn\n\n```bash\n# 安装核心库\nyarn add openvideo\n\n# 安装 Node.js 渲染包\nyarn add @combo/node\n```\n\n### CDN 引入\n\n对于浏览器环境，可以直接通过 CDN 引入 OpenVideo：\n\n```html\n<script type=\"importmap\">\n{\n  \"imports\": {\n    \"openvideo\": \"https://unpkg.com/openvideo/dist/index.es.js\"\n  }\n}\n</script>\n<script type=\"module\">\n  import { Compositor, Studio } from 'openvideo';\n  // 使用 OpenVideo API\n</script>\n```\n\n资料来源：[packages/node/src/template.html:1-20]()\n\n## 包结构说明\n\nOpenVideo 项目包含多个子包，每个包承担特定功能：\n\n### 核心包 (openvideo)\n\n| 属性 | 值 | 说明 |\n|------|---|------|\n| 包名 | openvideo | 核心视频处理库 |\n| 版本 | 0.2.18 | 当前稳定版本 |\n| 入口 (main) | dist/index.umd.js | UMD 格式，用于传统 script 标签 |\n| 入口 (module) | dist/index.es.js | ES Module 格式 |\n| 类型定义 | dist/index.d.ts | TypeScript 类型定义 |\n\n```json\n{\n  \"name\": \"openvideo\",\n  \"version\": \"0.2.18\",\n  \"main\": \"dist/index.umd.js\",\n  \"module\": \"dist/index.es.js\",\n  \"types\": \"dist/index.d.ts\"\n}\n```\n\n资料来源：[packages/openvideo/package.json:1-20]()\n\n### Node.js 渲染包 (@combo/node)\n\n用于在 Node.js 环境中进行服务端视频渲染，通过 Playwright 控制无头浏览器执行渲染任务：\n\n```json\n{\n  \"name\": \"@combo/node\",\n  \"dependencies\": {\n    \"playwright\": \"latest\"\n  }\n}\n```\n\n资料来源：[packages/node/package.json]()\n\n## 核心组件导入\n\n### 浏览器环境导入\n\n```typescript\n// 方式一：从完整包导入\nimport { Studio, Compositor, Video, Audio, Text, Image } from 'openvideo';\n\n// 方式二：按需导入（Tree-shaking 友好）\nimport { Studio } from 'openvideo';\nimport { Compositor } from 'openvideo';\nimport { Video } from 'openvideo/clips/video-clip';\n```\n\n### Node.js 环境导入\n\n```typescript\nimport { Renderer } from '@combo/node';\n\nconst renderer = new Renderer({\n  json: videoConfig,\n  outputPath: './output.mp4'\n});\n\nrenderer.on('progress', ({ phase, progress }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n});\n\nawait renderer.render();\n```\n\n资料来源：[packages/node/README.md:80-120]()\n\n## 构建配置\n\n### 浏览器端构建\n\nOpenVideo 使用 Vite 进行构建，生成 UMD 和 ES Module 两种格式：\n\n```bash\n# 在 packages/openvideo 目录下\npnpm build\n```\n\n构建产物包含：\n\n| 文件 | 格式 | 用途 |\n|------|------|------|\n| dist/index.umd.js | UMD | 兼容 AMD/CommonJS/全局变量 |\n| dist/index.es.js | ES Module | 现代浏览器和打包工具 |\n| dist/index.d.ts | TypeScript | 类型定义 |\n\n资料来源：[packages/openvideo/package.json:20-35]()\n\n### Node.js 包构建\n\n```bash\n# 构建 Node.js 渲染包\npnpm --filter @combo/node build\n```\n\n构建后需复制 HTML 模板到 dist 目录：\n\n```bash\n# 复制模板文件\ncp src/template.html dist/template.html\n```\n\n资料来源：[packages/node/README.md:40-80]()\n\n## 渲染器配置\n\n### Compositor 配置选项\n\n在浏览器环境中，Compositor 是核心渲染引擎：\n\n```typescript\nconst compositorOpts = {\n  width: 1920,           // 视频宽度\n  height: 1080,          // 视频高度\n  fps: 30,               // 帧率\n  bgColor: '#000000',    // 背景颜色\n  videoCodec: 'avc1.64001f',  // 视频编码器（可选）\n  bitrate: 5000000,      // 比特率（可选）\n  audio: true,           // 是否包含音频\n  metaDataTags: {        // 元数据标签（可选）\n    title: 'My Video',\n    author: 'Creator'\n  }\n};\n\nconst compositor = new Compositor(compositorOpts);\nawait compositor.initPixiApp();\n```\n\n资料来源：[packages/node/src/template.html:30-60]()\n\n### Renderer 配置选项（Node.js）\n\n| 选项 | 类型 | 必填 | 默认值 | 说明 |\n|------|------|------|--------|------|\n| json | object | 是 | - | 视频配置 JSON 对象 |\n| outputPath | string | 是 | - | 输出文件路径 |\n| browserOptions | object | 否 | 见下文 | 浏览器配置 |\n\n**browserOptions 子选项：**\n\n| 选项 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| headless | boolean | true | 是否使用无头模式 |\n| timeout | number | 300000 | 超时时间（毫秒） |\n\n```typescript\nconst renderer = new Renderer({\n  json: videoConfig,\n  outputPath: './output.mp4',\n  browserOptions: {\n    headless: true,\n    timeout: 600000  // 10 分钟\n  }\n});\n```\n\n资料来源：[packages/node/README.md:100-140]()\n\n## 快速开始示例\n\n### 浏览器端视频编辑\n\n```typescript\nimport { Studio, Video, Audio } from 'openvideo';\n\n// 1. 创建 Studio 实例\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\n// 2. 加载并添加视频片段\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 3. 添加音频\nconst audio = await Audio.fromUrl('https://example.com/audio.mp3');\nawait studio.addClip(audio);\n\n// 4. 开始预览\nstudio.play();\n```\n\n资料来源：[README.md:1-50]()\n\n### 服务端批量渲染\n\n```typescript\nimport { Renderer } from '@combo/node';\n\n// 批量渲染配置\nconst videos = [\n  { config: videoConfig1, output: 'output1.mp4' },\n  { config: videoConfig2, output: 'output2.mp4' }\n];\n\nfor (const { config, output } of videos) {\n  const renderer = new Renderer({\n    json: config,\n    outputPath: output\n  });\n  \n  renderer.on('progress', ({ phase, progress }) => {\n    console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n  });\n  \n  await renderer.render();\n  console.log(`✅ 已生成: ${output}`);\n}\n```\n\n## 开发环境配置\n\n### TypeScript 配置\n\n确保 tsconfig.json 正确配置模块解析：\n\n```json\n{\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"target\": \"ES2020\",\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"]\n  }\n}\n```\n\n### 开发工作流\n\n```mermaid\ngraph TD\n    A[修改源代码] --> B[运行构建命令]\n    B --> C{目标平台}\n    C -->|浏览器| D[pnpm --filter openvideo build]\n    C -->|Node.js| E[pnpm --filter @combo/node build]\n    D --> F[测试功能]\n    E --> F\n    F --> G{验证通过?}\n    G -->|是| H[提交代码]\n    G -->|否| A\n```\n\n开发调试步骤：\n\n1. **修改源代码** - 在 `packages/openvideo/src/` 或 `packages/node/src/` 目录下修改代码\n2. **重新构建** - 运行相应的构建命令\n3. **运行测试** - 执行 `pnpm test` 验证功能\n4. **调试运行** - 在 Node.js 中测试 `node dist/sample.js`\n\n资料来源：[packages/node/README.md:60-90]()\n\n## 常见问题排查\n\n### Playwright 安装失败\n\n```bash\n# 手动安装 Chromium\nnpx playwright install chromium\n```\n\n### 模块解析错误\n\n确保 openvideo 包已构建：\n\n```bash\npnpm --filter openvideo build\n```\n\n### 渲染超时\n\n增加浏览器超时时间：\n\n```typescript\nbrowserOptions: {\n  timeout: 600000  // 10 分钟\n}\n```\n\n### WebCodecs 不可用\n\n检查浏览器是否支持 WebCodecs：\n\n```javascript\nif ('VideoDecoder' in window) {\n  console.log('WebCodecs API 支持正常');\n} else {\n  console.error('浏览器不支持 WebCodecs API');\n}\n```\n\n## 技术栈依赖\n\nOpenVideo 基于以下核心技术构建：\n\n| 技术 | 用途 | 版本要求 |\n|------|------|----------|\n| WebCodecs | 硬件加速视频编解码 | 现代浏览器 |\n| PixiJS | 2D 渲染引擎 | 最新稳定版 |\n| wrapbox | MP4 容器操作 | 内置工具库 |\n| Playwright | 无头浏览器控制 | Node.js 环境 |\n\n核心组件架构：\n\n```mermaid\ngraph TB\n    subgraph \"用户层\"\n        A[Studio API]\n        B[Compositor API]\n        C[Clip API]\n    end\n    \n    subgraph \"渲染引擎层\"\n        D[PixiJS Renderer]\n        E[WebCodecs Encoder]\n        F[WebCodecs Decoder]\n    end\n    \n    subgraph \"文件处理层\"\n        G[MP4 Muxer]\n        H[wrapbox]\n        I[OPFS Manager]\n    end\n    \n    A --> D\n    B --> E\n    C --> F\n    D --> G\n    E --> G\n    F --> I\n    G --> H\n```\n\n资料来源：[README.md:50-80]()\n\n## 下一步\n\n完成安装配置后，建议继续阅读以下文档：\n\n- [快速开始指南](./quickstart.mdx) - 了解核心使用流程\n- [API 参考](./api-reference.mdx) - 完整的 API 文档\n- [示例项目](../examples/index.md) - 实际应用案例\n\n---\n\n<a id='page-quick-start'></a>\n\n## 快速开始\n\n### 相关页面\n\n相关主题：[安装与配置](#page-installation), [Studio - 项目状态管理](#page-studio)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio.ts)\n- [examples/src/App.tsx](https://github.com/openvideodev/openvideo/blob/main/examples/src/App.tsx)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/package.json](https://github.com/openvideov/openvideo/blob/main/packages/openvideo/package.json)\n- [README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n</details>\n\n# 快速开始\n\n本文档将帮助你在 5 分钟内快速上手 OpenVideo，掌握视频渲染项目的基本创建、剪辑添加和预览播放流程。\n\n---\n\n## 环境要求\n\n| 要求 | 版本说明 |\n|------|----------|\n| Node.js | >= 18 |\n| 包管理器 | pnpm（推荐） |\n| 浏览器 | 支持 WebCodecs API 的现代浏览器（Chrome、Edge、Firefox） |\n\n**安装依赖：**\n\n```bash\n# 克隆项目\ngit clone https://github.com/openvideodev/openvideo.git\ncd openvideo\n\n# 安装项目依赖\npnpm install\n\n# 构建核心包\npnpm --filter openvideo build\n```\n\n资料来源：[README.md:1-50]()\n\n---\n\n## 核心概念\n\nOpenVideo 的架构围绕三个核心组件展开：**Studio**（工作室）、**Compositor**（合成器）和 **Clips**（剪辑片段）。\n\n### 组件架构图\n\n```mermaid\ngraph TD\n    A[Studio] --> B[Compositor]\n    A --> C[Clips]\n    C --> D[Video]\n    C --> E[Audio]\n    C --> F[Text]\n    C --> G[Image]\n    C --> H[Caption]\n    B --> I[WebCodecs]\n    B --> J[PixiJS]\n    I --> K[MP4 Output]\n```\n\n| 组件 | 职责 |\n|------|------|\n| **Studio** | 管理项目状态、时间轴、轨道和剪辑 |\n| **Compositor** | 渲染引擎，处理播放、seek 和最终导出 |\n| **Clips** | 不同媒体类型的专用对象 |\n\n资料来源：[README.md:50-80]()\n\n---\n\n## 基本使用流程\n\n### 1. 创建 Studio 实例\n\n首先，需要在 HTML 中创建一个 `<canvas>` 元素用于渲染：\n\n```html\n<canvas id=\"preview-canvas\"></canvas>\n```\n\n然后在 JavaScript/TypeScript 中初始化 Studio：\n\n```typescript\nimport { Studio } from 'openvideo';\n\n// 获取 canvas 元素\nconst canvas = document.getElementById('preview-canvas') as HTMLCanvasElement;\n\n// 创建 Studio 实例\nconst studio = new Studio({\n  canvas,\n  width: 1280,\n  height: 720,\n  spacing: 20  // 可选：剪辑间距\n});\n\n// 等待初始化完成\nawait studio.ready;\n```\n\n资料来源：[examples/src/App.tsx:1-30]()\n\n### 2. 添加视频剪辑\n\n使用 `Video.fromUrl()` 从 URL 加载视频并添加到时间轴：\n\n```typescript\nimport { Studio, Video } from 'openvideo';\n\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\n// 加载并添加视频剪辑\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 也可以设置位置和尺寸\nconst video2 = await Video.fromUrl('https://example.com/video2.mp4', {\n  x: 100,\n  y: 200,\n  width: 640,\n  height: 360\n});\nawait studio.addClip(video2);\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:80-120]()\n\n### 3. 添加文本剪辑\n\n使用 `Text` 类创建文本覆盖层：\n\n```typescript\nimport { Studio, Text } from 'openvideo';\n\nconst text = new Text('Hello World');\ntext.duration = 5000000;  // 5秒（微秒单位）\nawait studio.addClip(text);\n```\n\n资料来源：[packages/openvideo/src/studio.ts:1-50]()\n\n### 4. 启动预览播放\n\n```typescript\n// 开始播放\nstudio.play();\n\n// 暂停\nstudio.pause();\n\n// 跳转时间\nstudio.seek(2000000);  // 2秒位置\n```\n\n---\n\n## 完整示例代码\n\n以下是一个完整的快速开始示例：\n\n```typescript\nimport { Studio, Video, Text } from 'openvideo';\n\n// 1. 初始化 Studio\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n  spacing: 20\n});\n\n// 2. 加载并添加视频\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 3. 添加文本叠加\nconst title = new Text('OpenVideo Quick Start');\ntitle.duration = 5000000;  // 5秒\nawait studio.addClip(title);\n\n// 4. 开始预览\nstudio.play();\n```\n\n---\n\n## 项目结构\n\n```\nopenvideo/\n├── packages/\n│   ├── openvideo/              # 核心渲染库\n│   │   ├── src/\n│   │   │   ├── studio.ts       # Studio 主类\n│   │   │   ├── compositor.ts  # 渲染引擎\n│   │   │   └── clips/          # 各类剪辑\n│   │   └── dist/               # 构建输出\n│   └── node/                   # Node.js 渲染包\n├── examples/                   # 示例应用\n└── docs/                       # 文档\n```\n\n资料来源：[README.md:1-30]()\n\n---\n\n## 核心 API 概览\n\n### Studio 类\n\n| 方法 | 说明 |\n|------|------|\n| `addClip(clip)` | 添加剪辑到时间轴 |\n| `removeClip(id)` | 从时间轴移除剪辑 |\n| `play()` | 开始播放 |\n| `pause()` | 暂停播放 |\n| `seek(time)` | 跳转到指定时间（微秒） |\n| `destroy()` | 销毁实例，释放资源 |\n\n### 可用剪辑类型\n\n| 类型 | 类名 | 说明 |\n|------|------|------|\n| 视频 | `Video` | 加载和播放视频文件 |\n| 音频 | `Audio` | 加载和播放音频文件 |\n| 文本 | `Text` | 文本叠加层 |\n| 图片 | `Image` | 静态图像 |\n| 字幕 | `Caption` | 带动画的字幕 |\n| 特效 | `Effect` | 视频特效 |\n\n资料来源：[packages/openvideo/src/studio.ts:50-100]()\n\n---\n\n## 下一步\n\n- **深入学习**：查看 [基础用法文档](./basic-usage.mdx) 了解更多高级功能\n- **技术栈**：OpenVideo 基于 [WebCodecs](https://developer.mozilla.org/en-US/docs/Web/API/WebCodecs_API)（硬件加速视频处理）和 [PixiJS](https://pixijs.com/)（2D/3D 渲染引擎）\n- **示例项目**：参考 `examples/` 目录中的完整示例\n\n资料来源：[README.md:80-100]()\n\n---\n\n<a id='page-architecture'></a>\n\n## 系统架构\n\n### 相关页面\n\n相关主题：[Studio - 项目状态管理](#page-studio), [Compositor - 渲染引擎](#page-compositor)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio.ts)\n- [packages/openvideo/src/compositor.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/compositor.ts)\n- [packages/openvideo/src/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/index.ts)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/transition/transition.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/transition/transition.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n- [packages/node/src/template.html](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/template.html)\n- [packages/node/src/renderer.ts](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/renderer.ts)\n- [README.md](https://github.com/openvideodev/openvideo/blob/main/README.md)\n</details>\n\n# 系统架构\n\n## 概述\n\nOpenVideo 是一个基于 Web 技术的视频渲染和处理库，其核心设计围绕**客户端视频合成**展开。该项目利用现代浏览器原生 API（主要是 WebCodecs）实现硬件加速的视频编解码，并通过 PixiJS 提供高性能的 2D/3D 渲染能力。 资料来源：[README.md]()\n\n系统的设计目标是提供一个纯前端实现的视频编辑框架，使开发者能够在浏览器环境中完成从素材加载、合成编辑到最终 MP4 输出的完整流程。架构上采用分层设计，核心层负责渲染引擎与媒体处理，节点层提供服务端自动化渲染能力。 资料来源：[packages/openvideo/package.json:1-14]()\n\n## 核心架构分层\n\nOpenVideo 系统采用三层架构设计，从上至下分别为：\n\n| 层级 | 组件 | 职责 |\n|------|------|------|\n| 应用层 | Studio | 项目状态管理、时间线编排、轨道与剪辑管理 |\n| 渲染层 | Compositor | PixiJS 应用初始化、帧渲染、播放控制、导出编码 |\n| 媒体层 | Clips、MP4 Utils | 视频/音频/文本等素材解码、MP4 封装与解封装 |\n\n```mermaid\ngraph TD\n    A[用户应用] --> B[Studio<br/>项目状态管理层]\n    B --> C[Compositor<br/>渲染引擎]\n    C --> D[PixiJS 渲染器]\n    C --> E[WebCodecs 编码器]\n    D --> F[Canvas 2D/WebGL]\n    E --> G[MP4 文件输出]\n    H[Clips 素材层] --> B\n    I[Node Renderer<br/>服务端自动化] --> E\n```\n\n资料来源：[README.md:30-45]()\n\n## 核心组件详解\n\n### Studio（项目状态管理）\n\nStudio 是整个系统的状态管理中心，负责管理项目配置、轨道布局、剪辑排列以及时间线相关的逻辑。它维护着项目中所有的轨道（Track）和剪辑（Clip）对象，并协调它们与 Compositor 之间的数据交互。\n\n主要职责包括：\n\n- **项目配置管理**：存储和管理视频的全局设置（如分辨率、帧率、背景色等）\n- **轨道管理**：维护多个轨道的层级关系，处理轨道的添加、删除、排序\n- **剪辑调度**：管理每个轨道上的剪辑对象，处理剪辑之间的对齐、重叠逻辑\n- **播放控制**：协调 Compositor 的播放、暂停、寻址操作\n\nStudio 的设计使得开发者可以通过声明式的方式定义视频结构，然后交由下层的渲染引擎执行具体的画面合成。 资料来源：[packages/openvideo/src/studio.ts]()\n\n### Compositor（渲染引擎）\n\nCompositor 是整个系统的核心渲染引擎，负责将 Studio 管理的轨道和剪辑数据转换为可视化的帧序列，并最终输出为 MP4 文件。它是衔接上层业务逻辑与底层媒体 API 的关键桥梁。\n\n```mermaid\ngraph LR\n    A[轨道数据] --> B[Compositor]\n    B --> C[PixiJS 应用]\n    C --> D[Canvas 渲染]\n    B --> E[VideoFrame]\n    E --> F[WebCodecs<br/>VideoEncoder]\n    F --> G[MP4 Muxer]\n    G --> H[output.mp4]\n```\n\nCompositor 的初始化过程如下：\n\n1. 创建 WebCodecs VideoEncoder 和 AudioEncoder 实例\n2. 初始化 PixiJS Application 作为 2D 渲染上下文\n3. 加载并解析所有轨道上的剪辑资源\n4. 设置事件监听器用于进度报告和错误处理\n\n渲染流程中，Compositor 按照指定帧率（默认 30fps）驱动 PixiJS 渲染每一帧画面，同时将 VideoFrame 数据送入 VideoEncoder 进行编码。编码后的样本（Sample）被传递给 MP4 封装器生成最终的输出文件。 资料来源：[packages/openvideo/src/compositor.ts]()\n\nCompositor 的核心配置选项：\n\n| 参数 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| width | number | 1280 | 输出视频宽度（像素） |\n| height | number | 720 | 输出视频高度（像素） |\n| fps | number | 30 | 输出帧率 |\n| bgColor | string | '#000000' | 背景颜色 |\n| videoCodec | string | - | 视频编码器标识 |\n| bitrate | number | - | 视频码率（bps） |\n| audio | boolean | true | 是否包含音频轨道 |\n| metaDataTags | object | - | MP4 元数据标签 |\n\n资料来源：[packages/node/src/template.html:20-40]()\n\n### Clips（素材剪辑）\n\nClips 是处理各类媒体素材的专门对象体系，每种媒体类型对应一个独立的 Clip 类。Clip 对象负责素材的加载、解码、以及在渲染时向 Compositor 提供对应的画面数据。\n\n#### 剪辑类型体系\n\n| 剪辑类型 | 类名 | 功能描述 |\n|----------|------|----------|\n| 视频剪辑 | Video | 加载并解码 MP4/WebM 视频流 |\n| 音频剪辑 | Audio | 处理音频轨道和音量控制 |\n| 文本剪辑 | Text | 渲染文字内容，支持样式和动画 |\n| 图像剪辑 | Image | 加载并显示静态图片 |\n| 字幕剪辑 | Caption | 时间轴驱动的字幕渲染 |\n\n#### Video Clip 实现\n\nVideo Clip 是最复杂的剪辑类型，它整合了资源加载、流解码和帧提取三个环节。核心逻辑位于 `video-clip.ts`：\n\n```mermaid\ngraph TD\n    A[Video.fromUrl<br/>静态工厂方法] --> B[ResourceManager<br/>获取可读流]\n    B --> C[new Video<br/>实例化剪辑]\n    C --> D[write<br/>写入 OPFS]\n    D --> E[ready promise<br/>等待解码完成]\n    E --> F[本地文件引用]\n```\n\n构造函数接受三种数据源类型：\n\n1. `ReadableStream<Uint8Array>` - 直接传入的流数据\n2. `OPFSToolFile` - 已存在于 OPFS（Origin Private File System）中的文件\n3. `MPClipCloneArgs` - 用于克隆已有剪辑状态的参数对象\n\n音频处理通过 `opts.audio` 参数控制，支持布尔值和对象两种配置方式。当为对象时，可通过 `volume` 属性独立控制音量。 资料来源：[packages/openvideo/src/clips/video-clip.ts:50-80]()\n\n#### Text Clip 实现\n\nText Clip 负责文字内容的渲染，其样式系统基于 PixiJS 的 TextStyle 构建，支持丰富的排版选项：\n\n- **字体样式**：fontFamily、fontWeight、fontStyle\n- **颜色填充**：支持纯色和渐变填充（gradient）\n- **描边效果**：stroke 对象定义描边颜色、宽度、连接方式和尖角样式\n- **阴影效果**：dropShadow 配置阴影颜色、透明度、模糊度和偏移\n\n渐变填充需要使用 `FillGradient` 类创建，通过 `x0`、`y0`、`x1`、`y1` 定义渐变向量方向，色彩数组通过 `ratio` 和 `color` 指定各节点的位置和颜色。 资料来源：[packages/openvideo/src/clips/text-clip.ts:60-100]()\n\n### 过渡效果系统（Transitions）\n\nTransition 系统负责处理轨道之间的画面切换效果。该系统支持多种内置过渡类型，每种过渡都有对应的 GLSL 着色器实现。\n\n#### 支持的过渡效果\n\n| 过渡名称 | 说明 | 匹配变体 |\n|----------|------|----------|\n| GridFlip | 网格翻转 | gridflip、GridFlip、grid_flip |\n| Circle | 圆形展开 | circle、circle_open |\n| Directional | 方向性擦除 | directional、directional_wipe |\n| UndulatingBurnOut | 波动燃烧 | undulatingburnout、UndulatingBurnOut |\n| SquaresWire | 方形线框 | squareswire、SquaresWire |\n| RotateScaleFade | 旋转缩放淡入淡出 | rotateScaleFade、rotatescalefade |\n| RandomSquares | 随机方块 | randomSquares、RandomSquares |\n| PolkaDotsCurtain | 圆点幕布 | polkadotscurtain、PolkaDotsCurtain |\n| Pixelize | 像素化 | pixelize、Pixelize |\n\n过渡名称的解析采用宽松匹配策略，支持驼峰命名、下划线分隔、全大写等多种变体形式。解析流程首先在用户传入的过渡对象中查找，然后搜索内置过渡注册表，最后尝试各种命名变体。 资料来源：[packages/openvideo/src/transition/transition.ts:1-80]()\n\n### 动画预设系统（Animation Presets）\n\n动画预设提供预定义的补间动画（tween）模式，可应用于剪辑的位置、缩放、透明度等属性变化。\n\n#### 支持的预设动画\n\n| 预设名称 | 描述 | 关键帧示例 |\n|----------|------|------------|\n| slideIn | 从指定方向滑入 | 0%: 外部位置 → 100%: 目标位置 |\n| slideOut | 向指定方向滑出 | 0%: 当前位置 → 100%: 外部位置 |\n| pulse | 脉冲缩放效果 | 0%→25%→50%→75%→100% 循环缩放 |\n| blurIn | 模糊淡入 | 0%: 高模糊低透明度 → 100%: 无模糊完全透明 |\n\n动画参数通过 `normalized` 对象自定义，slideIn/slideOut 预设支持：\n\n- `direction`: 方向（left、right、top、bottom）\n- `distance`: 移动距离（像素）\n- `duration`: 持续时间（毫秒，由调用方控制） 资料来源：[packages/openvideo/src/animation/presets.ts:20-60]()\n\n## 媒体封装与解封装\n\n### MP4 Utils 模块\n\nMP4 Utils 模块（位于 `src/mp4-utils/index.ts`）负责 MP4 文件格式的解析和生成，是实现视频导入和导出的底层基础设施。\n\n#### 时间戳规范化\n\n视频和音频样本的时间戳（ DTS / CTS ）在封装前需要经过规范化处理，确保时间线从零开始：\n\n1. 记录第一个视频样本和音频样本的时间戳作为基准\n2. 所有后续样本的 DTS 和 CTS 减去对应基准值\n3. 加上调用方指定的偏移量（offsetDTS / offsetCTS）\n\n这种处理方式保证了多轨道合成的正确性，使得音频和视频能够精确同步。 资料来源：[packages/openvideo/src/mp4-utils/index.ts:80-120]()\n\n#### 样本数据结构\n\n样本数据通过 `addSample` 方法添加到 MP4 文件中，每个样本包含：\n\n| 属性 | 类型 | 说明 |\n|------|------|------|\n| trackId | number | 所属轨道 ID |\n| data | Uint8Array | 编码后的样本数据 |\n| duration | number | 样本持续时间 |\n| dts | number | 解码时间戳 |\n| cts | number | composition 时间戳 |\n| is_sync | boolean | 是否为同步帧（关键帧） |\n\n### Thumbnail 生成器\n\n视频剪辑包含独立的缩略图生成功能，使用独立的 VideoDecoder 实例进行解码。解码器支持软件降级模式（`downgrade = true`），当硬件加速不可用时自动回退到软件解码以提高兼容性。\n\n错误处理机制会捕获解码器状态、队列长度和输入输出计数，便于诊断缩略图生成失败的原因。 资料来源：[packages/openvideo/src/clips/video-clip.ts:120-160]()\n\n## Node.js 渲染层\n\n### Renderer 类架构\n\nNode.js 包（`@combo/node`）提供了服务端自动化渲染能力，通过 Playwright 控制无头浏览器执行 HTML 模板中的渲染逻辑。\n\n```mermaid\ngraph TD\n    A[new Renderer<br/>配置初始化] --> B[render<br/>开始渲染]\n    B --> C[启动本地 HTTP 服务器]\n    C --> D[Playwright 启动 Chromium]\n    D --> E[加载 template.html]\n    E --> F[注入 RENDER_CONFIG]\n    F --> G[执行 Compositor<br/>WebCodecs 编码]\n    G --> H[触发 download 事件]\n    H --> I[保存文件到 outputPath]\n    I --> J[返回输出路径]\n```\n\nRenderer 继承自 EventEmitter，暴露三个事件：\n\n| 事件名称 | 回调参数 | 触发时机 |\n|----------|----------|----------|\n| progress | `{ phase, progress, message }` | 各阶段进度更新 |\n| error | `Error` | 渲染过程中发生错误 |\n| complete | `string` | 渲染完成，返回输出文件路径 |\n\n进度报告的阶段（phase）包括：initializing、loading、rendering、saving、complete。 资料来源：[packages/node/src/renderer.ts]()\n\n### HTML 渲染模板\n\n渲染模板（`template.html`）运行在浏览器环境中，负责：\n\n1. 从 `window.RENDER_CONFIG` 获取渲染配置\n2. 创建 Compositor 实例并初始化 PixiJS 应用\n3. 监听 Compositor 事件并向父进程报告进度\n4. 触发视频文件下载\n\n模板使用 Import Maps 解析 `openvideo` 包，确保模块能够正确加载：\n\n```html\n<script type=\"importmap\">\n{\n    \"imports\": {\n        \"openvideo\": \"/node_modules/openvideo/dist/index.es.js\"\n    }\n}\n</script>\n```\n\n配置参数通过 JSON 注入，支持设置分辨率、帧率、背景色、视频编码器、码率和元数据标签。 资料来源：[packages/node/src/template.html:1-50]()\n\n## 技术栈概览\n\n| 技术 | 用途 | 层级 |\n|------|------|------|\n| WebCodecs | 视频/音频编解码 | 媒体层 |\n| PixiJS | 2D 渲染引擎 | 渲染层 |\n| Compositor | 帧合成与导出 | 渲染层 |\n| wrapbox | MP4 Box 解析与写入 | 媒体层 |\n| Playwright | 浏览器自动化控制 | 节点层 |\n| TypeScript | 类型安全开发 | 全栈 |\n\nWebCodecs 提供硬件加速的视频编解码能力，是实现高性能渲染的关键技术。PixiJS 则负责处理文本、图像、过渡效果等视觉元素的渲染，两者的结合使得 OpenVideo 能够在浏览器环境中实现接近原生的视频处理性能。 资料来源：[README.md:45-55]()\n\n## 包导出结构\n\nOpenVideo 主包（`openvideo`）通过 `src/index.ts` 统一导出所有公共 API：\n\n| 导出项 | 来源 | 说明 |\n|--------|------|------|\n| Studio | studio.ts | 项目状态管理类 |\n| Compositor | compositor.ts | 渲染引擎类 |\n| Video | video-clip.ts | 视频剪辑类 |\n| Text | text-clip.ts | 文本剪辑类 |\n| Caption | caption-clip.ts | 字幕剪辑类 |\n| Image | image-clip.ts | 图像剪辑类 |\n| Audio | audio-clip.ts | 音频剪辑类 |\n| JsonSerialization | serialization.ts | JSON 序列化工具 |\n\n包的入口配置支持 ES Modules 和 CommonJS 两种模块系统：\n\n```json\n{\n  \"main\": \"dist/index.umd.js\",\n  \"module\": \"dist/index.es.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.es.js\",\n      \"require\": \"./dist/index.umd.js\"\n    }\n  }\n}\n```\n\n资料来源：[packages/openvideo/package.json:15-30]()\n\n## 数据流总览\n\n```mermaid\ngraph LR\n    A[视频素材<br/>MP4/WebM] --> B[Video Clip<br/>解码器]\n    B --> C[VideoFrame]\n    D[音频素材<br/>MP4/WAV] --> E[Audio Clip<br/>解码器]\n    E --> F[AudioFrame]\n    G[文本内容] --> H[Text Clip<br/>PixiJS 渲染]\n    H --> I[Sprite/Texture]\n    C --> J[Compositor<br/>帧合成]\n    F --> J\n    I --> J\n    J --> K[VideoEncoder<br/>WebCodecs]\n    K --> L[EncodedVideoChunk]\n    L --> M[MP4 Muxer<br/>wrapbox]\n    M --> N[output.mp4]\n```\n\n整个数据流从素材输入开始，视频和音频素材分别由对应的 Clip 对象负责解码。Text Clip 生成的纹理与解码后的视频帧一同送入 Compositor 进行帧合成。合成后的画面通过 VideoEncoder 编码为压缩的 Chunk，最后由 MP4 Muxer 按照 ISO Base Media File Format 规范封装为最终的 MP4 文件。\n\n---\n\n<a id='page-studio'></a>\n\n## Studio - 项目状态管理\n\n### 相关页面\n\n相关主题：[系统架构](#page-architecture), [Compositor - 渲染引擎](#page-compositor), [剪辑系统](#page-clips)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio.ts)\n- [packages/openvideo/src/studio/selection-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/selection-manager.ts)\n- [packages/openvideo/src/studio/transport.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/transport.ts)\n- [packages/openvideo/src/studio/timeline-model.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/timeline-model.ts)\n- [packages/openvideo/src/studio/resource-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/resource-manager.ts)\n- [packages/openvideo/src/studio/history-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/history-manager.ts)\n</details>\n\n# Studio - 项目状态管理\n\n## 概述\n\nStudio 是 OpenVideo 库的核心模块，负责管理整个视频编辑项目的状态、轨道、剪辑片段和时间线配置。它作为顶层协调器，整合了时间轴模型、资源管理、选择管理、历史记录管理和播放传输等多个子系统，为用户提供完整的视频编辑体验。\n\nStudio 模块的核心职责包括：管理项目中的所有剪辑片段、协调各子系统之间的通信、处理播放控制、以及维护项目状态的序列化与反序列化。通过 EventEmitter 模式，Studio 实现了模块间的松耦合通信，确保状态变更能够及时传播到所有监听者。\n\n## 架构概览\n\nStudio 的架构采用分层设计，每个子系统专注于特定的功能领域。这种设计使得代码职责清晰，便于维护和扩展。\n\n```mermaid\ngraph TD\n    A[Studio 核心] --> B[TimelineModel 时间轴模型]\n    A --> C[ResourceManager 资源管理]\n    A --> D[SelectionManager 选择管理]\n    A --> E[HistoryManager 历史管理]\n    A --> F[Transport 播放传输]\n    A --> G[PixiJS 渲染引擎]\n    \n    B --> H[Tracks 轨道]\n    B --> I[Clips 剪辑片段]\n    \n    C --> J[文件系统]\n    C --> K[媒体资源]\n    \n    F --> L[播放状态]\n    F --> M[帧控制]\n    \n    G --> N[Canvas 画布]\n    G --> O[Sprites 精灵]\n```\n\n## 核心组件\n\n### TimelineModel（时间轴模型）\n\nTimelineModel 是 Studio 中最核心的数据结构，负责管理项目的时间线和轨道系统。每个 Studio 实例都持有一个 TimelineModel 实例，通过它可以访问和操作项目中的所有轨道和剪辑片段。\n\nTimelineModel 的主要职责包括：创建和管理轨道、添加和删除剪辑片段、更新剪辑属性、以及处理时间相关的计算。轨道（Track）是组织剪辑片段的容器，支持视频轨道、音频轨道、文字轨道等多种类型。\n\n| 方法 | 描述 | 返回值 |\n|------|------|--------|\n| `addTrack(type)` | 添加指定类型的轨道 | `Promise<Track>` |\n| `removeTrack(id)` | 移除指定轨道 | `Promise<void>` |\n| `addClip(trackId, clip)` | 在轨道中添加剪辑 | `Promise<Clip>` |\n| `removeClip(clipId)` | 移除剪辑片段 | `Promise<void>` |\n| `updateSelected(updates)` | 更新选中的剪辑 | `Promise<void>` |\n| `clear()` | 清空所有轨道和剪辑 | `Promise<void>` |\n\n资料来源：[packages/openvideo/src/studio/timeline-model.ts]()\n\n### ResourceManager（资源管理）\n\nResourceManager 负责管理系统中的媒体资源，包括视频、音频、图片等文件的加载和缓存。它提供了统一的资源获取接口，支持从 URL、OPFS（Origin Private File System）以及其他来源加载媒体资源。\n\nResourceManager 使用流式加载机制，能够高效处理大型媒体文件。它还维护了一个资源缓存池，避免重复加载相同的资源。当项目序列化时，ResourceManager 负责将资源引用转换为可序列化的格式，并在反序列化时重建资源连接。\n\n```typescript\n// 从 URL 加载视频资源\nconst stream = await ResourceManager.getReadableStream(url);\n\n// 加载并配置视频剪辑\nconst clip = new Video(stream, {}, url);\n```\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts]()\n\n### HistoryManager（历史管理）\n\nHistoryManager 实现了撤销/重做功能，允许用户回退到之前的操作状态。它维护了一个操作历史栈，记录每次状态变更的快照。\n\n每次用户执行修改操作时（如移动剪辑、调整属性等），HistoryManager 会自动保存当前状态的快照。当用户请求撤销时，系统会从历史栈中弹出上一个状态并恢复。类似地，重做功能会重新应用被撤销的操作。\n\n| 属性 | 类型 | 描述 |\n|------|------|------|\n| `canUndo` | `boolean` | 是否可以执行撤销 |\n| `canRedo` | `boolean` | 是否可以执行重做 |\n| `historyStack` | `StateSnapshot[]` | 历史状态栈 |\n\n资料来源：[packages/openvideo/src/studio/history-manager.ts]()\n\n### SelectionManager（选择管理）\n\nSelectionManager 负责处理剪辑片段的选中状态和变换操作。当用户在画布上点击剪辑时，SelectionManager 会确定被选中的剪辑，并激活相应的变换控制器（Transformer）。\n\n变换控制器支持多种操作模式：移动（无手柄）、调整大小（四角和四边手柄）、旋转（角落外侧手柄）。SelectionManager 还实现了多选功能，通过 Shift 键可以同时选中多个剪辑，并对它们应用统一的变换操作。\n\n```typescript\n// 双击处理\nif (topmostClip.type === 'Text' || topmostClip.type === 'Caption') {\n    this.studio.emit('clip:dblclick', { clip: topmostClip });\n}\n\n// 多选支持\nthis.selectClip(topmostClip, e.shiftKey);\n```\n\n资料来源：[packages/openvideo/src/studio/selection-manager.ts:60-75]()\n\n### Transport（播放传输）\n\nTransport 模块控制项目的播放状态，包括播放、暂停、停止和跳转等操作。它维护了当前播放头位置，并负责协调渲染引擎按照指定的时间点进行画面渲染。\n\nTransport 提供了精细的帧级控制能力，支持逐帧前进和后退。这对于精确编辑和对齐剪辑片段非常有帮助。时间单位统一使用微秒（microseconds），确保时间计算的精度。\n\n| 方法 | 描述 |\n|------|------|\n| `play()` | 开始播放 |\n| `pause()` | 暂停播放 |\n| `stop()` | 停止播放并重置到开始位置 |\n| `seek(time)` | 跳转到指定时间（微秒） |\n| `frameNext()` | 前进一帧 |\n| `framePrev()` | 后退一帧 |\n\n资料来源：[packages/openvideo/src/studio/transport.ts]()\n\n## 状态管理机制\n\n### 事件驱动架构\n\nStudio 继承自 EventEmitter，实现了完整的事件驱动架构。所有状态变更都通过事件进行传播，监听者可以订阅感兴趣的事件并做出响应。\n\n```mermaid\ngraph LR\n    A[状态变更] --> B[emit 事件]\n    B --> C[EventEmitter]\n    C --> D[进度监听器]\n    C --> E[完成监听器]\n    C --> F[错误监听器]\n    C --> G[重置监听器]\n```\n\nStudio 核心事件列表：\n\n| 事件名 | 回调参数 | 描述 |\n|--------|----------|------|\n| `progress` | `{ phase, progress, message }` | 渲染进度更新 |\n| `complete` | `outputPath` | 渲染完成 |\n| `error` | `Error` | 错误发生 |\n| `reset` | - | 项目重置/清空 |\n| `clip:dblclick` | `{ clip }` | 剪辑片段双击 |\n\n### 状态重置流程\n\n当调用 `clear()` 方法时，Studio 会执行完整的状态重置流程。这包括清空时间轴、销毁 PixiJS 纹理资源、清理过渡渲染器等。\n\n```typescript\nasync clear(): Promise<void> {\n    // 清空时间轴\n    await this.timeline.clear();\n\n    // 销毁过渡纹理\n    if (this.transFromTexture) {\n        this.transFromTexture.destroy(true);\n        this.transFromTexture = null;\n    }\n    if (this.transToTexture) {\n        this.transToTexture.destroy(true);\n        this.transToTexture = null;\n    }\n    \n    // 销毁过渡渲染器和精灵\n    this.transitionRenderers.forEach((r: any) => r.destroy());\n    this.transitionRenderers.clear();\n    this.transitionSprites.forEach((s) => s.destroy());\n    this.transitionSprites.clear();\n\n    this.emit(\"reset\");\n}\n```\n\n资料来源：[packages/openvideo/src/studio.ts:280-302]()\n\n## PixiJS 渲染集成\n\nStudio 与 PixiJS 紧密集成，利用其强大的 2D 渲染能力来显示和操作项目中的视觉元素。每个剪辑片段都被渲染为 PixiJS 的 Sprite（精灵）对象，支持缩放、旋转、透明度等变换操作。\n\n渲染管道的主要组件包括：\n\n- **SpriteRenderers**：负责将每个剪辑渲染为对应的 Sprite\n- **TransitionRenderers**：处理过渡效果的专用渲染器\n- **ActiveTransformer**：用户交互时的变换控制器\n- **Artboard**：画布容器，承载所有视觉元素\n\n渲染状态通过 `pixiApp.render()` 方法触发更新，确保画面与数据状态保持同步。\n\n## 使用示例\n\n### 基础使用\n\n```typescript\nimport { Studio } from 'openvideo';\n\n// 创建 Studio 实例\nconst studio = new Studio({\n    previewCanvas: document.getElementById('preview-canvas') as HTMLCanvasElement,\n    spacing: 20\n});\n\n// 添加剪辑\nconst video = await Video.fromUrl('https://example.com/video.mp4');\nawait studio.addClip(video);\n\n// 开始预览\nstudio.play();\n```\n\n### 进度跟踪\n\n```typescript\nstudio.on('progress', ({ phase, progress, message }) => {\n    console.log(`[${phase}] ${Math.round(progress * 100)}% - ${message}`);\n});\n\nstudio.on('complete', (outputPath) => {\n    console.log(`✅ 视频保存至: ${outputPath}`);\n});\n\nstudio.on('error', (error) => {\n    console.error('渲染失败:', error);\n});\n```\n\n## 相关文档\n\n- [Compositor 渲染引擎](../compositor/overview)\n- [剪辑片段系统](../clips/overview)\n- [过渡效果系统](../transitions/overview)\n- [JSON 序列化](../serialization/overview)\n\n---\n\n<a id='page-compositor'></a>\n\n## Compositor - 渲染引擎\n\n### 相关页面\n\n相关主题：[系统架构](#page-architecture), [Studio - 项目状态管理](#page-studio)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/node/src/template.html](https://github.com/openvideodev/openvideo/blob/main/packages/node/src/template.html)\n- [packages/openvideo/render.html](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/render.html)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/clips/caption-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/caption-clip.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n- [packages/openvideo/src/animation/presets.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/animation/presets.ts)\n- [packages/openvideo/src/transition/transition.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/transition/transition.ts)\n</details>\n\n# Compositor - 渲染引擎\n\n## 概述\n\nCompositor（合成器）是 OpenVideo 项目中的核心渲染引擎，负责视频的最终合成、编码和导出工作。它基于 WebCodecs API 实现硬件加速的视频编码，结合 PixiJS 进行 2D/3D 图形渲染，为开发者提供高性能的客户端视频渲染能力。\n\nCompositor 的核心职责包括：\n- 初始化 PixiJS 应用作为渲染画布\n- 接收来自 Studio 的视频帧数据进行合成\n- 使用 WebCodecs VideoEncoder 将帧编码为 MP4 格式\n- 管理音频轨道和音视频同步\n- 支持多种视频编码器和比特率配置\n\n资料来源：[packages/openvideo/render.html:42-60]()\n\n## 架构设计\n\n### 组件层级关系\n\nCompositor 在整个渲染管线中处于下游位置，接收来自 Studio 和各种 Clip（视频、文本、图像等）的渲染数据。\n\n```mermaid\ngraph TD\n    A[Studio 项目容器] --> B[Timeline 时间轴]\n    B --> C[Track 轨道]\n    C --> D[Clip 媒体片段]\n    \n    D --> E[VideoClip 视频片段]\n    D --> F[TextClip 文本片段]\n    D --> G[ImageClip 图像片段]\n    D --> H[CaptionClip 字幕片段]\n    D --> I[AudioClip 音频片段]\n    \n    E --> J[Compositor 渲染引擎]\n    F --> J\n    G --> J\n    H --> J\n    I --> J\n    \n    J --> K[PixiJS 渲染层]\n    J --> L[WebCodecs VideoEncoder]\n    J --> M[MP4 Muxer]\n    \n    K --> N[Canvas 画布渲染]\n    L --> O[Encoded Video Frames]\n    M --> P[output.mp4]\n```\n\n### 渲染流程\n\n```mermaid\nsequenceDiagram\n    participant User as 用户代码\n    participant Studio as Studio\n    participant Compositor as Compositor\n    participant PixiJS as PixiJS\n    participant Encoder as VideoEncoder\n    participant Muxer as MP4 Muxer\n\n    User->>Compositor: new Compositor(options)\n    Compositor->>PixiJS: initPixiApp()\n    PixiJS-->>Compositor: App initialized\n    \n    User->>Studio: addClip(clip)\n    Studio->>Compositor: 注册渲染任务\n    \n    User->>Compositor: 开始播放/render\n    Compositor->>PixiJS: 逐帧渲染\n    PixiJS-->>Compositor: VideoFrame\n    \n    Compositor->>Encoder: encode(frame)\n    Encoder-->>Compositor: EncodedChunk\n    \n    Compositor->>Muxer: addSample()\n    Muxer-->>Compositor: MP4 Container\n    \n    Compositor-->>User: 输出文件路径\n```\n\n## 初始化配置\n\n### 构造函数选项\n\n创建 Compositor 实例时需要传入配置对象，控制输出视频的基本参数。\n\n| 参数 | 类型 | 默认值 | 说明 |\n|------|------|--------|------|\n| `width` | `number` | `1280` | 输出视频宽度（像素） |\n| `height` | `number` | `720` | 输出视频高度（像素） |\n| `fps` | `number` | `30` | 输出帧率（fps） |\n| `bgColor` | `string` | `#000000` | 背景颜色（十六进制） |\n| `videoCodec` | `string` | - | 视频编码器标识符 |\n| `bitrate` | `number` | - | 视频比特率（bps） |\n| `audio` | `boolean` | `true` | 是否包含音频轨道 |\n| `metaDataTags` | `object` | - | MP4 元数据标签 |\n\n资料来源：[packages/openvideo/render.html:35-50]()\n\n### 初始化流程\n\n```typescript\n// 典型初始化代码\nconst compositorOpts = {\n  width: settings.width || 1280,\n  height: settings.height || 720,\n  fps: settings.fps || 30,\n  bgColor: settings.bgColor || '#000000',\n};\n\nif (settings.videoCodec) {\n  compositorOpts.videoCodec = settings.videoCodec;\n}\nif (settings.bitrate) {\n  compositorOpts.bitrate = settings.bitrate;\n}\nif (settings.audio === false) {\n  compositorOpts.audio = false;\n}\nif (settings.metaDataTags) {\n  compositorOpts.metaDataTags = settings.metaDataTags;\n}\n\nconst compositor = new Compositor(compositorOpts);\nawait compositor.initPixiApp();\n```\n\n资料来源：[packages/node/src/template.html:38-58]()\n\n## 事件系统\n\nCompositor 继承自 EventEmitter，提供了完善的事件机制用于监控渲染进度。\n\n### OutputProgress 事件\n\n用于追踪视频编码进度：\n\n```typescript\ncompositor.on('OutputProgress', (progress: {\n  progress: number;   // 0-1 之间的进度值\n  phase: string;      // 当前阶段\n  message?: string;   // 可选的状态消息\n}) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}%`);\n});\n```\n\n### 渲染阶段\n\n| 阶段标识 | 说明 |\n|---------|------|\n| `initializing` | 初始化阶段 |\n| `loading` | 加载资源阶段 |\n| `rendering` | 正在渲染阶段 |\n| `saving` | 保存文件阶段 |\n| `complete` | 完成阶段 |\n\n## 视频编码底层实现\n\n### MP4 样本处理\n\nCompositor 内部使用 MP4-box 库处理 MP4 容器格式，核心功能包括：\n\n1. **时间戳归一化**：将所有样本的时间戳归一化到以 0 为起点\n2. **轨道管理**：分别为视频和音频创建独立的 track\n3. **样本交织**：正确处理 DTS（解码时间戳）和 CTS（组合时间戳）\n\n```typescript\n// 时间戳归一化逻辑\nif (firstVDTS === null) {\n  firstVDTS = s.dts;\n  firstVCTS = s.cts;\n}\n// 归一化到从 0 开始，然后加上偏移\nnormalizedDTS = s.dts - firstVDTS!;\nnormalizedCTS = s.cts - (firstVCTS ?? 0);\n```\n\n资料来源：[packages/openvideo/src/mp4-utils/index.ts:45-65]()\n\n### 视频解码与降级\n\n对于缩略图生成等场景，Compositor 依赖的解码器支持硬件加速降级：\n\n```typescript\nfunction createVideoDec(downgrade = false) {\n  const encoderConf = {\n    ...decConf,\n    ...(downgrade ? { hardwareAcceleration: \"prefer-software\" } : {}),\n  } as VideoDecoderConfig;\n  // 首次尝试硬件加速，失败后降级到软件解码\n}\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:89-105]()\n\n## 渲染模式与动画支持\n\n### 动画预设\n\nCompositor 支持丰富的动画预设，通过 PixiJS 实现平滑过渡效果：\n\n| 动画类型 | 效果说明 |\n|---------|---------|\n| `fadeIn` | 淡入效果 |\n| `fadeOut` | 淡出效果 |\n| `slideIn` | 滑入效果（支持方向和距离配置） |\n| `slideOut` | 滑出效果 |\n| `pulse` | 脉冲效果 |\n| `blurIn` | 模糊淡入 |\n| `blurOut` | 模糊淡出 |\n\n```typescript\n// 滑出动画配置示例\ncase \"slideOut\": {\n  const direction = normalized?.direction || \"left\";\n  const distance = normalized?.distance || 300;\n  return {\n    \"0%\": { x: xPositionInit ?? 0, opacity: opacityInit ?? 1 },\n    \"100%\": {\n      x: direction === \"left\" ? -distance : distance,\n      opacity: opacityEnd ?? 0,\n    },\n  };\n}\n```\n\n资料来源：[packages/openvideo/src/animation/presets.ts:45-70]()\n\n### 转场效果\n\nCompositor 支持多种转场效果，通过 GLSL Shader 实现：\n\n| 转场名称 | 类型标识 | 说明 |\n|---------|---------|------|\n| `GridFlip` | `gridflip` | 网格翻转 |\n| `CircleOpen` | `circleopen` | 圆形展开 |\n| `Directional` | `directional` | 方向性渐变 |\n| `UndulatingBurnOut` | `undulatingburnout` | 波浪燃烧 |\n| `SquaresWire` | `squareswire` | 方块线条 |\n| `RotateScaleFade` | `rotatescalefade` | 旋转缩放淡入淡出 |\n| `PolkaDotsCurtain` | `polkadotscurtain` | 圆点幕布 |\n| `Pixelize` | `pixelize` | 像素化 |\n| `Heart` | `heart` | 心形效果 |\n| `Displacement` | `displacement` | 置换效果 |\n| `DirectionalWipe` | `directionalwipe` | 方向性擦除 |\n| `Crosshatch` | `crosshatch` | 十字阴影 |\n\n```typescript\nif (transitionCircleOpen) {\n  transitionGlsl = CIRCLE_FRAGMENT;\n  transitionUniforms = {\n    ...uniforms.basics,\n    ...CIRCLEOPEN_UNIFORMS,\n  };\n}\n```\n\n资料来源：[packages/openvideo/src/transition/transition.ts:35-50]()\n\n## 文本渲染\n\nCompositor 通过 TextClip 支持丰富的文本样式配置：\n\n| 样式属性 | 类型 | 说明 |\n|---------|------|------|\n| `fontSize` | `number` | 字体大小 |\n| `fontFamily` | `string` | 字体系列 |\n| `fontWeight` | `string\\|number` | 字重 |\n| `fontStyle` | `string` | 字体样式（normal/italic） |\n| `fill` | `string\\|number` | 填充颜色 |\n| `align` | `string` | 文本对齐 |\n| `wordWrap` | `boolean` | 是否自动换行 |\n| `wordWrapWidth` | `number` | 换行宽度 |\n| `lineHeight` | `number` | 行高 |\n| `letterSpacing` | `number` | 字间距 |\n| `stroke` | `object` | 描边配置 |\n| `dropShadow` | `object` | 阴影配置 |\n\n```typescript\nif (this.originalOpts.stroke) {\n  if (typeof this.originalOpts.stroke === 'object') {\n    style.stroke = {\n      color: this.originalOpts.stroke.color,\n      width: this.originalOpts.stroke.width,\n      join: this.originalOpts.stroke.join,\n      cap: this.originalOpts.stroke.cap,\n      miterLimit: this.originalOpts.stroke.miterLimit,\n    };\n  }\n}\n```\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:85-105]()\n\n## 字幕支持\n\nCaptionClip 提供专业的字幕渲染功能，支持动态颜色变化和词动画：\n\n```typescript\n// 字幕颜色状态配置\nif (processedOpts.caption?.colors?.appeared !== undefined)\n  this.opts.appeared = processedOpts.caption.colors.appeared;\nif (processedOpts.caption?.colors?.active !== undefined)\n  this.opts.active = processedOpts.caption.colors.active;\nif (processedOpts.caption?.colors?.keyword !== undefined)\n  this.opts.keyword = processedOpts.caption.colors.keyword;\n```\n\n支持的功能包括：\n- 渐变色填充文本\n- 关键词高亮颜色保持\n- 单词级动画效果\n- 背景色和描边样式\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:50-75]()\n\n## 使用示例\n\n### 基础渲染流程\n\n```typescript\nimport { Compositor } from 'openvideo';\n\nasync function renderVideo() {\n  const compositor = new Compositor({\n    width: 1920,\n    height: 1080,\n    fps: 30,\n    bgColor: '#000000',\n    bitrate: 5_000_000,\n  });\n\n  await compositor.initPixiApp();\n\n  compositor.on('OutputProgress', (progress) => {\n    console.log(`[${progress.phase}] ${Math.round(progress.progress * 100)}%`);\n  });\n\n  // 添加片段并触发渲染...\n}\n```\n\n### 与 Renderer 集成\n\n在 Node.js 环境下，通常使用 Renderer 类包装 Compositor：\n\n```typescript\nimport { Renderer } from '@combo/node';\n\nconst renderer = new Renderer({\n  json: videoConfig,\n  outputPath: './output.mp4',\n});\n\nrenderer.on('progress', ({ phase, progress, message }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}% - ${message}`);\n});\n\nawait renderer.render();\nconsole.log('视频渲染完成！');\n```\n\n资料来源：[packages/node/README.md:90-120]()\n\n## 总结\n\nCompositor 是 OpenVideo 项目的核心渲染引擎，通过整合 WebCodecs 和 PixiJS 两大技术栈，为开发者提供了：\n\n- **高性能编码**：利用浏览器原生 WebCodecs API 实现硬件加速视频编码\n- **灵活配置**：支持多种分辨率、帧率、编码器和比特率组合\n- **丰富视觉效果**：内置大量动画预设和转场效果\n- **完善的事件系统**：实时反馈渲染进度，便于构建用户界面\n- **跨平台兼容**：基于 Web 标准，可在桌面和移动浏览器中运行\n\nCompositor 的设计遵循模块化原则，与上层的 Studio、Clip 系统松耦合，同时通过标准化的事件机制保证各组件间的有效通信。\n\n---\n\n<a id='page-clips'></a>\n\n## 剪辑系统\n\n### 相关页面\n\n相关主题：[视频与音频剪辑](#page-video-clip), [文字与字幕剪辑](#page-text-caption)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/clips/iclip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/iclip.ts)\n- [packages/openvideo/src/clips/base-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/base-clip.ts)\n- [packages/openvideo/src/clips/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/index.ts)\n- [packages/openvideo/src/clips/effect-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/effect-clip.ts)\n- [packages/openvideo/src/clips/transition-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/transition-clip.ts)\n</details>\n\n# 剪辑系统\n\n## 概述\n\n剪辑系统（Clip System）是 OpenVideo 项目的核心模块之一，负责管理和处理各种类型的媒体资源。该系统采用面向对象的设计思想，通过统一的接口定义和继承体系，支持视频、音频、文本、图像、字幕等多种媒体类型的剪辑操作。\n\n剪辑系统的设计目标是为开发者提供一个灵活、可扩展的媒体处理框架，使得创建复杂的视频编辑功能变得简单直观。系统通过抽象基类和接口定义，确保了不同类型剪辑之间的一致性，同时允许各类型保留其特有的属性和行为。\n\n## 架构设计\n\n### 类层次结构\n\n剪辑系统采用经典的继承层次结构，从顶层到底层依次为：接口层（IClip）、抽象基类层（BaseClip）、具体实现类层。每一层都有明确的职责划分，下层继承并扩展上层的功能。\n\n```mermaid\ngraph TD\n    A[IClip 接口] --> B[BaseClip 抽象基类]\n    B --> C[VideoClip 视频剪辑]\n    B --> D[AudioClip 音频剪辑]\n    B --> E[TextClip 文本剪辑]\n    B --> F[ImageClip 图像剪辑]\n    B --> G[CaptionClip 字幕剪辑]\n    B --> H[EffectClip 特效剪辑]\n    B --> I[TransitionClip 过渡剪辑]\n    \n    C --> C1[fromUrl 静态方法]\n    C --> C2[本地文件处理]\n    \n    H --> H1[内置特效]\n    H --> H2[自定义特效]\n    \n    I --> I1[过渡效果名称匹配]\n    I --> I2[GLSL着色器实现]\n```\n\n### 核心接口 IClip\n\nIClip 接口是整个剪辑系统的契约定义，所有剪辑类型都必须实现该接口规定的方法和属性。该接口定义了剪辑的基本行为规范，包括时间定位、状态管理、事件处理等核心功能。通过实现 IClip 接口，不同类型的剪辑可以在统一的方式下被 Studio 系统管理和调度。\n\n接口的设计遵循了最小化原则，仅包含最核心的方法签名，具体实现细节由各个子类自行决定。这种设计使得系统具有高度的灵活性，同时保持了接口的一致性和可预测性。\n\n### 抽象基类 BaseClip\n\nBaseClip 提供了所有剪辑类型的共同实现，是系统的核心基类。该类封装了剪辑共有的属性和方法，包括时间轴控制、位置尺寸设置、样式配置等通用功能。子类通过继承 BaseClip 自动获得这些基础能力，只需关注其特有的业务逻辑。\n\nBaseClip 的设计体现了代码复用原则，避免了子类之间的重复代码。同时，该基类预留了大量可扩展的钩子方法，允许子类在特定生命周期节点插入自定义逻辑。\n\n## 剪辑类型详解\n\n### 视频剪辑 VideoClip\n\n视频剪辑是系统中最重要的剪辑类型之一，负责处理视频媒体资源。该类型支持从网络 URL 创建实例，并自动下载和管理本地文件。VideoClip 提供了灵活的音视频控制选项，开发者可以独立控制音频的开关和音量大小。\n\n```typescript\n// 视频剪辑创建示例\nconst video = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 100,\n  y: 200,\n  width: 1280,\n  height: 720\n});\nstudio.addClip(video);\n```\n\n视频剪辑支持从 OPFS（Origin Private File System）文件、ReadableStream 或已存在的视频样本数据三种方式创建实例。这种多源支持的设计使得系统可以灵活应对不同的视频数据来源，无论是实时流、本地文件还是内存中的视频数据都能得到妥善处理。\n\n| 属性/方法 | 类型 | 说明 |\n|-----------|------|------|\n| fromUrl | 静态方法 | 从网络 URL 创建视频剪辑 |\n| src | string | 视频源路径 |\n| audio | boolean | 是否包含音频轨道 |\n| volume | number | 音量大小（0-1） |\n| localFile | OPFSToolFile | 本地缓存文件引用 |\n\n### 文本剪辑 TextClip\n\n文本剪辑用于在视频中添加文字内容。该类型支持丰富的样式配置，包括字体、字号、颜色、对齐方式、字间距、行高等属性。文本剪辑还支持文字换行功能，通过 wordWrapWidth 属性可以控制文字的最大宽度。\n\n文本剪辑的一个重要特性是支持文字描边（stroke）和投影（dropShadow）效果。描边可以通过颜色和宽度进行自定义配置，而投影效果则支持颜色、透明度、模糊度、距离和角度等多个参数的自由组合。\n\n### 字幕剪辑 CaptionClip\n\n字幕剪辑是专门为视频字幕场景设计的类型，它在 TextClip 的基础上增加了逐词高亮显示的动画功能。该类型支持词汇级别的颜色控制，可以为已显示词汇、当前活跃词汇、关键词等分别设置不同的颜色方案。\n\n| 颜色配置项 | 说明 |\n|-----------|------|\n| appeared | 已显示完成的词汇颜色 |\n| active | 当前正在播放的词汇颜色 |\n| activeFill | 当前词汇的填充颜色 |\n| background | 背景高亮颜色 |\n| keyword | 关键词颜色 |\n\n字幕剪辑还支持逐词动画效果（wordAnimation），可以为每个词汇的显示配置不同的动画样式。这种精细的控制能力使得字幕展示可以达到接近专业视频编辑软件的动态效果。\n\n### 特效剪辑 EffectClip\n\n特效剪辑用于在视频轨道上添加视觉特效。该类型支持多种内置特效，包括常见的淡入淡出、滑动、脉冲等预设动画。特效剪辑的设计允许开发者通过简单的配置参数快速应用复杂的视觉效果。\n\n```typescript\n// 预设特效配置示例\nconst presetAnimation = {\n  preset: \"blurIn\",\n  params: {\n    blurInit: 20,\n    blurEnd: 0,\n    opacityInit: 0,\n    opacityEnd: 1\n  }\n};\n```\n\n特效剪辑还支持多个方向的配置选项，包括左、右、上、下四个方向，以及不同的距离参数。这种灵活性使得特效的展示方式可以根据具体需求进行精确调整。\n\n### 过渡剪辑 TransitionClip\n\n过渡剪辑用于实现两个剪辑之间的切换效果。系统支持多种过渡类型，包括网格翻转、圆形展开、方向擦拭、不规则燃烧等多种视觉效果。过渡剪辑通过名称匹配机制识别所需的过渡效果，支持多种命名变体的识别。\n\n```mermaid\ngraph LR\n    A[剪辑 A] --> B[TransitionClip]\n    C[剪辑 B] --> B\n    B --> D[过渡效果输出]\n    \n    B --> E[名称匹配]\n    B --> F[GLSL 着色器]\n    B --> G[Uniform 参数]\n```\n\n过渡效果的实现依赖于 WebGL 着色器（Fragment Shader），每个过渡效果都有对应的 GLSL 代码和 Uniform 参数定义。这种基于着色器的实现方式确保了过渡效果的高性能和硬件加速支持。\n\n## 状态管理\n\n### 生命周期状态\n\n剪辑对象在运行时有多个生命周期状态，系统通过精细的状态转换机制确保对象在正确的时间执行相应的操作。状态转换遵循严格的规则，不允许跳跃式状态变更。\n\n```mermaid\nstateDiagram-v2\n    [*] --> 创建中: 构造函数\n    创建中 --> 已就绪: 初始化完成\n    已就绪 --> 播放中: play()\n    播放中 --> 已暂停: pause()\n    已暂停 --> 播放中: play()\n    播放中 --> 已结束: 时间到达终点\n    已结束 --> [*]: 销毁\n    已就绪 --> [*]: 销毁\n```\n\n### 事件系统\n\n剪辑系统使用事件发射器模式进行状态通知。主要事件包括进度事件（OutputProgress）、错误事件（error）和完成事件（complete）。开发者可以通过监听这些事件来跟踪剪辑的渲染进度或处理异常情况。\n\n```typescript\n// 事件监听示例\nclip.on('progress', ({ phase, progress, message }) => {\n  console.log(`[${phase}] ${Math.round(progress * 100)}% - ${message}`);\n});\n\nclip.on('error', (error) => {\n  console.error('处理失败:', error);\n});\n\nclip.on('complete', () => {\n  console.log('剪辑处理完成');\n});\n```\n\n## 渲染流程\n\n### 渲染阶段划分\n\n视频渲染过程分为多个阶段，每个阶段都有明确的职责和输出：\n\n| 阶段名称 | 说明 | 典型耗时 |\n|---------|------|---------|\n| initializing | 初始化渲染器 | 1-5秒 |\n| loading | 加载媒体资源 | 取决于网络 |\n| rendering | 执行渲染计算 | 取决于视频时长 |\n| saving | 保存输出文件 | 取决于文件大小 |\n| complete | 渲染完成 | - |\n\n### 渲染配置选项\n\nCompositor 是实际执行渲染的核心类，它接收多种配置参数来控制输出视频的属性：\n\n```typescript\nconst compositorOpts = {\n  width: 1280,           // 输出宽度\n  height: 720,          // 输出高度\n  fps: 30,              // 帧率\n  bgColor: '#000000',    // 背景颜色\n  videoCodec: 'avc1.640028',  // 视频编码器\n  bitrate: 5000000,      // 比特率\n  audio: true,           // 是否包含音频\n  metaDataTags: {        // 元数据标签\n    title: 'My Video',\n    author: 'Creator'\n  }\n};\n```\n\n## 样式配置系统\n\n### 文字样式\n\n文字样式的配置采用分层设计，从基类继承通用样式属性，同时允许子类添加特定样式选项。主要的文字样式属性包括：\n\n- fontFamily：字体家族\n- fontSize：字号大小\n- fontWeight：字重粗细\n- fontStyle：斜体/正常\n- fill：填充颜色\n- align：对齐方式\n- letterSpacing：字间距\n- lineHeight：行高\n- wordWrap：自动换行\n- wordWrapWidth：换行宽度\n\n### 颜色系统\n\n系统支持多种颜色表示方式，包括十六进制颜色代码和数字格式。在字幕剪辑中，颜色配置被组织为嵌套结构，支持默认颜色、活跃颜色、背景颜色等多个维度的独立控制。\n\n### 渐变填充\n\n文本填充除了支持纯色外，还支持渐变色填充。渐变通过起点坐标（x0, y0）和终点坐标（x1, y1）定义方向，通过颜色数组和对应的比例值定义渐变色分布。\n\n## 与 Studio 的集成\n\n### 添加和移除剪辑\n\nStudio 类提供了 addClip 和 removeClip 方法用于管理项目中的剪辑。添加的剪辑会被自动编排到时间轴上，并根据其时间属性决定播放顺序。\n\n```typescript\n// 剪辑添加示例\nconst text = new Text(\"Hello World\");\ntext.duration = 5e6;  // 5秒（微秒单位）\nawait studio.addClip(text);\n\n// 移除剪辑\nawait studio.removeClip(text.id);\n```\n\n### 时间轴控制\n\nStudio 负责管理整个项目的时间轴配置，包括总时长、帧率等参数。每个添加到 Studio 的剪辑都会继承项目级的时间轴设置，同时保留覆盖这些设置的能力。\n\n## 扩展机制\n\n### 自定义特效\n\n系统提供了扩展接口允许开发者添加自定义特效。通过实现 EffectClip 的扩展接口，可以注册新的预设动画效果，这些效果会自动出现在可用的特效列表中。\n\n### 自定义过渡\n\n类似地，开发者可以通过扩展 TransitionClip 添加新的过渡效果。新的过渡效果需要提供对应的 GLSL 着色器代码和 Uniform 参数定义，完成注册后即可通过名称在项目中使用。\n\n## 总结\n\n剪辑系统是 OpenVideo 项目的基础模块，通过精心设计的类层次结构和接口规范，实现了多类型媒体的统一管理。该系统提供了从基础的视频、音频剪辑到高级的字幕、特效、过渡等多种功能，覆盖了视频编辑的核心需求。\n\n系统的架构设计充分考虑了扩展性和性能要求，通过基于 WebCodecs 和 WebGL 的底层实现，确保了视频处理的效率和跨平台兼容性。事件驱动的设计模式使得渲染进度的监控和错误处理变得简单可靠。\n\n---\n\n<a id='page-video-clip'></a>\n\n## 视频与音频剪辑\n\n### 相关页面\n\n相关主题：[剪辑系统](#page-clips), [Compositor - 渲染引擎](#page-compositor)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/clips/audio-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/audio-clip.ts)\n- [packages/openvideo/src/clips/image-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/image-clip.ts)\n- [packages/openvideo/src/json-serialization.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/json-serialization.ts)\n- [packages/openvideo/src/mp4-utils/index.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/mp4-utils/index.ts)\n</details>\n\n# 视频与音频剪辑\n\n## 概述\n\n视频与音频剪辑是 openvideo 项目的核心功能模块，负责管理和处理各类媒体资源。该模块基于 WebCodecs API 实现硬件加速的视频解码与编码，支持从远程 URL 或本地文件系统加载媒体文件，并通过 PixiJS 渲染引擎实现高性能的 2D/3D 合成。\n\n剪辑系统采用面向对象的设计模式，定义了统一的 `BaseClip` 基类，所有具体剪辑类型（如 Video、Audio、Image、Text、Caption）都继承自该基类。这种设计确保了统一的接口规范和一致的渲染行为。\n\n## 核心类架构\n\n### 类继承体系\n\n```mermaid\ngraph TD\n    A[IClip 接口] --> B[BaseClip]\n    B --> C[Video]\n    B --> D[Audio]\n    B --> E[Image]\n    B --> F[Text]\n    B --> G[Caption]\n    B --> H[Placeholder]\n    \n    C -.->|实现| I[IPlaybackCapable]\n    \n    J[Compositor] --> K[渲染引擎]\n    C --> K\n    D --> K\n    E --> K\n    F --> K\n    G --> K\n```\n\n### 主要类说明\n\n| 类名 | 职责 | 源码位置 |\n|------|------|----------|\n| `Video` | 视频解码、帧提取、缩略图生成 | `video-clip.ts:1-100` |\n| `Audio` | 音频解码、音量控制 | `audio-clip.ts` |\n| `Image` | 静态图像加载与渲染 | `image-clip.ts` |\n| `Text` | 文本渲染与排版 | `text-clip.ts` |\n| `Caption` | 字幕样式与动画 | `caption-clip.ts` |\n\n## Video 剪辑详解\n\n### 基本用法\n\n`Video` 类是视频处理的核心组件，支持从 URL 异步加载 MP4 文件，并提供精确的帧级控制。\n\n```typescript\n// 从 URL 加载视频\nconst videoClip = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 0,\n  y: 0,\n  width: 1920,\n  height: 1080,\n});\n\n// 设置时间轴位置\nvideoClip.set({\n  display: {\n    from: 150,  // 起始帧\n    to: 450,    // 结束帧（30fps 下为 10 秒）\n  },\n});\n```\n\n### 构造函数参数\n\n```typescript\nconstructor(\n  source: OPFSToolFile | ReadableStream<Uint8Array> | MPClipCloneArgs,\n  opts: IMP4ClipOpts = {},\n  src?: string,\n)\n```\n\n| 参数 | 类型 | 说明 | 默认值 |\n|------|------|------|--------|\n| `source` | `OPFSToolFile \\| ReadableStream \\| MPClipCloneArgs` | 视频数据源 | 必需 |\n| `opts` | `IMP4ClipOpts` | 配置选项 | `{}` |\n| `src` | `string` | 视频源 URL | `\"\"` |\n\n### 配置选项 (IMP4ClipOpts)\n\n```typescript\ninterface IMP4ClipOpts {\n  audio?: boolean | { volume: number };\n  __unsafe_hardwareAcceleration__?: HardwarePreference;\n}\n```\n\n| 选项 | 类型 | 说明 |\n|------|------|------|\n| `audio` | `boolean \\| { volume: number }` | 音频开关或音量配置（0-1） |\n| `__unsafe_hardwareAcceleration__` | `HardwarePreference` | 硬件加速偏好设置 |\n\n资料来源：[video-clip.ts:50-70]()\n\n### 核心属性\n\n| 属性 | 类型 | 说明 |\n|------|------|------|\n| `type` | `\"Video\"` | 剪辑类型标识 |\n| `src` | `string` | 视频源 URL |\n| `audio` | `boolean` | 是否启用音频 |\n| `volume` | `number` | 音频音量（0-1） |\n| `ready` | `Promise<void>` | 加载完成状态 |\n| `_meta` | `object` | 元数据（duration, width, height） |\n\n### 帧数据处理流程\n\n```mermaid\nsequenceDiagram\n    participant User as 用户\n    participant Video as Video 类\n    participant ResourceManager as ResourceManager\n    participant Compositor as Compositor\n    \n    User->>Video: fromUrl(url)\n    Video->>ResourceManager: getReadableStream(url)\n    ResourceManager-->>Video: ReadableStream\n    Video->>Video: write(localFile, stream)\n    Video->>Video: await ready\n    Video->>Compositor: 渲染帧\n    Compositor-->>User: 显示视频\n```\n\n视频帧数据经过以下处理流程：\n\n1. **加载阶段**：通过 `ResourceManager.getReadableStream()` 获取可读流\n2. **存储阶段**：写入本地 OPFS 文件系统\n3. **解码阶段**：使用 WebCodecs VideoDecoder 进行 MP4 解析\n4. **渲染阶段**：通过 Compositor 和 PixiJS 渲染到画布\n\n资料来源：[mp4-utils/index.ts:20-60]()\n\n## Audio 剪辑\n\n### 音频配置\n\n音频剪辑支持灵活的音量控制和播放参数：\n\n```typescript\n// 启用音频\nconst video = await Video.fromUrl('video.mp4', {\n  audio: true,\n});\n\n// 音量控制\nconst videoWithVolume = await Video.fromUrl('video.mp4', {\n  audio: {\n    volume: 0.5,  // 50% 音量\n  },\n});\n\n// 禁用音频\nconst videoNoAudio = await Video.fromUrl('video.mp4', {\n  audio: false,\n});\n```\n\n音频参数处理逻辑如下：\n\n```typescript\nthis.audio = typeof this.opts.audio === \"boolean\" \n  ? this.opts.audio \n  : true;\n\nthis.volume = typeof opts.audio === \"object\" && \"volume\" in opts.audio\n  ? opts.audio.volume\n  : ((opts as any).volume ?? 1);\n```\n\n资料来源：[video-clip.ts:75-90]()\n\n## Image 剪辑\n\n### 图像加载\n\n`Image` 类支持从 URL 或 data URI 加载静态图像：\n\n```typescript\n// 从 URL 加载\nconst image = await ImageClip.fromUrl('https://example.com/image.png');\n\n// 设置位置和尺寸\nconst imageWithOpts = await ImageClip.fromUrl('image.png', {\n  x: 100,\n  y: 200,\n  width: 800,\n  height: 600,\n});\n```\n\n### 支持的图像格式\n\n| 格式 | MIME 类型 | 支持情况 |\n|------|-----------|----------|\n| PNG | `image/png` | 完全支持 |\n| JPEG | `image/jpeg` | 完全支持 |\n| WebP | `image/webp` | 完全支持 |\n| SVG | `image/svg+xml` | 需测试 |\n| Base64 | data URI | 完全支持 |\n\n## 剪辑通用属性\n\n所有剪辑类型共享以下核心属性：\n\n| 属性 | 类型 | 说明 | 适用剪辑 |\n|------|------|------|----------|\n| `id` | `string` | 唯一标识 | 全部 |\n| `src` | `string` | 资源路径 | Video, Audio, Image |\n| `left` | `number` | X 坐标 | 全部 |\n| `top` | `number` | Y 坐标 | 全部 |\n| `width` | `number` | 宽度 | 全部 |\n| `height` | `number` | 高度 | 全部 |\n| `angle` | `number` | 旋转角度 | 全部 |\n| `zIndex` | `number` | 层级 | 全部 |\n| `opacity` | `number` | 透明度 | 全部 |\n| `flip` | `\"horizontal\" \\| \"vertical\" \\| null` | 翻转方向 | 全部 |\n| `duration` | `number` | 时长（微秒） | 全部 |\n| `playbackRate` | `number` | 播放速率 | 全部 |\n\n资料来源：[json-serialization.ts:15-50]()\n\n## 时间轴与显示配置\n\n### display 属性\n\n```typescript\ndisplay: {\n  from: number;  // 起始帧\n  to: number;    // 结束帧\n};\n```\n\n```typescript\n// 设置 5 秒时长的剪辑\ntext.duration = 5e6;  // 5000000 微秒\n```\n\n### trim 属性（可选）\n\n```typescript\ntrim?: {\n  from: number;  // 裁剪起始点\n  to: number;    // 裁剪结束点\n};\n```\n\n## 特效与动画\n\n### 特效配置\n\n```typescript\neffects?: Array<{\n  id: string;\n  key: string;\n  startTime: number;\n  duration: number;\n  targets?: number[];\n}>;\n```\n\n### 动画配置\n\n```typescript\nanimation?: {\n  keyFrames: Record<string, Partial<{\n    x: number;\n    y: number;\n    w: number;\n    h: number;\n    angle: number;\n    opacity: number;\n  }>>;\n  opts: {\n    duration: number;\n    delay?: number;\n    iterCount?: number;\n  };\n};\n```\n\n资料来源：[json-serialization.ts:50-75]()\n\n## JSON 序列化\n\n### BaseClipJSON 接口\n\n```typescript\ninterface BaseClipJSON {\n  id?: string;\n  name?: string;\n  metadata?: Record<string, any>;\n  effects?: Array<{...}>;\n  src: string;\n  display: {\n    from: number;\n    to: number;\n  };\n  playbackRate: number;\n  duration: number;\n  left: number;\n  top: number;\n  width: number;\n  height: number;\n  angle: number;\n  zIndex: number;\n  opacity: number;\n  flip: \"horizontal\" | \"vertical\" | null;\n  trim?: { from: number; to: number };\n  transition?: ITransitionInfo;\n  style?: any;\n  locked?: boolean;\n  colorAdjustment?: ColorAdjustment;\n  animation?: {...};\n  animations?: Array<{...}>;\n}\n```\n\n### 导出示例\n\n```typescript\nimport { JsonSerialization } from 'openvideo';\n\nconst projectJson = JsonSerialization.toJSON(studio);\nconsole.log(JSON.stringify(projectJson, null, 2));\n```\n\n## 在 Studio 中使用剪辑\n\n### 添加剪辑到时间轴\n\n```typescript\nconst studio = new Studio({\n  canvas: document.getElementById('canvas'),\n  width: 1920,\n  height: 1080,\n});\n\nawait studio.ready;\n\n// 添加视频剪辑\nconst video = await Video.fromUrl('video.mp4');\nawait studio.addClip(video);\n\n// 添加图像剪辑\nconst image = await ImageClip.fromUrl('image.png');\nawait studio.addClip(image);\n```\n\n### 移除剪辑\n\n```typescript\nawait studio.removeClip(video.id);\n```\n\n### 替换剪辑\n\n```typescript\nawait studio.timeline.replaceClipsBySource(\n  'old-video.mp4',\n  async (oldClip) => {\n    return await Video.fromUrl('new-video.mp4');\n  }\n);\n```\n\n资料来源：[studio.spec.ts:30-60]()\n\n## 工作流程图\n\n```mermaid\ngraph LR\n    A[加载媒体] --> B[解析 MP4/图像]\n    B --> C[创建 Clip 实例]\n    C --> D[添加到 Studio]\n    D --> E[配置 Timeline]\n    E --> F[Compositor 渲染]\n    F --> G[输出视频]\n    \n    H[JSON 序列化] -.-> C\n    I[反序列化] -.-> C\n```\n\n## 最佳实践\n\n### 1. 异步加载\n\n始终使用 `await` 等待资源加载完成：\n\n```typescript\nconst video = await Video.fromUrl('video.mp4');\nawait studio.addClip(video);\nawait studio.ready;\n```\n\n### 2. 资源清理\n\n使用完剪辑后及时销毁释放内存：\n\n```typescript\nvideo.destroy();\nstudio.destroy();\n```\n\n### 3. 缩略图生成\n\n使用 `ThumbnailOpts` 生成视频缩略图：\n\n```typescript\nconst thumbnails = await video.getThumbnails({\n  start: 0,\n  end: video.duration,\n  step: 300,  // 每 10 秒一帧（30fps）\n});\n```\n\n### 4. 批量替换\n\n使用 `replaceClipsBySource` 进行批量替换：\n\n```typescript\nawait studio.timeline.replaceClipsBySource(\n  'old.mp4',\n  async (oldClip) => Video.fromUrl('new.mp4')\n);\n```\n\n## 总结\n\nopenvideo 的视频与音频剪辑模块提供了完整的媒体处理能力，支持从 URL 加载各类媒体资源，并通过统一的接口规范实现灵活的剪辑管理。开发者可以通过继承 `BaseClip` 创建自定义剪辑类型，通过 Compositor 实现高性能渲染，并通过 JSON 序列化实现项目持久化存储。该模块充分利用 WebCodecs API 和 PixiJS 渲染引擎，为 Web 环境下的专业视频编辑提供了坚实的技术基础。\n\n---\n\n<a id='page-text-caption'></a>\n\n## 文字与字幕剪辑\n\n### 相关页面\n\n相关主题：[剪辑系统](#page-clips)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/clips/text-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/text-clip.ts)\n- [packages/openvideo/src/clips/caption-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/caption-clip.ts)\n- [packages/openvideo/src/utils/fonts.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/fonts.ts)\n- [packages/openvideo/src/utils/srt-parser.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/srt-parser.ts)\n- [packages/openvideo/src/studio/timeline-model.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/timeline-model.ts)\n- [packages/openvideo/src/animation/presets.ts](https://github.com/openvideov/openvideo/blob/main/packages/openvideo/src/animation/presets.ts)\n</details>\n\n# 文字与字幕剪辑\n\n## 概述\n\n文字与字幕剪辑是 OpenVideo 视频编辑器中的核心功能模块，负责处理视频中的文字渲染和字幕显示。该模块包含两个主要组件：**TextClip（文字剪辑）** 和 **CaptionClip（字幕剪辑）**，它们共享底层的 PixiJS 渲染引擎，但面向不同的使用场景。\n\n**TextClip** 适用于静态或动态文字叠加，如标题、水印、动态文字效果；**CaptionClip** 则专注于字幕功能，支持逐字高亮、词动画、SRT 格式解析等高级特性。\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:1-50]()\n\n## 架构设计\n\n### 组件关系图\n\n```mermaid\ngraph TD\n    A[Studio] --> B[TextClip]\n    A --> C[CaptionClip]\n    B --> D[SplitBitmapText]\n    C --> E[Word-Level Animation]\n    B --> F[PixiJS Container]\n    C --> F\n    D --> G[CanvasTextMetrics]\n    F --> H[PixiJS Renderer]\n    I[SRT Parser] --> C\n    J[FontManager] --> B\n    J --> C\n```\n\n### 核心职责划分\n\n| 组件 | 职责 | 继承关系 |\n|------|------|----------|\n| `TextClip` | 基础文字渲染，支持 stroke、shadow、wordWrap | ClipBase |\n| `CaptionClip` | 字幕渲染，支持逐词动画、颜色状态 | ClipBase |\n| `SplitBitmapText` | 文字分词渲染单元 | PIXI.Text |\n| `FontManager` | 字体加载与管理 | - |\n| `SRTParser` | SRT 字幕格式解析 | - |\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:1-30]()\n\n## TextClip 文字剪辑\n\n### 功能特性\n\nTextClip 提供了丰富的文字渲染能力，支持以下特性：\n\n- **字体样式**：fontFamily、fontSize、fontWeight、fontStyle\n- **文本装饰**：stroke（描边）、dropShadow（阴影）\n- **布局控制**：align、wordWrap、wordWrapWidth、lineHeight、letterSpacing\n- **颜色填充**：支持纯色和渐变填充\n- **文字分词**：将文本拆分为独立的单词进行渲染\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:100-180]()\n\n### 渲染流程\n\n```mermaid\nsequenceDiagram\n    participant User as 用户\n    participant TextClip as TextClip\n    participant Container as PixiJS Container\n    participant WordTexts as SplitBitmapText[]\n    \n    User->>TextClip: 设置文本内容\n    TextClip->>TextClip: 解析样式选项\n    TextClip->>TextClip: 拆分单词数组\n    TextClip->>TextClip: 计算行布局\n    TextClip->>Container: 创建/更新容器\n    Loop 每个单词\n        TextClip->>WordTexts: 创建 SplitBitmapText\n        Container->>WordTexts: 添加到容器\n    end\n    TextClip->>Container: 应用变换和动画\n```\n\n### 样式配置\n\nTextClip 支持从多种来源读取样式配置，包括剪辑自身的选项和外部传入的样式对象：\n\n```typescript\ninterface ITextOpts {\n  // 基础样式\n  text?: string;\n  fontFamily?: string;\n  fontSize?: number;\n  fontWeight?: string | number;\n  fontStyle?: 'normal' | 'italic';\n  fill?: number | string | FillGradient;\n  \n  // 布局\n  align?: 'left' | 'center' | 'right';\n  wordWrap?: boolean;\n  wordWrapWidth?: number;\n  lineHeight?: number;\n  letterSpacing?: number;\n  \n  // 装饰\n  stroke?: string | { color: string; width: number; join?: string; cap?: string; miterLimit?: number };\n  strokeWidth?: number;\n  dropShadow?: {\n    color?: string;\n    alpha?: number;\n    blur?: number;\n    distance?: number;\n    angle?: number;\n  };\n  \n  // 垂直对齐\n  verticalAlign?: 'top' | 'middle' | 'bottom';\n}\n```\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:80-150]()\n\n### 文本布局算法\n\nTextClip 使用智能换行算法来计算文字布局：\n\n1. **空格宽度计算**：使用 CanvasTextMetrics 和 SplitBitmapText 两种方式计算空格宽度，取较大值\n2. **换行宽度判断**：根据 wordWrapWidth 确定是否需要换行\n3. **行分配**：将单词依次分配到各行，计算每行的总宽度和高度\n4. **垂直对齐处理**：根据 verticalAlign 调整行在容器中的位置\n\n```typescript\n// 行宽计算逻辑\nconst wrapWidth = style.wordWrap && style.wordWrapWidth > 0 \n  ? style.wordWrapWidth \n  : 1e5;\n\nconst lines: { words: SplitBitmapText[]; width: number; height: number }[] = [];\nlet currentLineWords: SplitBitmapText[] = [];\nlet currentLineWidth = 0;\n```\n\n资料来源：[packages/openvideo/src/clips/text-clip.ts:200-280]()\n\n## CaptionClip 字幕剪辑\n\n### 功能特性\n\nCaptionClip 是专为字幕场景设计的剪辑类型，提供了比 TextClip 更丰富的字幕功能：\n\n- **逐词动画**：支持每个单词独立的动画效果\n- **颜色状态**：区分\"已出现(appeared)\"、\"激活(active)\"、\"背景(background)\"等状态\n- **关键词高亮**：支持特定关键词的颜色标记\n- **SRT 解析**：内置 SRT 字幕文件解析器\n- **保留关键词颜色**：在动画过程中保持关键词颜色不变\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:50-120]()\n\n### 字幕颜色系统\n\nCaptionClip 维护了一套完整的颜色状态系统：\n\n| 状态 | 说明 | 配置键 |\n|------|------|--------|\n| appeared | 已显示完成的单词 | colors.appeared |\n| active | 当前正在高亮的单词 | colors.active |\n| activeFill | 激活单词的填充色 | colors.activeFill |\n| background | 未激活单词的颜色 | colors.background |\n| keyword | 关键词的特殊颜色 | colors.keyword |\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:80-110]()\n\n### 颜色配置示例\n\n```typescript\nconst captionClip = new CaptionClip({\n  text: \"Hello world\",\n  colors: {\n    appeared: 0x888888,    // 已显示文字灰色\n    active: 0xFFFFFF,      // 当前高亮白色\n    activeFill: 0xFFFF00,  // 高亮填充黄色\n    background: 0x333333,  // 背景色深灰\n    keyword: 0x00FF00      // 关键词绿色\n  },\n  preserveKeywordColor: true // 保持关键词颜色\n});\n```\n\n### 渐变填充支持\n\nCaptionClip 支持使用 FillGradient 实现渐变文字效果：\n\n```typescript\nif (this.opts.fill && typeof this.opts.fill === 'object' && this.opts.fill.type === 'gradient') {\n  const gradient = new FillGradient(\n    this.opts.fill.x0,\n    this.opts.fill.y0,\n    this.opts.fill.x1,\n    this.opts.fill.y1\n  );\n  this.opts.fill.colors.forEach(\n    ({ ratio, color }: { ratio: number; color: string | number }) => {\n      const colorNumber = typeof color === 'number' \n        ? color \n        : (parseColor(color) ?? 0xffffff);\n      gradient.addColorStop(ratio, colorNumber);\n    }\n  );\n}\n```\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:150-200]()\n\n## SRT 字幕解析\n\n### SRTParser 模块\n\nOpenVideo 提供了内置的 SRT 格式解析器，可以将标准 SRT 字幕文件转换为内部格式：\n\n```mermaid\ngraph LR\n    A[SRT 文件] --> B[SRTParser]\n    B --> C[字幕片段数组]\n    C --> D[startTime, endTime]\n    C --> E[text]\n    D --> F[CaptionClip]\n```\n\n### 解析流程\n\n1. **时间码解析**：将 `00:00:01,000 --> 00:00:05,000` 格式转换为微秒时间戳\n2. **文本提取**：获取字幕片段中的文字内容\n3. **片段组合**：将多个连续片段合并为单个字幕项\n4. **格式输出**：输出符合 CaptionClip 输入格式的数据\n\n资料来源：[packages/openvideo/src/utils/srt-parser.ts]()\n\n## 字体管理\n\n### FontManager\n\n字体管理模块负责动态加载自定义字体，确保文字渲染使用正确的字形：\n\n```mermaid\ngraph TD\n    A[TimelineModel] --> B[FontManager]\n    B --> C{字体已缓存?}\n    C -->|是| D[直接使用]\n    C -->|否| E[加载字体]\n    E --> F[FontFace API]\n    F --> G[添加到 document.fonts]\n    G --> D\n    D --> H[渲染文字]\n```\n\n### 字体加载策略\n\nFontManager 会扫描所有剪辑中的字体引用，统一进行加载：\n\n```typescript\n// 检查普通文字样式中的字体\nif (clip.style?.fontUrl || (clip as any).fontUrl) {\n  fontsToLoad.set(fontUrl, {\n    name: clip.style?.fontFamily || (clip as any).fontFamily || \"CustomFont\",\n    url: fontUrl,\n  });\n}\n\n// 检查字幕样式中的字体\nif (clip.type === \"Caption\") {\n  const fontUrl = clip.style?.fontUrl || (clip as any).fontUrl;\n  if (fontUrl) {\n    fontsToLoad.set(fontUrl, { ... });\n  }\n}\n```\n\n资料来源：[packages/openvideo/src/studio/timeline-model.ts:200-260]()\n\n## 动画预设\n\n### 内置动画类型\n\nOpenVideo 为文字和字幕剪辑提供了丰富的预设动画：\n\n| 动画类型 | 说明 | 参数 |\n|----------|------|------|\n| fadeIn | 淡入效果 | opacityInit, opacityEnd |\n| slideIn | 滑入效果 | direction, distance |\n| slideOut | 滑出效果 | direction, distance |\n| pulse | 脉冲效果 | scaleInit, scaleEnd |\n| blurIn | 模糊淡入 | blurInit, opacityInit |\n\n### 动画配置示例\n\n```typescript\n// 淡入动画\ncase \"fadeIn\":\n  return {\n    \"0%\": { opacity: opacityInit ?? 0, mirror: defaultMirror },\n    \"100%\": { opacity: opacityEnd ?? 1, mirror: defaultMirror },\n  };\n\n// 滑入动画\ncase \"slideIn\": {\n  const direction = normalized?.direction || \"left\";\n  const distance = normalized?.distance || 300;\n  return {\n    \"0%\": {\n      x: direction === \"left\" ? -distance : direction === \"right\" ? distance : 0,\n      opacity: opacityInit ?? 0,\n      mirror: defaultMirror,\n    },\n    \"100%\": {\n      x: 0,\n      opacity: opacityEnd ?? 1,\n      mirror: defaultMirror,\n    },\n  };\n}\n```\n\n资料来源：[packages/openvideo/src/animation/presets.ts:50-120]()\n\n## JSON 序列化\n\n### 序列化格式\n\nTextClip 和 CaptionClip 都支持完整的 JSON 序列化，便于项目保存和加载：\n\n```typescript\ninterface CaptionDataJSON {\n  words?: string[];              // 单词数组\n  colors?: CaptionColorsJSON;    // 颜色配置\n  appearedColor?: number;        // 已显示颜色（向后兼容）\n  activeColor?: number;          // 激活颜色（向后兼容）\n  activeFillColor?: number;      // 激活填充色（向后兼容）\n  backgroundColor?: number;      // 背景色（向后兼容）\n  isKeyWordColor?: number;       // 关键词色（向后兼容）\n  bottomOffset?: number;         // 底部偏移\n  videoWidth?: number;           // 视频宽度\n  videoHeight?: number;          // 视频高度\n  wordsPerLine?: number;         // 每行词数\n  fontUrl?: string;              // 字体 URL\n  preserveKeywordColor?: boolean; // 保留关键词颜色\n  style?: TextStyleJSON;         // 文字样式\n}\n```\n\n### 向后兼容性\n\nCaptionClip 的序列化模块实现了向后兼容处理，支持旧版本的扁平化数据结构：\n\n```typescript\n// 旧扁平结构（向后兼容）\nif (json.appearedColor !== undefined) {\n  captionOpts.colors = captionOpts.colors || {};\n  captionOpts.colors.appeared = json.appearedColor;\n}\n\n// 新嵌套结构\nif (this.originalOpts?.caption?.colors?.appeared !== undefined) {\n  this.opts.appeared = this.originalOpts.caption.colors.appeared;\n}\n```\n\n资料来源：[packages/openvideo/src/clips/caption-clip.ts:300-400]()\n\n## 使用示例\n\n### 创建文字剪辑\n\n```typescript\nimport { Studio, Text } from 'openvideo';\n\nconst studio = new Studio({\n  canvas: document.getElementById('preview-canvas'),\n  width: 1280,\n  height: 720,\n});\n\nconst title = new Text('Hello World');\ntitle.duration = 5e6;  // 5秒\ntitle.fontSize = 48;\ntitle.fontFamily = 'Arial';\ntitle.fontWeight = 'bold';\ntitle.fill = '#FFFFFF';\ntitle.stroke = { color: '#000000', width: 2 };\ntitle.dropShadow = {\n  color: '#000000',\n  alpha: 0.5,\n  blur: 4,\n  distance: 2,\n  angle: Math.PI / 4\n};\n\nawait studio.addClip(title);\n```\n\n### 创建字幕剪辑\n\n```typescript\nimport { CaptionClip } from 'openvideo';\n\nconst caption = new CaptionClip({\n  text: 'This is a subtitle example',\n  fontSize: 32,\n  fontFamily: 'Microsoft YaHei',\n  colors: {\n    appeared: 0x888888,\n    active: 0xFFFFFF,\n    activeFill: 0xFFFF00,\n    background: 0x333333\n  },\n  wordAnimation: 'fadeIn',\n  verticalAlign: 'bottom',\n  bottomOffset: 50\n});\n\nawait studio.addClip(caption);\n```\n\n### 从 SRT 文件加载\n\n```typescript\nimport { SRTParser } from 'openvideo';\n\nconst srtContent = await fetch('/path/to/subtitle.srt').then(r => r.text());\nconst parsed = SRTParser.parse(srtContent);\n\nfor (const segment of parsed) {\n  const caption = new CaptionClip({\n    startTime: segment.startTime,\n    endTime: segment.endTime,\n    text: segment.text,\n    fontSize: 28,\n    colors: {\n      appeared: 0xAAAAAA,\n      active: 0xFFFFFF,\n      activeFill: 0x00FF00\n    }\n  });\n  await studio.addClip(caption);\n}\n```\n\n## 最佳实践\n\n### 性能优化\n\n1. **避免频繁创建文字对象**：TextClip 会为每个单词创建独立的 SplitBitmapText，过多的单词会影响性能\n2. **合理设置 wordWrapWidth**：过小的换行宽度会导致行数增加，增加渲染负担\n3. **使用缓存的字体**：确保字体只加载一次，避免重复加载\n\n### 兼容性注意\n\n1. **使用标准字体**：跨平台渲染时，优先使用系统自带字体\n2. **提供回退字体**：在 fontFamily 中指定多个字体作为回退\n3. **SRT 时间码格式**：确保 SRT 文件使用标准格式 `HH:MM:SS,mmm`\n\n## 相关模块\n\n| 模块 | 文件路径 | 用途 |\n|------|----------|------|\n| 核心剪辑 | `src/clips/clip.ts` | 剪辑基类 |\n| 文字剪辑 | `src/clips/text-clip.ts` | 文字渲染实现 |\n| 字幕剪辑 | `src/clips/caption-clip.ts` | 字幕渲染实现 |\n| 字体管理 | `src/utils/fonts.ts` | 字体加载管理 |\n| SRT 解析 | `src/utils/srt-parser.ts` | SRT 格式解析 |\n| 动画预设 | `src/animation/presets.ts` | 内置动画效果 |\n| 时间轴模型 | `src/studio/timeline-model.ts` | 时间轴数据管理 |\n\n---\n\n<a id='page-resources'></a>\n\n## 资源管理\n\n### 相关页面\n\n相关主题：[Studio - 项目状态管理](#page-studio), [视频与音频剪辑](#page-video-clip)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [packages/openvideo/src/studio/resource-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/studio/resource-manager.ts)\n- [packages/openvideo/src/utils/asset-manager.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/asset-manager.ts)\n- [packages/openvideo/src/clips/video-clip.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/clips/video-clip.ts)\n- [packages/openvideo/src/utils/chromakey.ts](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/src/utils/chromakey.ts)\n- [packages/openvideo/render.html](https://github.com/openvideodev/openvideo/blob/main/packages/openvideo/render.html)\n</details>\n\n# 资源管理\n\n## 概述\n\nOpenVideo 的资源管理模块是整个视频处理工作流的基础组件，负责媒体资源的加载、存储、流式传输和生命周期管理。该模块由 `ResourceManager` 和 `AssetManager` 两个核心类构成，支持从远程 URL 获取资源并将数据持久化到本地 OPFS（Origin Private File System）文件系统。\n\n资源管理的核心设计目标包括：\n\n- **统一资源获取**：提供一致的接口获取各类媒体资源（视频、音频、图片等）\n- **本地缓存**：通过 OPFS 实现资源的本地持久化存储，减少重复网络请求\n- **流式处理**：支持 ReadableStream 流式读取，适配大文件处理场景\n- **异步操作**：所有资源操作均为异步执行，确保主线程不被阻塞\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts:1-50]()\n\n## 核心架构\n\n### 类结构\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                    ResourceManager                          │\n│  - getReadableStream(url): Promise<ReadableStream>          │\n│  - 静态方法，提供统一的资源获取入口                           │\n└─────────────────────────────────────────────────────────────┘\n                              │\n                              ▼\n┌─────────────────────────────────────────────────────────────┐\n│                    AssetManager                             │\n│  - 管理资源缓存和生命周期                                    │\n│  - 提供资源加载、释放、状态追踪                              │\n└─────────────────────────────────────────────────────────────┘\n                              │\n                              ▼\n┌─────────────────────────────────────────────────────────────┐\n│                    OPFS (Origin Private File System)         │\n│  - 本地文件系统存储                                          │\n│  - 支持大文件持久化                                          │\n└─────────────────────────────────────────────────────────────┘\n```\n\n资料来源：[packages/openvideo/src/utils/asset-manager.ts:1-30]()\n\n### 资源加载流程\n\n```mermaid\ngraph TD\n    A[请求资源 URL] --> B{检查缓存}\n    B -->|命中缓存| C[从 OPFS 读取本地文件]\n    B -->|未命中| D[发起网络请求]\n    D --> E[获取 ReadableStream]\n    E --> F[写入 OPFS 本地文件]\n    F --> G[返回本地文件引用]\n    C --> G\n    G --> H[创建 Video/Audio/Image Clip]\n```\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts:20-40]()\n\n## ResourceManager\n\n### 核心方法\n\n`ResourceManager` 是静态工具类，提供资源获取的核心接口。\n\n#### getReadableStream(url: string): Promise<ReadableStream<Uint8Array>>\n\n从指定 URL 获取资源的可读流。\n\n| 参数 | 类型 | 说明 |\n|------|------|------|\n| url | string | 资源 URL，支持 HTTP/HTTPS 协议 |\n\n| 返回值 | 说明 |\n|--------|------|\n| Promise<ReadableStream<Uint8Array>> | 资源的可读字节流 |\n\n```typescript\n// 获取视频资源的流\nconst stream = await ResourceManager.getReadableStream('https://example.com/video.mp4');\n```\n\n资料来源：[packages/openvideo/src/studio/resource-manager.ts:30-45]()\n\n## AssetManager\n\n### 资源缓存机制\n\n`AssetManager` 负责管理资源缓存状态和生命周期，确保内存资源得到正确释放。\n\n### 资源类型支持\n\n| 类型 | 说明 | 适用场景 |\n|------|------|----------|\n| 视频资源 | 通过 Video Clip 加载的 MP4/WebM 等格式 | 视频轨道编辑 |\n| 音频资源 | 独立的音频流 | 音频混合处理 |\n| 图片资源 | PNG/JPG/WebP 等静态图像 | 封面、字幕背景 |\n\n资料来源：[packages/openvideo/src/utils/asset-manager.ts:25-40]()\n\n## Video Clip 中的资源集成\n\n### fromUrl 静态工厂方法\n\n`Video.fromUrl()` 是创建视频剪辑的便捷入口，内部自动调用 `ResourceManager` 获取资源。\n\n```typescript\nstatic async fromUrl(\n  url: string,\n  opts: {\n    x?: number;\n    y?: number;\n    width?: number;\n    height?: number;\n  } = {}\n): Promise<Video>\n```\n\n| 参数 | 类型 | 必填 | 说明 |\n|------|------|------|------|\n| url | string | 是 | 视频资源 URL |\n| opts.x | number | 否 | 剪辑在画布中的 X 坐标 |\n| opts.y | number | 否 | 剪辑在画布中的 Y 坐标 |\n| opts.width | number | 否 | 剪辑显示宽度 |\n| opts.height | number | 否 | 剪辑显示高度 |\n\n```typescript\n// 加载远程视频并设置位置\nconst video = await Video.fromUrl('https://example.com/video.mp4', {\n  x: 100,\n  y: 50,\n  width: 1280,\n  height: 720\n});\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:50-80]()\n\n### localFile 本地文件管理\n\n视频资源下载后会存储在 OPFS 中，`localFile` 属性保存本地文件引用。\n\n```typescript\n// Video Clip 构造函数中的本地文件初始化\nconst initByStream = async (s: ReadableStream) => {\n  await write(this.localFile, s);\n  return this.localFile;\n};\n\nthis.localFile = isOTFile(source)\n  ? source\n  : \"localFileFinder\"; // 使用 OPFS 存储\n```\n\n| 属性 | 类型 | 说明 |\n|------|------|------|\n| localFile | OPFSToolFile | OPFS 中的本地文件句柄 |\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:75-85]()\n\n## 图像处理中的资源管理\n\n### 图像源接口\n\n`ImgSource` 类型用于统一不同来源的图像数据：\n\n```typescript\ntype ImgSource = ImageBitmap | HTMLImageElement | \n                  HTMLCanvasElement | OffscreenCanvas | \n                  VideoFrame;\n```\n\n### Chromakey（色键抠像）资源处理\n\n`createChromakey` 函数展示了图像资源的流式处理模式：\n\n```typescript\nexport const createChromakey = (\n  opts: Omit<IChromakeyOpts, 'keyColor'> & {\n    keyColor?: [number, number, number];\n  }\n) => {\n  let canvas: HTMLCanvasElement | OffscreenCanvas | null = null;\n  let gl: WebGLRenderingContext | null = null;\n  let keyColor = opts.keyColor;\n  let texture: WebGLTexture | null = null;\n\n  return async (imgSource: ImgSource) => {\n    if (canvas == null || gl == null || texture == null) {\n      if (keyColor == null) keyColor = getKeyColor(imgSource);\n      // 初始化 canvas 和 WebGL 上下文\n    }\n    // 更新纹理并返回处理后的 VideoFrame\n  };\n};\n```\n\n| 组件 | 类型 | 生命周期 |\n|------|------|----------|\n| canvas | HTMLCanvasElement \\| OffscreenCanvas | 首次调用时创建 |\n| gl | WebGLRenderingContext | 首次调用时初始化 |\n| texture | WebGLTexture | 按需创建和更新 |\n\n资料来源：[packages/openvideo/src/utils/chromakey.ts:20-60]()\n\n## 渲染模板中的资源注入\n\nOpenVideo 在服务端渲染场景中使用 Playwright 注入配置，HTML 模板通过 `window.RENDER_CONFIG` 获取渲染参数。\n\n```javascript\n// 获取 JSON 配置\nconst jsonConfig = window.RENDER_CONFIG;\n\nif (!jsonConfig) {\n  throw new Error('No render configuration provided');\n}\n\n// 从配置中提取设置\nconst settings = jsonConfig.settings || {};\nconst compositorOpts = {\n  width: settings.width || 1280,\n  height: settings.height || 720,\n  fps: settings.fps || 30,\n  bgColor: settings.bgColor || '#000000',\n};\n```\n\n| 配置项 | 默认值 | 说明 |\n|--------|--------|------|\n| width | 1280 | 输出视频宽度 |\n| height | 720 | 输出视频高度 |\n| fps | 30 | 帧率 |\n| bgColor | #000000 | 背景颜色 |\n| videoCodec | - | 视频编码器 |\n| bitrate | - | 比特率 |\n| audio | true | 是否包含音频 |\n\n资料来源：[packages/openvideo/render.html:25-50]()\n\n## 最佳实践\n\n### 资源加载建议\n\n1. **使用 fromUrl 工厂方法**：优先使用 `Video.fromUrl()` 而非直接操作流，确保资源正确缓存\n2. **指定尺寸参数**：在 `fromUrl` 中指定 `width`/`height` 可避免布局抖动\n3. **检查资源就绪状态**：调用 `await clip.ready` 确保媒体元数据加载完成\n\n### 内存管理\n\n```typescript\n// 正确的异步初始化模式\nconst video = await Video.fromUrl('video.mp4');\nawait video.ready; // 等待元数据加载\nawait video.thumbnails(100); // 生成缩略图\n```\n\n### 异常处理\n\n```typescript\ntry {\n  const stream = await ResourceManager.getReadableStream(url);\n  if (!stream) {\n    throw new Error('Failed to get readable stream');\n  }\n} catch (error) {\n  console.error('Resource loading failed:', error);\n}\n```\n\n资料来源：[packages/openvideo/src/clips/video-clip.ts:60-75]()\n\n## 总结\n\nOpenVideo 的资源管理模块通过 `ResourceManager` 和 `AssetManager` 提供了完整的资源获取和生命周期管理能力。结合 OPFS 本地存储和流式处理机制，该系统能够高效处理远程媒体资源，同时保持较低的内存占用。开发者应遵循工厂方法优先、异步操作必检、资源释放及时的原则，以确保应用的稳定性和性能。\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：openvideodev/openvideo\n\n摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1125747446 | https://github.com/openvideodev/openvideo | README/documentation is current enough for a first validation pass.\n\n## 2. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | last_activity_observed missing\n\n## 3. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n\n## 4. 安全/权限坑 · 存在安全注意事项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：No sandbox install has been executed yet; downstream must verify before user use.\n- 对用户的影响：用户安装前需要知道权限边界和敏感操作。\n- 建议检查：转成明确权限清单和安全审查提示。\n- 防护动作：安全注意事项必须面向用户前置展示。\n- 证据：risks.safety_notes | github_repo:1125747446 | https://github.com/openvideodev/openvideo | No sandbox install has been executed yet; downstream must verify before user use.\n\n## 5. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n\n## 6. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | issue_or_pr_quality=unknown\n\n## 7. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | release_recency=unknown\n\n<!-- canonical_name: openvideodev/openvideo; human_manual_source: deepwiki_human_wiki -->\n",
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "Human Manual / 人类版说明书"
    },
    "pitfall_log": {
      "asset_id": "pitfall_log",
      "filename": "PITFALL_LOG.md",
      "markdown": "# Pitfall Log / 踩坑日志\n\n项目：openvideodev/openvideo\n\n摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1125747446 | https://github.com/openvideodev/openvideo | README/documentation is current enough for a first validation pass.\n\n## 2. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | last_activity_observed missing\n\n## 3. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n\n## 4. 安全/权限坑 · 存在安全注意事项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：No sandbox install has been executed yet; downstream must verify before user use.\n- 对用户的影响：用户安装前需要知道权限边界和敏感操作。\n- 建议检查：转成明确权限清单和安全审查提示。\n- 防护动作：安全注意事项必须面向用户前置展示。\n- 证据：risks.safety_notes | github_repo:1125747446 | https://github.com/openvideodev/openvideo | No sandbox install has been executed yet; downstream must verify before user use.\n\n## 5. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1125747446 | https://github.com/openvideodev/openvideo | no_demo; severity=medium\n\n## 6. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | issue_or_pr_quality=unknown\n\n## 7. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1125747446 | https://github.com/openvideodev/openvideo | release_recency=unknown\n",
      "summary": "用户实践前最可能遇到的身份、安装、配置、运行和安全坑。",
      "title": "Pitfall Log / 踩坑日志"
    },
    "prompt_preview": {
      "asset_id": "prompt_preview",
      "filename": "PROMPT_PREVIEW.md",
      "markdown": "# openvideo - Prompt Preview\n\n> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 openvideo 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的软件开发与交付任务。\n我常用的宿主 AI：Local CLI\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: Open-source React Video Editor with client-side rendering (WebCodecs) and pixi.js. Capcut clone. Canva clone. React video editor. webgl video editor. 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. page-introduction：项目介绍。围绕“项目介绍”模拟一次用户任务，不展示安装或运行结果。\n2. page-installation：安装与配置。围绕“安装与配置”模拟一次用户任务，不展示安装或运行结果。\n3. page-quick-start：快速开始。围绕“快速开始”模拟一次用户任务，不展示安装或运行结果。\n4. page-architecture：系统架构。围绕“系统架构”模拟一次用户任务，不展示安装或运行结果。\n5. page-studio：Studio - 项目状态管理。围绕“Studio - 项目状态管理”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. page-introduction\n输入：用户提供的“项目介绍”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. page-installation\n输入：用户提供的“安装与配置”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. page-quick-start\n输入：用户提供的“快速开始”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. page-architecture\n输入：用户提供的“系统架构”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. page-studio\n输入：用户提供的“Studio - 项目状态管理”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / page-introduction：Step 1 必须围绕“项目介绍”形成一个小中间产物，并等待用户确认。\n- Step 2 / page-installation：Step 2 必须围绕“安装与配置”形成一个小中间产物，并等待用户确认。\n- Step 3 / page-quick-start：Step 3 必须围绕“快速开始”形成一个小中间产物，并等待用户确认。\n- Step 4 / page-architecture：Step 4 必须围绕“系统架构”形成一个小中间产物，并等待用户确认。\n- Step 5 / page-studio：Step 5 必须围绕“Studio - 项目状态管理”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/openvideodev/openvideo\n- https://github.com/openvideodev/openvideo#readme\n- README.md\n- packages/openvideo/src/index.ts\n- docs/content/docs/installation.mdx\n- packages/openvideo/package.json\n- package.json\n- docs/content/docs/basic-usage.mdx\n- packages/openvideo/src/studio.ts\n- examples/src/App.tsx\n- packages/openvideo/src/compositor.ts\n- packages/openvideo/src/studio/timeline-model.ts\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 openvideo 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\n```\n",
      "summary": "不安装项目也能感受能力节奏的安全试用 Prompt。",
      "title": "Prompt Preview / 安装前试用 Prompt"
    },
    "quick_start": {
      "asset_id": "quick_start",
      "filename": "QUICK_START.md",
      "markdown": "# Quick Start / 官方入口\n\n项目：openvideodev/openvideo\n\n## 官方安装入口\n\n### Node.js / npm · 官方安装入口\n\n```bash\nnpm install openvideo\n```\n\n来源：https://github.com/openvideodev/openvideo#readme\n\n## 来源\n\n- repo: https://github.com/openvideodev/openvideo\n- docs: https://github.com/openvideodev/openvideo#readme\n",
      "summary": "从项目官方 README 或安装文档提取的开工入口。",
      "title": "Quick Start / 官方入口"
    }
  },
  "validation_id": "dval_afe2a45ad6dc4273ab1c040781a767e4"
}
