<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>知了博客</title><link>https://www.webgou.info/</link><description>集天地之精华，吸日月之灵气</description><item><title>codex安装教程</title><link>https://www.webgou.info/?id=726</link><description>&lt;p class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; margin: 0px; font-size: 16px; line-height: 28px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;OpenAI Codex 是 OpenAI 推出的 AI 编程助手，支持桌面端和命令行（CLI）两种使用方式。以下是详细的安装与配置教程。&lt;/p&gt;&lt;h4 class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-size: 16px; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; line-height: 28px; margin-top: 16px; margin-bottom: 14px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;桌面端安装（适合新手与日常使用）&lt;/h4&gt;&lt;p class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; margin: 0px; font-size: 16px; line-height: 28px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;桌面端操作最直观，适合不想折腾命令行的用户。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; padding-left: 18px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;访问官网&lt;/span&gt;：打开 &lt;a href=&quot;https://openai.com/codex/&quot; class=&quot;xhs-answer-titled-link&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; background-color: transparent; text-decoration: none; color: rgb(61, 138, 245); cursor: pointer; line-height: 28px; overflow-wrap: anywhere;&quot;&gt;OpenAI Codex 官网&lt;/a&gt;，页面会自动识别你的系统。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;下载安装包&lt;/span&gt;：点击对应的 &lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;Download for Mac&lt;/span&gt; 或 &lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;Download for Windows&lt;/span&gt; 按钮。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;执行安装&lt;/span&gt;：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;macOS&lt;/span&gt;：下载 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;.dmg&lt;/code&gt; 文件后双击挂载，将 Codex 图标拖入「应用程序」文件夹即可。首次打开若提示无法验证开发者，请进入「系统设置 → 隐私与安全性」点击「仍要打开」。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;Windows&lt;/span&gt;：下载 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;.exe&lt;/code&gt; 或 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;.msix&lt;/code&gt; 安装包，双击运行并按向导提示完成安装。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;登录账号&lt;/span&gt;：打开应用，使用你的 ChatGPT / OpenAI 账号扫码或输入密码登录（通常需要 Plus 或 Pro 订阅才能使用完整功能）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-size: 16px; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; line-height: 28px; margin-top: 16px; margin-bottom: 14px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;命令行端安装（适合开发者与自动化）&lt;/h4&gt;&lt;p class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; margin: 0px; font-size: 16px; line-height: 28px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;如果你习惯在终端工作，或者想将 Codex 接入其他工具，可以使用 CLI 版本。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; padding-left: 18px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;准备环境&lt;/span&gt;：确保电脑已安装 &lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;Node.js&lt;/span&gt;（版本 18 或更高，推荐 22+）和 &lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;npm&lt;/span&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;全局安装&lt;/span&gt;：在终端或 PowerShell 中执行以下命令：&lt;/p&gt;&lt;/li&gt;&lt;ul style=&quot;list-style-type: square;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;标准安装&lt;/span&gt;：&lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;npm install -g @openai/codex&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;国内加速&lt;/span&gt;：如果 npm 下载慢，可以加上镜像源：&lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;npm install -g @openai/codex --registry=https://registry.npmmirror.com&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;Mac 用户备选&lt;/span&gt;：如果你使用了 Homebrew，也可以直接运行 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;brew install --cask codex&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;验证安装&lt;/span&gt;：安装完成后，输入 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;codex --version&lt;/code&gt;，如果终端返回了版本号，说明安装成功。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;登录使用&lt;/span&gt;：在终端输入 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;codex&lt;/code&gt;，浏览器会自动弹出授权页面，完成登录后即可在命令行中使用。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-size: 16px; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; line-height: 28px; margin-top: 16px; margin-bottom: 14px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;配置 API Key 与接入国产模型&lt;/h4&gt;&lt;p class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; margin: 0px; font-size: 16px; line-height: 28px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;如果你没有 ChatGPT 订阅，或者想接入 &lt;span data-keyword=&quot;DeepSeek安装教程&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: #133667; font-weight: 600; display: inline; cursor: pointer;&quot;&gt;DeepSeek&lt;/span&gt;、&lt;span data-keyword=&quot;Kimi Codex安装教程&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: #133667; font-weight: 600; display: inline; cursor: pointer;&quot;&gt;Kimi&lt;/span&gt; 等国产模型，可以通过配置 API Key 来实现。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; padding-left: 18px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;获取 API Key&lt;/span&gt;：登录对应的模型开放平台（如 DeepSeek 开放平台），在后台创建并复制你的 API Key。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;配置环境变量&lt;/span&gt;：在终端中执行命令将 Key 加入环境变量（以 macOS/Linux 为例）： &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;export OPENAI_API_KEY=&amp;quot;你的 sk- 开头的密钥&amp;quot;&lt;/code&gt; （Windows PowerShell 用户可使用：&lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;$env:OPENAI_API_KEY=&amp;quot;你的 sk- 开头的密钥&amp;quot;&lt;/code&gt;）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;配置模型参数&lt;/span&gt;：你可以创建或编辑 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;~/.codex/config.toml&lt;/code&gt; 配置文件，将模型名称修改为你想要的模型（例如 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;model = &amp;quot;deepseek-chat&amp;quot;&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;使用本地路由工具&lt;/span&gt;：由于 Codex 默认走 OpenAI 的接口格式，而国产模型格式不同，很多开发者会搭配 &lt;span data-keyword=&quot;CCSwitch安装教程&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: #133667; font-weight: 600; display: inline; cursor: pointer;&quot;&gt;CCSwitch&lt;/span&gt; 或类似的本地路由工具进行协议翻译。在路由工具中添加供应商和 API Key，开启本地路由后，Codex 就能正常调用国产模型了。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 class=&quot;&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-size: 16px; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; line-height: 28px; margin-top: 16px; margin-bottom: 14px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;常见问题与避坑指南&lt;/h4&gt;&lt;ul class=&quot; list-paddingleft-2&quot; style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; color: rgba(0, 0, 0, 0.8); font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; padding-left: 18px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;网络限制&lt;/span&gt;：官方服务对地区有限制，国内直连经常不稳定或无法登录。如果无法访问，请检查网络环境，或者改用上述的“接入国产模型”方案。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;权限模式设置&lt;/span&gt;：首次进入桌面端时，&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;务必将权限模式设置为「自动审查」&lt;/span&gt;。这样 Codex 在执行危险操作（如删除文件、运行复杂命令）前会询问你，防止误删项目代码。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;API Key 安全&lt;/span&gt;：API Key 相当于你的账号密码和钱包，&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;千万不要截图发给别人或上传到公开的代码仓库&lt;/span&gt;。如果不小心泄露，请立即去后台作废并重新生成。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-weight: 600; position: relative;&quot;&gt;Windows 环境变量报错&lt;/span&gt;：如果 Windows 版打开提示 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;Unable to locate the Codex CLI binary&lt;/code&gt;，可以通过 PowerShell 设置环境变量 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;CODEX_CLI_PATH&lt;/code&gt;，指向你电脑上 &lt;code style=&quot;box-sizing: border-box; user-select: auto; scrollbar-width: none; -webkit-tap-highlight-color: transparent; font-family: &amp;quot;PingFang SC&amp;quot;, Arial, sans-serif, &amp;quot;Noto Sans SC&amp;quot;; font-size: 1em;&quot;&gt;codex.exe&lt;/code&gt; 的实际安装路径。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 12 Nov 2026 10:37:40 +0800</pubDate></item><item><title>做小红书运营后的几点真实感想</title><link>https://www.webgou.info/?id=725</link><description>&lt;h4&gt;一、关于内容：真诚永远是底层逻辑&lt;/h4&gt;&lt;p&gt;刚入行的时候总觉得运营是 “玩技巧”，堆关键词、套爆款模板、研究封面公式，以为把 SEO 做满就能拿到流量。直到自己发过好几篇 0 赞的笔记才明白：&lt;strong&gt;SEO 只是放大器，不是救命稻草&lt;/strong&gt;。内容本身空洞、说教，全是 “你应该”“你必须”，哪怕关键词埋得再密，用户划到也会立刻走。&lt;/p&gt;&lt;p&gt;反而随手写的一篇真实日常感悟，没有刻意布局关键词，却收到了几十条评论共鸣。小红书的用户本质是来找同类、找慰藉、找解决方案的，不是来听人上课的。真实的 “普通人视角”，比完美的 “专家人设” 更容易让人停下手指。不精致但有用、不华丽但真诚的内容，生命力反而更长。&lt;/p&gt;&lt;p&gt;慢慢也懂了 “利他” 两个字不是口号。一篇笔记能不能跑起来，开头三秒就要回答用户 “我能得到什么”—— 是一个能直接抄的方法，是一种被说中心事的情绪，还是一个能避坑的经验？只讲自己想讲的，不管用户想看的，再努力也是自嗨。&lt;/p&gt;&lt;h4&gt;二、关于流量：爆款是测出来的，不是算出来的&lt;/h4&gt;&lt;p&gt;新手期最容易陷入 “爆款焦虑”：别人发什么火了，自己立刻照搬，结果数据惨淡，就怀疑账号不行、平台针对自己。做久了才接受一个现实：&lt;strong&gt;爆款没有百分百的公式，它是概率事件&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;冷启动阶段，模仿爆款选题和结构是效率最高的方式，但模仿的是 “方向” 不是 “复制粘贴”，表达和观点必须是自己的人人都是产...。与其死磕一篇内容追求完美，不如快速测试、快速迭代，用小成本试错找到用户喜欢的口味。&lt;/p&gt;&lt;p&gt;还有一个很反直觉的体会：赞藏高不等于涨粉多。很多大爆款数据很漂亮，但粉丝涨不动，因为用户只认可这一篇内容，不认可你这个人。真正能沉淀粉丝的，是持续稳定的垂直输出，让用户点进主页就知道 “关注你能持续获得什么”。流量是让别人看见你，而人设和价值感，才是让别人留下来的原因。&lt;/p&gt;&lt;h4&gt;三、关于心态：情绪脱敏是运营的必修课&lt;/h4&gt;&lt;p&gt;做小红书最磨人的不是做内容，是盯数据。发布后一小时刷八次小眼睛，赞少了就自我怀疑，数据波动就彻夜复盘，是很多人的常态。但运营越久越明白：把情绪和数据绑定，是最内耗的事。&lt;/p&gt;&lt;p&gt;0 赞的笔记教会人的东西，有时候比爆款还多。它会逼你直面自己的浮躁 —— 太急于求成，太想靠技巧走捷径，反而忽略了内容本身的温度。数据好的时候别飘，那可能只是平台刚好给了一波流量；数据差的时候也别否定自己，也许只是选题没踩中当下的需求，换个角度再试就好。&lt;/p&gt;&lt;p&gt;“开始比完美重要” 这句话，说起来容易做起来难。很多人迟迟不发第一篇，总觉得还没准备好：封面不够好看、文案不够精炼、人设不够清晰。但事实上，没有谁一开始就做对所有事。账号是一步步跑出来的，风格是一篇篇试出来的，停在原地想，永远不会有答案。&lt;/p&gt;&lt;h4&gt;四、关于变现：流量和转化是两件事&lt;/h4&gt;&lt;p&gt;早期很容易陷入 “唯流量论”，觉得只要爆文多，变现自然水到渠成。真正跑通变现后才发现，&lt;strong&gt;只做爆款不设计转化，很难持续&lt;/strong&gt;人人都是产...。爆文带来的是曝光，但从 “看过” 到 “买单”，中间还差着信任、需求和路径设计。&lt;/p&gt;&lt;p&gt;如果是做带货或知识付费，内容从一开始就要兼顾 “流量属性” 和 “转化属性”。不能为了博眼球做和自己赛道完全无关的内容，那样引来的流量不精准，变现时全是无效粉。比起泛流量，精准的垂直粉丝价值高得多 —— 哪怕只有几千粉，只要信任度够，转化也会很可观。&lt;/p&gt;&lt;p&gt;还有一点很深的体会：小红书的变现是慢功夫。它不像短视频平台爆发性强，但用户信任度高、决策周期短，靠的是内容资产的长期积累。今天发的一篇笔记，可能半年后还在源源不断带来咨询和订单，这也是它最有魅力的地方。&lt;/p&gt;&lt;h4&gt;五、最后想说的话&lt;/h4&gt;&lt;p&gt;做小红书运营到最后，拼的其实不是技巧，是耐心和认知。有人三个月没起色就放弃，有人半年才摸到门路，有人坚持一年才迎来爆发。这个平台很公平，你有没有用心做内容，用户和算法都能感觉到。&lt;/p&gt;&lt;p&gt;它不只是一个流量工具，更像一面镜子 —— 你急功近利，数据就给你泼冷水；你真诚分享，用户就给你正向反馈。比起涨了多少粉、赚了多少钱，更珍贵的收获是：学会了用用户视角看问题，学会了在波动里保持节奏，也学会了把一件事长期、认真地做下去。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Wed, 04 Nov 2026 16:29:16 +0800</pubDate></item><item><title>把停服七年的手游变成单机版：REA 逆向实战</title><link>https://www.webgou.info/?id=724</link><description>&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;前言&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;最近拿到一个 2015 年的手游 APK——《高达战争》，百度渠道包，207MB。这类老网游的宿命都一样：服务器早就停了，域名解析都没有了，但游戏的引擎、美术、玩法逻辑还完整地躺在安装包里。这篇文章记录的是一次完整的目标：把这个包变成&lt;strong&gt;本地可运行的单机版&lt;/strong&gt;，包括破解脚本加密、还原通信协议、搭本地服务、修改存档、注入兑换码，以及最后治理&amp;quot;概率性闪退&amp;quot;的全过程。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;全部工作只用了 Python 标准库、jadx、adb 和一个安卓模拟器。没有 Frida，没有 IDA。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;方法论上依赖的是自建的 &lt;strong&gt;REA（Reverse Engineering Assistant，通用逆向助手工具集）&lt;/strong&gt;。REA 最初为逆向一款 Electron 桌面应用而建：一个纯 Python 实现的 ASAR 解包器，加上几十个单文件分析脚本——域名扫描、关键词上下文检索、IPC 渠道分析、凭据编解码器与硬编码密钥扫描等等，约定&amp;quot;改脚本第一行的 root 变量即可对新目标开跑&amp;quot;。随着项目积累，REA 从脚本集合演化成一套&lt;strong&gt;按目标类型沉淀的 playbook 体系&lt;/strong&gt;：Electron 应用一条、加固壳 Cocos 游戏一条，每打完一个目标就把可复用的流程、判据和踩坑清单写回对应的 playbook。这次的项目，就是照着 REA 的套路从头走到尾，最后又把经验沉淀成了它的第三条 playbook。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;一、五分钟定引擎：看文件指纹&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;拿到一个游戏 APK，第一件事不是打开反编译器，而是解包看两个地方：&lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;lib/&lt;/code&gt; 里的 so 名字和 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;assets/&lt;/code&gt; 的目录形态。引擎指纹互不混淆：&lt;/p&gt;&lt;table width=&quot;860&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;th style=&quot;border-color: rgb(221, 221, 221); padding: 6px 10px; font-size: 14px; text-align: left; background: rgb(240, 244, 248);&quot;&gt;看哪里&lt;/th&gt;&lt;th style=&quot;border-color: rgb(221, 221, 221); padding: 6px 10px; font-size: 14px; text-align: left; background: rgb(240, 244, 248);&quot;&gt;Cocos2d-x + Lua&lt;/th&gt;&lt;th style=&quot;border-color: rgb(221, 221, 221); padding: 6px 10px; font-size: 14px; text-align: left; background: rgb(240, 244, 248);&quot;&gt;Cocos Creator JS&lt;/th&gt;&lt;th style=&quot;border-color: rgb(221, 221, 221); padding: 6px 10px; font-size: 14px; text-align: left; background: rgb(240, 244, 248);&quot;&gt;Unity&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;lib/*.so&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;libcocos2dlua.so&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;libcocos2djs.so&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;libil2cpp.so + libunity.so&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;assets&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;src/*.lua + res/&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;src/*.jsc + _CCSettings&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;bin/Data + Assembly-CSharp&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;这个包是标准的 Cocos2d-x Lua 架构：708 个 Lua 脚本、3256 个资源文件。更有意思的是 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;assets/config.json&lt;/code&gt; 里有 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;simulator_screen_size&lt;/code&gt; 和 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;consolePort&lt;/code&gt;——这是 Cocos Code IDE 时代 runtime 的标志格式，说明这游戏&lt;strong&gt;原生支持桌面模拟器运行&lt;/strong&gt;。后面会看到，这个细节成了整个本地化工作的钥匙。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;二、破解脚本加密：钥匙就藏在引擎隔壁&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;打开 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;src/main.lua&lt;/code&gt;，满屏乱码——但头部 10 个字节是可读的 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;51hutongnb&lt;/code&gt;。这是 cocos2d-x 脚本加密的标准形态：&lt;strong&gt;签名头 + XXTEA 密文&lt;/strong&gt;。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;密钥在哪？不需要动态调试。cocos 引擎启动时通过 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;setXXTEAKeyAndSign&lt;/code&gt; 把密钥和签名传进去，两者都是字符串常量，必然并排躺在 libcocos2dlua.so 的只读数据区里。于是：&lt;/p&gt;&lt;pre style=&quot;background: rgb(246, 248, 250); padding: 12px; border-radius: 6px; overflow-x: auto; font-size: 13px; color: rgb(51, 51, 51);&quot;&gt;idx&amp;nbsp;=&amp;nbsp;so.find(b&amp;#39;51hutongnb&amp;#39;)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;先搜签名
seg&amp;nbsp;=&amp;nbsp;so[idx-300:idx+300]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;挖前后&amp;nbsp;600&amp;nbsp;字节
#&amp;nbsp;输出:&amp;nbsp;...&amp;nbsp;923e0288f6673ff08d4bc41d8e7aea12&amp;nbsp;/&amp;nbsp;51hutong&amp;nbsp;/&amp;nbsp;51hutongnb&amp;nbsp;...
#&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;→&amp;nbsp;key&amp;nbsp;=&amp;nbsp;&amp;quot;51hutong&amp;quot;(8字节),&amp;nbsp;sign&amp;nbsp;=&amp;nbsp;&amp;quot;51hutongnb&amp;quot;(10字节)&lt;/pre&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;那个 32 位 hex 字符串是干扰项。真正的坑在 XXTEA 实现本身：cocos 用的是 xxtea-c 的变体，加密前会把明文补齐到 4 字节边界，然后&lt;strong&gt;在密文末尾追加 4 字节的原始长度&lt;/strong&gt;。我第一版解密脚本把长度当成了前缀，解出来全是乱码。正确做法是解密后校验尾部长度字段——顺便这也是验证密钥对不对的免费手段。修正后，708 个 Lua 全部解密成明文。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;三、读明文：339 个接口和一条登录链&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;Lua 变成明文之后，剩下的就是 grep 的艺术。几条命令下来，整个游戏的架构就清楚了：&lt;/p&gt;&lt;pre style=&quot;background: rgb(246, 248, 250); padding: 12px; border-radius: 6px; overflow-x: auto; font-size: 13px; color: rgb(51, 51, 51);&quot;&gt;grep&amp;nbsp;-rho&amp;nbsp;&amp;#39;&amp;quot;gundam/[a-zA-Z/_]*&amp;quot;&amp;#39;&amp;nbsp;src&amp;nbsp;--include=&amp;quot;*.lua&amp;quot;&amp;nbsp;|&amp;nbsp;sort&amp;nbsp;-u
#&amp;nbsp;→&amp;nbsp;339&amp;nbsp;个服务端接口：fuben(副本)/union(军团)/pvp/kuaFuTeam(跨服)…&lt;/pre&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;这是一个典型的客户端-服务器网游：HTTP POST 表单 + MD5 签名（密钥 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;GUNDAM_2015&lt;/code&gt; 硬编码在 global.lua 里），JSON 响应。登录链是：&lt;/p&gt;&lt;blockquote style=&quot;border-left: 4px solid rgb(203, 213, 224); margin: 1em 0px; padding: 2px 14px; color: rgb(85, 85, 85); background: rgb(250, 250, 250); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;机型检测 → 版本检查 → 服务器列表 → 登录 → 玩家初始化（返回 201 表示新号）→ 建角色 → 12 个数据同步接口 → 主城&lt;/blockquote&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;最关键的发现藏在 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;system.lua&lt;/code&gt;：游戏按渠道号决定登录方式，而渠道 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;00000000_ADWUYOU&lt;/code&gt; 走的是 &lt;strong&gt;loginType=2 设备 ID 登录&lt;/strong&gt;——完全绕开百度 SDK。也就是说，游戏自己就带着&amp;quot;无账号登录&amp;quot;的后门，只差有人把渠道号指过去。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;四、本地化改造：改一个文件，重签一次名&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;方案变得非常薄：只改 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;src/system.lua&lt;/code&gt; 一个文件——把渠道强制为 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;00000000_ADWUYOU&lt;/code&gt;，把四个服务器地址全部指向本地——然后用 Python 的 zipfile 把它替换回 APK（顺便丢掉旧签名），jarsigner 重新签名。不需要 apktool，不需要碰引擎 so。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;本地服务用 Python 标准库写一个 mock：实现启动链的 20 个接口，其余 319 个统一返回空成功兜底。几个踩过的坑值得记：&lt;/p&gt;&lt;ul style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;模拟器连宿主机：LDPlayer 里 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;10.0.2.2&lt;/code&gt; 不通，要用宿主机的局域网 IP；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;阵容(zhenrong)数据结构里 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;formMap&lt;/code&gt; 缺失会在战力计算里报空指针——这种报错从 logcat 的 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;TestinAgent: reason&lt;/code&gt; 里直接能看到完整 Lua 堆栈；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;guide.stepId=&amp;quot;end&amp;quot;&lt;/code&gt; 可以跳过强制新手引导。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;验证结果：登录、建号、教学战斗、主城、仓库全链路跑通。一款死了七年的网游，在本地活了过来。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;五、转折：一份现成的离线包&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;故事到这里有个转折：又拿到一份别人做好的&amp;quot;离线版&amp;quot;APK。对这种包，正确姿势不是从头分析，而是&lt;strong&gt;先 diff 文件清单&lt;/strong&gt;：&lt;/p&gt;&lt;pre style=&quot;background: rgb(246, 248, 250); padding: 12px; border-radius: 6px; overflow-x: auto; font-size: 13px; color: rgb(51, 51, 51);&quot;&gt;find&amp;nbsp;assets/src&amp;nbsp;-type&amp;nbsp;f&amp;nbsp;|&amp;nbsp;sort&amp;nbsp;&amp;gt;&amp;nbsp;new.txt
diff&amp;nbsp;old.txt&amp;nbsp;new.txt
#&amp;nbsp;→&amp;nbsp;多出&amp;nbsp;13&amp;nbsp;个文件，全在&amp;nbsp;offline/&amp;nbsp;目录，且是明文&lt;/pre&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;读下来发现是一套相当工整的实现：它在场景启动前劫持了 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;system&lt;/code&gt; 模块的全部设备/渠道方法，替换了 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;network/http_manager.lua&lt;/code&gt;，把所有 HTTP 请求转进同进程的 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;offline/server.lua&lt;/code&gt;——一个 300 多行的&amp;quot;进程内游戏服务器&amp;quot;，读写本地 JSON 存档，带原子提交和备份。Lua 异常全部被 xpcall 接住写进 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;offline_error.log&lt;/code&gt;。这个细节后面排查闪退时帮了大忙：错误日志为空，直接证明崩溃不在脚本层。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;六、改存档与造兑换码&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;离线包的存档是 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;/data/data/&amp;lt;包名&amp;gt;/files/gundam_offline_save.json&lt;/code&gt;。root 模拟器上直接拉出来用 Python 改：VIP、等级、改造、潜能、关卡星级、每日次数，都是一目了然的字段。唯一要注意的是重装应用后 uid 会变，push 回去必须 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;chown&lt;/code&gt; 回新 uid，否则游戏读不到。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;更有意思的是兑换码。游戏原本就有 CDKey 系统（主城 → 头像 → 兑换码按钮），离线包里也实现了处理器。往里面加自己的码只需要几行 Lua：&lt;/p&gt;&lt;pre style=&quot;background: rgb(246, 248, 250); padding: 12px; border-radius: 6px; overflow-x: auto; font-size: 13px; color: rgb(51, 51, 51);&quot;&gt;if&amp;nbsp;code==&amp;#39;VIP666&amp;#39;&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.player.vip&amp;nbsp;=&amp;nbsp;math.max(n(s.player.vip),&amp;nbsp;10)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;r.csSyncMap&amp;nbsp;=&amp;nbsp;{PlayerOut={vip=s.player.vip}}&amp;nbsp;&amp;nbsp;--&amp;nbsp;客户端即时刷新
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;r
end&lt;/pre&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;两个细节：失败提示要复用客户端已有错误码的文案（14001=码不存在、14006=已使用过），自定义 message 客户端根本不显示；通关类的码要&amp;quot;只补未通关的关卡&amp;quot;，避免覆盖玩家已有星级。最终交付了四个码：VIP666（VIP10）、SHUX666（等级/改造/潜能满配+百万资源）、TG666（直接通关前 10 关）、GD666（三合一），全部实测可用。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;七、最难的部分：概率性闪退&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;离线包有个遗留问题：某些关卡会闪退，时闪时不闪。这是整个项目里最像侦探工作的一段。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;&lt;strong&gt;第一步，取证。&lt;/strong&gt;常规 logcat 抓不到现场，就写了个持续监控脚本挂在 logcat 上，维护一个&amp;quot;崩前 40 行&amp;quot;的环形缓冲，SIGSEGV 一出现就落盘。配合 root 从 &lt;code style=&quot;background: rgb(246, 248, 250); padding: 1px 5px; border-radius: 3px;&quot;&gt;/data/tombstones/&lt;/code&gt; 拉 tombstone，凑齐了证据链：&lt;/p&gt;&lt;table width=&quot;860&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;th style=&quot;border-color: rgb(221, 221, 221); padding: 6px 10px; font-size: 14px; text-align: left; background: rgb(240, 244, 248);&quot;&gt;证据&lt;/th&gt;&lt;th style=&quot;border-color: rgb(221, 221, 221); padding: 6px 10px; font-size: 14px; text-align: left; background: rgb(240, 244, 248);&quot;&gt;推论&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;offline_error.log 为空&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;不是 Lua 层错误&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;signal 11 空指针，线程名 GLThread，PC 落在转译层代码区&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;x86 模拟器上 ARM 转译层的渲染崩溃&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;同一动画 7 次安全加载、7 次出现在崩溃前&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;概率性问题，&amp;quot;拉黑特定资源&amp;quot;方案否决&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;两个包的资源 MD5 完全一致&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;排除资源损坏&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;崩溃时内存映射已达 0xffffdfff（4GB 顶满），2301 个映射&lt;/td&gt;&lt;td style=&quot;padding: 6px 10px; font-size: 14px;&quot;&gt;32 位地址空间耗尽是诱因&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;&lt;strong&gt;结论：&lt;/strong&gt;2015 年的 32 位游戏 + 大量 Cocos Studio 骨骼动画图集，在 x86 模拟器的转译层上执行，地址空间被挤满后 GL 分配拿到空指针，老引擎不判空直接崩。真机上反而不会发生——转译层是模拟器特有的。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;&lt;strong&gt;第二步，缓解。&lt;/strong&gt;根因在环境层修不掉，就打组合拳把概率压下来：每场战斗的敌人统一为同一机体（单套骨骼动画）、上限 3 台；启动时强制低画质（RGBA4444，纹理内存减半）；最后在模拟器上跑一个 root 看门狗——进程死亡 2 秒内自动重启，战斗状态有持久化、自动恢复到崩溃的那一场。修复前同类战斗约 50% 崩溃率，之后连续压测 6 场零崩溃。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;八、方法论：REA 的三段式闭环&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;回头看，这次的项目之所以顺，是因为每一步都踩在 REA playbook 已经验证过的判据上。REA 的核心是一个三段式闭环：&lt;/p&gt;&lt;blockquote style=&quot;border-left: 4px solid rgb(203, 213, 224); margin: 1em 0px; padding: 2px 14px; color: rgb(85, 85, 85); background: rgb(250, 250, 250); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;&lt;strong&gt;① 指纹识别定路线&lt;/strong&gt;（引擎/壳/容器一张对照表，前五分钟决定后面五小时）→ &lt;strong&gt;② 通用脚本组开路&lt;/strong&gt;（字符串提取、上下文检索、批量解密、文件清单 diff——全是&amp;quot;改一行 root 就能跑&amp;quot;的单文件 Python 脚本）→ &lt;strong&gt;③ 证据驱动的深挖&lt;/strong&gt;（hook、tombstone、日志相关性，先建证据链再动手）&lt;/blockquote&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;本项目的完整流水线就是这三段的具体化：&lt;/p&gt;&lt;blockquote style=&quot;border-left: 4px solid rgb(203, 213, 224); margin: 1em 0px; padding: 2px 14px; color: rgb(85, 85, 85); background: rgb(250, 250, 250); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;&lt;strong&gt;指纹定引擎 → 字符串区挖密钥 → 明文 grep 还原逻辑 → 对新包先 diff 再通读 → 崩溃用 tombstone + 日志相关性说话&lt;/strong&gt;&lt;/blockquote&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;几条个人经验：&lt;/p&gt;&lt;ul style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;解包后的前五分钟决定后面五小时——指纹对了，后面全是套路；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;密钥、签名、配置这类字符串常量不用逆向二进制，它们总在 so 的字符串区里抱团出现；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对&amp;quot;别人改过的包&amp;quot;，diff 文件清单是最快的理解方式；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;概率性崩溃一定要先建证据链再动手，黑名单式的直觉方案（拉黑 war_131）就被数据直接否决过；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;修不掉的环境问题，把&amp;quot;降低概率 + 快速自动恢复&amp;quot;做扎实，体验上等于修好了。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(43, 108, 176); padding-left: 10px; margin-top: 2em; color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; white-space: normal;&quot;&gt;尾声&lt;/h2&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;最终的交付物是一个 220MB 的离线 APK：VIP/属性/通关进度可调，内置自助兑换码，模拟器上带自动复活。一款停服七年的游戏，现在拔掉网线也能从建号玩到主城。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;项目收尾时，整个流程被写回了 REA 的 playbook 库（《Cocos Lua 网游 APK 本地化》篇，与前两篇并列）：XXTEA 长度藏在密文末尾、LDPlayer 连宿主要用局域网 IP、重装后存档要 chown 回新 uid、兑换码失败提示要复用客户端错误码、概率性崩溃的三层缓解组合……下次再遇到同类目标，这些坑就可以直接跳过了。工具会过时，但&lt;strong&gt;带着判据的流程沉淀&lt;/strong&gt;不会——这大概就是维护一套 REA 这种&amp;quot;逆向助手&amp;quot;最大的意义。&lt;/p&gt;&lt;p style=&quot;color: rgb(51, 51, 51); font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;PingFang SC&amp;quot;, sans-serif; font-size: medium; white-space: normal;&quot;&gt;最后是老生常谈但必须说的：这类操作属于对已停运作品的学习研究与技术存档，不触碰支付、不复原服务器数据、不分发原始资源。游戏代码与美术的版权归原厂商所有。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 26 Oct 2026 08:02:25 +0800</pubDate></item><item><title>技术人员在家办公被吵怎么办？小县城个人公司改善办公条件：租还是买？实用分析</title><link>https://www.webgou.info/?id=723</link><description>&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;作为一名技术人员，自己开个人公司接业务，需要同时兼顾技术开发、商务洽谈、产品打磨和售后服务。当前业务还不盈利，日常在家里办公，却因为家里人多吵闹，严重影响专注力和工作效率。小县城环境下，租一套小公寓大概每月1000元左右，买一套大概需要30万左右。面对这样的情况，究竟该如何改善办公条件？是继续在家硬扛，还是租，还是买？今天结合实际成本和业务阶段，做一个务实分析。&lt;/p&gt;&lt;h3 class=&quot;mt-6 mb-2 font-semibold text-xl&quot; data-streamdown=&quot;heading-3&quot; style=&quot;box-sizing: border-box; margin: 0px 0px calc(8px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); font-size: inherit; --tw-space-y-reverse: 0; margin-block: 0px 16px; --tw-font-weight: 600; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;一、当前痛点：噪音对技术人员的影响有多大？&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;在家办公看似省钱，但对技术人员来说，噪音的隐性成本很高：&lt;/p&gt;&lt;ul class=&quot;list-disc list-outside whitespace-normal ps-6 marker:text-secondary list-paddingleft-2&quot; data-streamdown=&quot;unordered-list&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;写代码、调试、设计方案等需要深度专注的工作，容易被频繁打断。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;客户电话、商务沟通、售后对接时，环境嘈杂会显得不专业。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;长期下来容易疲劳、拖延，甚至直接导致丢单或延期。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;研究表明，噪音会显著降低认知效率和专注力。哪怕每周因此多损失几小时有效工作时间，或一年因此少接一单，损失都可能远超租金。对于还在起步、需要快速验证业务的个人公司来说，专注环境往往比省下的租金更值钱。&lt;/p&gt;&lt;h3 class=&quot;mt-6 mb-2 font-semibold text-xl&quot; data-streamdown=&quot;heading-3&quot; style=&quot;box-sizing: border-box; margin: 0px 0px calc(8px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); font-size: inherit; --tw-space-y-reverse: 0; margin-block: 0px 16px; --tw-font-weight: 600; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;二、三种方案对比&lt;/h3&gt;&lt;div class=&quot;my-4 flex flex-col gap-2 rounded-lg border border-border bg-sidebar p-2&quot; data-streamdown=&quot;table-wrapper&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --x-radius-m: 1.8; corner-shape: squircle; --tw-space-y-reverse: 0; margin-block: 0px 16px; display: flex; flex-direction: column; gap: calc(8px); border-radius: 43.2px; background-color: rgb(255, 255, 255); color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal;&quot;&gt;&lt;div class=&quot;border-collapse overflow-x-auto overflow-y-auto rounded-md border border-border bg-background&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 1px solid rgba(0, 0, 0, 0.15); --x-radius-m: 1.8; corner-shape: squircle; overflow: auto; border-radius: 28.8px; max-height: 300px;&quot;&gt;&lt;table class=&quot;w-full divide-y divide-border&quot; data-streamdown=&quot;table&quot; width=&quot;734&quot;&gt;&lt;thead class=&quot;bg-muted/80&quot; data-streamdown=&quot;table-header&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;&gt;&lt;tr class=&quot;border-border firstRow&quot; data-streamdown=&quot;table-row&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;&gt;&lt;th class=&quot;whitespace-nowrap px-4 py-2 text-left font-semibold text-sm&quot; data-streamdown=&quot;table-header-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px); text-align: left; --tw-font-weight: 600; white-space: nowrap;&quot;&gt;方案&lt;/th&gt;&lt;th class=&quot;whitespace-nowrap px-4 py-2 text-left font-semibold text-sm&quot; data-streamdown=&quot;table-header-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px); text-align: left; --tw-font-weight: 600; white-space: nowrap;&quot;&gt;月成本（约）&lt;/th&gt;&lt;th class=&quot;whitespace-nowrap px-4 py-2 text-left font-semibold text-sm&quot; data-streamdown=&quot;table-header-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px); text-align: left; --tw-font-weight: 600; white-space: nowrap;&quot;&gt;一次性投入&lt;/th&gt;&lt;th class=&quot;whitespace-nowrap px-4 py-2 text-left font-semibold text-sm&quot; data-streamdown=&quot;table-header-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px); text-align: left; --tw-font-weight: 600; white-space: nowrap;&quot;&gt;灵活性&lt;/th&gt;&lt;th class=&quot;whitespace-nowrap px-4 py-2 text-left font-semibold text-sm&quot; data-streamdown=&quot;table-header-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px); text-align: left; --tw-font-weight: 600; white-space: nowrap;&quot;&gt;适合当前阶段？&lt;/th&gt;&lt;th class=&quot;whitespace-nowrap px-4 py-2 text-left font-semibold text-sm&quot; data-streamdown=&quot;table-header-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px); text-align: left; --tw-font-weight: 600; white-space: nowrap;&quot;&gt;主要风险&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody class=&quot;divide-y divide-border&quot; data-streamdown=&quot;table-body&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;&gt;&lt;tr class=&quot;border-border&quot; data-streamdown=&quot;table-row&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;继续在家 + 低成本改善&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;0～几百元&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;低&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;最高&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;可先试&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;干扰可能持续存在&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;border-border&quot; data-streamdown=&quot;table-row&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;租小公寓当办公室&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;1000 + 水电物业（约1200～1800）&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;低（押金+基础家具）&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;高&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;&lt;span class=&quot;font-semibold&quot; data-streamdown=&quot;strong&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-font-weight: 600; font-weight: 600;&quot;&gt;最推荐&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;固定支出，不盈利时有压力&lt;/td&gt;&lt;/tr&gt;&lt;tr class=&quot;border-border&quot; data-streamdown=&quot;table-row&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;买公寓当办公室&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;月供或机会成本&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;30万左右&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;低&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;不推荐&lt;/td&gt;&lt;td class=&quot;px-4 py-2 text-sm&quot; data-streamdown=&quot;table-cell&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border-width: 0px; border-color: rgba(0, 0, 0, 0.15); padding-inline: calc(16px); padding-block: calc(8px);&quot;&gt;资金锁死、小县城流动性差&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;h3 class=&quot;mt-6 mb-2 font-semibold text-xl&quot; data-streamdown=&quot;heading-3&quot; style=&quot;box-sizing: border-box; margin: 0px 0px calc(8px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); font-size: inherit; --tw-space-y-reverse: 0; margin-block: 0px 16px; --tw-font-weight: 600; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;三、财务测算：租和买到底差多少？&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;以小县城实际价格为例：&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;span class=&quot;font-semibold&quot; data-streamdown=&quot;strong&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-font-weight: 600; font-weight: 600;&quot;&gt;租的成本&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;/&gt;每月1000元房租，加上水电、物业等，实际约1200～1800元/月，一年下来约1.5万～2.2万元。&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;span class=&quot;font-semibold&quot; data-streamdown=&quot;strong&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-font-weight: 600; font-weight: 600;&quot;&gt;买的成本&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;/&gt;30万本金如果拿去稳健理财或用于业务投入，按4%～5%年化计算，机会成本一年约1.2万～1.5万元，再加上持有成本。表面看和租金差不多，但流动性差很多。&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;更关键的是：你现在还不盈利。钱应该优先投入到能直接带来订单的地方（获客、产品迭代、交付能力），而不是锁死在固定资产里。小县城房产近两年分化明显，很多地方供应过剩、流动性差、租金回报率低（常见1%～2%），增值预期并不乐观。&lt;/p&gt;&lt;h3 class=&quot;mt-6 mb-2 font-semibold text-xl&quot; data-streamdown=&quot;heading-3&quot; style=&quot;box-sizing: border-box; margin: 0px 0px calc(8px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); font-size: inherit; --tw-space-y-reverse: 0; margin-block: 0px 16px; --tw-font-weight: 600; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;四、实操建议（按优先级）&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;span class=&quot;font-semibold&quot; data-streamdown=&quot;strong&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-font-weight: 600; font-weight: 600;&quot;&gt;1. 先低成本改善家里（试1～2周）&lt;/span&gt;&lt;br style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15);&quot;/&gt;购买主动降噪耳机、明确工作时段规则、尽量使用独立房间并关门。如果仍然严重被干扰，再进入下一步。&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;span class=&quot;font-semibold&quot; data-streamdown=&quot;strong&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-font-weight: 600; font-weight: 600;&quot;&gt;2. 短期租小公寓测试（强烈推荐）&lt;/span&gt;&lt;/p&gt;&lt;ul class=&quot;list-disc list-outside whitespace-normal ps-6 marker:text-secondary list-paddingleft-2&quot; data-streamdown=&quot;unordered-list&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;选择安静小区的小户型即可。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;优先签短租或灵活租约，验证效率是否明显提升。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;主要用于专注开发、商务通话和售后对接。客户来访可以约外面咖啡店。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;同时确认本地政策：很多小县城允许住宅作为注册地址（需居委会/物业/邻居同意证明），技术服务类业务通常相对好办。不确定可先咨询当地市场监管局。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;span class=&quot;font-semibold&quot; data-streamdown=&quot;strong&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-font-weight: 600; font-weight: 600;&quot;&gt;3. 其他低成本备选&lt;/span&gt;&lt;/p&gt;&lt;ul class=&quot;list-disc list-outside whitespace-normal ps-6 marker:text-secondary list-paddingleft-2&quot; data-streamdown=&quot;unordered-list&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;如果县城有共享办公空间，可按工位或灵活方式使用。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;使用虚拟地址挂靠（仅用于注册）+ 自己找安静地方工作。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;等业务稳定产生持续现金流后，再考虑长期租或买。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 class=&quot;mt-6 mb-2 font-semibold text-xl&quot; data-streamdown=&quot;heading-3&quot; style=&quot;box-sizing: border-box; margin: 0px 0px calc(8px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); font-size: inherit; --tw-space-y-reverse: 0; margin-block: 0px 16px; --tw-font-weight: 600; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;五、决策原则总结&lt;/h3&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;不盈利阶段，固定成本越低越好。办公空间是工具，不是面子工程。能明显提升专注度和专业度就值得投入，否则优先把钱花在能直接产生订单的地方。&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;&lt;span class=&quot;font-semibold&quot; data-streamdown=&quot;strong&quot; style=&quot;box-sizing: border-box; margin: 0px; padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-font-weight: 600; font-weight: 600;&quot;&gt;现阶段最优路径：先租，验证效率提升和业务改善；现金流稳定、业务可预期后再考虑买。&lt;/span&gt; 这是风险最低、最务实的做法。&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; margin: 0px 0px calc(12px); padding: 0px; border: 0px solid rgba(0, 0, 0, 0.15); --tw-space-y-reverse: 0; margin-block: 0px 16px; color: rgb(15, 20, 25); font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Helvetica, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;, &amp;quot;Twemoji Mozilla&amp;quot;, sans-serif; font-size: 15px; white-space: normal; background-color: rgb(255, 255, 255);&quot;&gt;如果你也是技术人员在家办公被吵、个人公司起步阶段，欢迎在评论区交流你的实际做法和当地租金/房价情况。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 26 Oct 2026 06:56:34 +0800</pubDate></item><item><title>CowAgent 框架全解：从一条消息的旅程，看懂 chatgpt-on-wechat 的架构设计</title><link>https://www.webgou.info/?id=722</link><description>&lt;div class=&quot;cow-article&quot;&gt;&lt;h1&gt;CowAgent 框架全解：从一条消息的旅程，看懂 chatgpt-on-wechat 的架构设计&lt;/h1&gt;&lt;blockquote&gt;基于 v2.2.1 源码实读（非官方文档转述）。项目原名 &lt;code&gt;chatgpt-on-wechat&lt;/code&gt;，现已更名为 &lt;strong&gt;CowAgent&lt;/strong&gt;，定位也从「微信接入 ChatGPT」演进为一套完整的 &lt;strong&gt;Agent Harness&lt;/strong&gt; 参考实现。&lt;/blockquote&gt;&lt;h2&gt;一、一句话定位&lt;/h2&gt;&lt;p&gt;CowAgent 是一个开源超级 AI 助手框架：消息从十余种渠道进来，由 Agent 内核规划、推理、调用工具与技能，再把结果发回原渠道，可以 7×24 跑在个人电脑或服务器上，接入任意主流大模型。&lt;/p&gt;&lt;p&gt;它的工程价值在于：把「大模型 API + IM 渠道」这个看似简单的组合，做成了&lt;strong&gt;层与层彻底解耦、每层可独立扩展&lt;/strong&gt;的框架。&lt;/p&gt;&lt;h2&gt;二、整体分层架构&lt;/h2&gt;&lt;p&gt;整个工程只有五层，层与层之间只靠 &lt;code&gt;Context&lt;/code&gt;（入）和 &lt;code&gt;Reply&lt;/code&gt;（出）两个对象传递，没有横向 import：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;渠道层 channel/&lt;/strong&gt;：12+ 渠道。Web 控制台（默认端口 9899）是默认渠道；其余覆盖微信、企业微信、飞书、钉钉、QQ、Telegram、Slack、Discord、公众号、微信客服，外加 Electron 桌面端。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;桥接层 bridge/&lt;/strong&gt;：&lt;code&gt;Bridge&lt;/code&gt; 是单例门面，同时保留旧 bot / voice / translate 工厂；&lt;code&gt;AgentBridge&lt;/code&gt; 负责 create_agent / agent_reply，&lt;code&gt;AgentInitializer&lt;/code&gt; 负责组装运行时。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent 运行时 agent/protocol/&lt;/strong&gt;：Agent 容器（system prompt + 工具表）、&lt;code&gt;AgentStreamExecutor&lt;/code&gt;（tool-call 主循环）、cancel / steer 注册表。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;能力层&lt;/strong&gt;：工具 agent/tools/、技能 agent/skills/、模型 models/。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;状态层&lt;/strong&gt;：&lt;code&gt;common/state_dir&lt;/code&gt; 定义的 ~/cow 工作区契约、SQLite 会话历史、agent/memory 三层记忆。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;这个设计解释了为什么 12 渠道 × 18 模型能自由组合——&lt;strong&gt;因为任何一层都不知道其他层的存在&lt;/strong&gt;。&lt;/p&gt;&lt;h2&gt;三、一条消息的完整旅程&lt;/h2&gt;&lt;ol class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;消息进入 &lt;code&gt;ChatChannel&lt;/code&gt; 子类，先做语音转文本、媒体下载缓存，插件可在此前置拦截（godcmd 管理指令、keyword 关键词等）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;_compose_context&lt;/code&gt; 判定私聊/群聊、群白名单、@检查，组装成 Context。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;produce&lt;/code&gt; 丢进会话队列——&lt;strong&gt;同一 session 严格串行&lt;/strong&gt;，避免并发回复错乱。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Bridge 取出该 session 的持久会话历史，调用 &lt;code&gt;agent_reply&lt;/code&gt; 进入 Agent 运行时。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;run_stream&lt;/code&gt; 主循环里 LLM 与工具交替执行（下节展开）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;过程中以流式事件（delta / thinking / 工具卡片）回推渠道；结束后会话落库、记忆摘要入队。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;_decorate_reply&lt;/code&gt; 做装饰（Markdown 围栏、@ 前缀、长文分片），&lt;code&gt;_send_reply&lt;/code&gt; 发回用户。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;运行中用户随时可以 &lt;code&gt;/cancel&lt;/code&gt; 打断、&lt;code&gt;/steer&lt;/code&gt; 追加指令——靠 contextvars 穿透线程的注册表实现，不用等到本轮结束。&lt;/p&gt;&lt;h2&gt;四、Agent 内核：tool-call 主循环&lt;/h2&gt;&lt;p&gt;&lt;code&gt;agent/protocol/agent_stream.py&lt;/code&gt; 的 &lt;code&gt;run_stream&lt;/code&gt; 是整个框架的「心脏」：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;进循环前&lt;strong&gt;一次性裁剪上下文&lt;/strong&gt;，裁剪点保证不留孤儿 tool_use（否则 API 直接报错）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;每轮先检查 cancel 注册表（轮间到达的打断在此短路），再把 steer 指令并入本轮消息。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;finish_reason&lt;/code&gt; 为 tool_calls 时解析参数——&lt;code&gt;json_repair&lt;/code&gt; 修复畸形 JSON，length 截断则提示模型重发；多工具且 &lt;code&gt;parallel_safe&lt;/code&gt; 时用线程池并行执行。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;循环外还有三个韧性机制：&lt;strong&gt;模型 fallback 链&lt;/strong&gt;（主模型耗尽重试后按链切换，且是粘性的，本轮不再弹回）、&lt;strong&gt;工具熔断&lt;/strong&gt;（同名同参连续失败即熔断，防死循环烧 token）、&lt;strong&gt;thinking 流剥离&lt;/strong&gt;（跨 chunk 半截标签有缓冲）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;轮数上限默认 30（&lt;code&gt;agent_max_turns&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;五、记忆：三层架构 + Deep Dream&lt;/h2&gt;&lt;p&gt;记忆是 CowAgent 最有辨识度的设计：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;短期层&lt;/strong&gt;：当前上下文。超预算时按「完整轮」裁剪，被丢弃的内容压缩成摘要回填，绝不留下断链。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;中期层&lt;/strong&gt;：daily 文件。&lt;code&gt;MemoryFlushManager&lt;/code&gt; 每日定时把被丢弃消息用 LLM 摘要成「当日记录」，追写 &lt;code&gt;memory/YYYY-MM-DD.md&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;长期层&lt;/strong&gt;：MEMORY.md。夜间 &lt;strong&gt;Deep Dream&lt;/strong&gt; 把现有长期条目 + 当日日记蒸馏精炼，回写长期层，另产出一份「梦境日记」。MEMORY.md 每次对话都注入 system prompt，所以必须保持精炼。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;检索&lt;/strong&gt;：关键词 FTS + 向量混合，未配 embedding 时自动降级纯关键词。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;三层写入全部自动发生，用户不需要「保存记忆」这个动作。&lt;/p&gt;&lt;h2&gt;六、能力层：工具、技能与模型&lt;/h2&gt;&lt;h3&gt;工具（原子能力）&lt;/h3&gt;&lt;p&gt;文件读写（read / write / edit / ls）、终端 bash、浏览器自动化、调度器、记忆检索、web 搜索、视觉等十余个内置工具；通过 &lt;strong&gt;MCP 协议&lt;/strong&gt;（一份 mcp.json，支持 stdio / SSE、热重载）接入整个开放生态。&lt;/p&gt;&lt;h3&gt;技能（工作流）&lt;/h3&gt;&lt;p&gt;&lt;code&gt;SKILL.md + scripts/ + resources/&lt;/code&gt; 构成一个技能目录，可从 Skill Hub 市场、GitHub、ClawHub、URL 一键安装，也能在对话里用 &lt;code&gt;skill-creator&lt;/code&gt; 让 Agent 自己生成。加载时校验 frontmatter（name / description / emoji / requires），requires 不满足则不注入；自定义技能优先级高于内置，同名覆盖。&lt;/p&gt;&lt;h3&gt;模型（provider 工厂）&lt;/h3&gt;&lt;p&gt;DeepSeek、Claude、OpenAI、Gemini、MiniMax、GLM、Qwen、Kimi、Doubao、文心、MiMo、LinkAI 及自定义兼容接口。&lt;strong&gt;Chat / 视觉 / 画图 / ASR / TTS / Embedding 可分别路由到不同厂商&lt;/strong&gt;，全部在 Web 控制台里切换，不改配置文件。&lt;/p&gt;&lt;h2&gt;七、多 Agent 与自进化&lt;/h2&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;多 Agent&lt;/strong&gt;：&lt;code&gt;AgentRouter + AgentRegistry&lt;/code&gt; 管理团队花名册（agents/team.json）。&lt;strong&gt;正式队友&lt;/strong&gt;有独立 workspace 和独立记忆，可在共享会话里被 @ 编排；&lt;strong&gt;sub-agent&lt;/strong&gt; 则是临时执行单元，共享主 Agent 工作区、无独立记忆，用于并行派生。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;自进化&lt;/strong&gt;：后台线程每 60s 扫描活跃会话，空闲 ≥10 分钟且（距上次进化 ≥6 个用户轮 或 上下文超预算 80%）时触发。进化在隔离环境跑一次复盘 Agent：&lt;strong&gt;改进已有技能、跟进未完成任务、回填记忆与知识&lt;/strong&gt;，全程由 backup.py 备份、可回滚。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;八、权限与安全&lt;/h2&gt;&lt;p&gt;会话级三种权限模式：&lt;/p&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;th&gt;模式&lt;/th&gt;&lt;th&gt;行为&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;read-only&lt;/td&gt;&lt;td&gt;拒绝所有写 + bash 只允许白名单只读命令 + 有副作用工具全拒&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;workspace-write&lt;/td&gt;&lt;td&gt;工作目录内自由写；越界写拒；放权文件（MCP 配置 / config / 凭据 / 会话设置）拒&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;full-access&lt;/td&gt;&lt;td&gt;不设限（历史默认）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;bash 命令会解析重定向、rm / mv 越界、提权（尽力而为，非 OS 沙箱）。拒绝时返回 &lt;code&gt;permission_denied&lt;/code&gt; 标记，前端提示用户切换权限而非笼统报错。&lt;/p&gt;&lt;h2&gt;九、状态目录契约（~/cow）&lt;/h2&gt;&lt;p&gt;所有状态收敛到 &lt;code&gt;~/cow&lt;/code&gt; 一个目录，分三类：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;系统共享&lt;/strong&gt;：skills / knowledge / mcp、&lt;code&gt;~/.cow/.env&lt;/code&gt; 密钥、agents/team.json 团队花名册。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;每 Agent 隔离&lt;/strong&gt;：SYSTEM.md / USER.md / AGENT.md / RULE.md、MEMORY.md + memory/、sessions/、tmp/。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;每终端用户&lt;/strong&gt;：画像 / 偏好 / 记忆 / 任务记录。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;设计规则：共享的复制会漂移 → 谁用谁建；每 Agent 的 = 「之所以是不同 Agent」；每用户的 = 关于人而非 Agent 的事实。&lt;/blockquote&gt;&lt;h2&gt;十、配置、启动与部署&lt;/h2&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;配置&lt;/strong&gt;：&lt;code&gt;config.json&lt;/code&gt;（模板 config-template.json），启动后大部分可在 Web 控制台改。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;启动&lt;/strong&gt;：一行安装脚本（Linux/macOS bash、Windows PowerShell、docker compose 三选一），默认 &lt;code&gt;http://localhost:9899&lt;/code&gt; 开 Web 控制台。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLI&lt;/strong&gt;：&lt;code&gt;cow start | stop | restart | status | logs | update | skill install&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;桌面端&lt;/strong&gt;：macOS / Windows 客户端，内置后端开箱即用。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;本机交付&lt;/strong&gt;：仓库根目录的 &lt;code&gt;cow-start.cmd / cow-stop.cmd&lt;/code&gt; 做了就绪轮询、端口占用检测、日志尾部打印，双击即用。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;十一、插件系统&lt;/h2&gt;&lt;p&gt;&lt;code&gt;plugins/&lt;/code&gt; 下是经典插件机制（Event + Plugin 基类，plugin_manager 统一调度），内置 godcmd（管理员）、keyword、role、dungeon、banwords、finish、hello、tool、linkai 等。插件在&lt;strong&gt;渠道层&lt;/strong&gt;前置/后置拦截，与 Agent 层正交——这是从 bot 时代继承下来的扩展面，与 skills 体系并行不悖。&lt;/p&gt;&lt;h2&gt;十二、结语&lt;/h2&gt;&lt;p&gt;CowAgent 的框架价值可以压缩成三句话：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;渠道与模型彻底解耦&lt;/strong&gt;，所以 12 渠道 × 18 模型能自由组合；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent 内核只认 tool-call 循环&lt;/strong&gt;，所以任何能力（工具、技能、MCP、多 Agent）都能长进去；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;状态全部收敛到 ~/cow&lt;/strong&gt;，所以整个助手可以像目录一样备份和迁移。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;延伸阅读：同目录的《CowAgent-技术图解》有 13 张源码级时序 / 流程图，每个环节都标注了对应源码位置，适合对照阅读。&lt;/blockquote&gt;&lt;/div&gt;</description><pubDate>Tue, 20 Oct 2026 17:32:09 +0800</pubDate></item><item><title>中年人失业的出路</title><link>https://www.webgou.info/?id=721</link><description>&lt;p&gt;中年人失业的出路包括但不限于：&lt;/p&gt;&lt;p&gt;1）接手一个路边摊，并利用一些手段和城管搞好关系；&lt;/p&gt;&lt;p&gt;2）搞文字创业，写女频小说；&lt;/p&gt;&lt;p&gt;3）干“铁人三项”（外卖/快递/网约车）,出去跑外卖；&lt;/p&gt;&lt;p&gt;4）找一个生活成本低的三线城市提前退休养老；&lt;/p&gt;&lt;p&gt;5）学习新技能，考了一个A照，找了个国企开考斯特）；&lt;/p&gt;&lt;p&gt;6）干“吉祥三宝”（保安/保洁/保姆），当高端住家保姆；&lt;/p&gt;&lt;p&gt;7）合伙开咨询公司，顺便交社保。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;综上，我们可以看到,人到中年失业，基本上就三条路：其一曰：降低生活成本，其二曰：学习新技能，其三曰：‘铁人三项”或“吉祥三宝”。以上三条路，都伴随着收入下降。&lt;/p&gt;</description><pubDate>Tue, 20 Oct 2026 17:29:53 +0800</pubDate></item><item><title>没有剪辑软件的画布，怎么拿它做短剧和广告？——infinite-canvas 生产流程实战分析</title><link>https://www.webgou.info/?id=720</link><description>&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;上一篇扒了 infinite-canvas 的存储设计，这篇说点更实际的：能不能拿它干活？比如做一部 AI 短剧，或者给产品剪条营销广告。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;先把结论放在前面：&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;可以，但你要接受它的定位——它是一个&amp;quot;分镜工厂&amp;quot;，不是剪辑台。&lt;/strong&gt; 从分镜图到镜头视频这段路它能送你走完，最后拼接成片那一步，还得回剪映或者 Premiere。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; white-space: normal;&quot;&gt;先泼冷水：它没有&amp;quot;短剧模式&amp;quot;&lt;/h2&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;打开工程源码看节点类型，一共就六种：Image、Text、Config、Video、Audio、Group。没有分镜表节点，没有故事板，没有任何带&amp;quot;剧&amp;quot;字的功能。第一眼很容易得出&amp;quot;这工具做不了正经内容&amp;quot;的结论。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;但用一会儿就会发现，它的设计重心不在节点类型，在&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;连线&lt;/strong&gt;。画布上把一个节点连线到另一个节点，连线不是装饰——上游会自动变成下游的生成参考。图片节点连到图片节点，就是图生图的参考图；连到视频节点，就是视频的首帧。整个生产流程是靠连线组织起来的，这跟专业工具里&amp;quot;依赖关系&amp;quot;的概念是一回事，只是被画得更直观。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; white-space: normal;&quot;&gt;两种视频模式，撑起全部玩法&lt;/h2&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;视频生成只提供了两种模式，但够用：&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;frames 模式（默认）&lt;/strong&gt;：连线传给视频节点的参考图，第一张作为 first_frame，第二张作为 last_frame。只连一张，视频就是&amp;quot;从这帧动起来&amp;quot;；连两张，模型在两帧之间插值出一段运动。这个&amp;quot;首尾帧&amp;quot;设计是整条生产线的灵魂，后面会讲为什么。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;reference 模式&lt;/strong&gt;：可以传参考视频和参考音频。做风格迁移、动作续写这类活儿用它。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;参数面上，时长、画面比例（9:16 竖屏当然支持）、分辨率、是否生成音频、去水印，这些开关都有。没有多镜头管理，没有角色库，没有场景库——但素材库（assets）可以沉淀图片，变通着用。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;img class=&quot;ue-image&quot; src=&quot;https://www.webgou.info/zb_users/upload/2026/10/202610051791176672416309.png&quot; title=&quot;production-flow.png&quot; alt=&quot;production-flow.png&quot;/&gt;&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; white-space: normal;&quot;&gt;短剧的完整流程，实测是这样跑的&lt;/h2&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;第一步，角色定妆。&lt;/strong&gt; 文生图出主角定妆图。注意，这张图之后就是你全剧的&amp;quot;角色锚点&amp;quot;，所有后续镜头里的主角，都要靠这张图做参考生成。挑图的时候多花点时间，值得。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;第二步，场景库。&lt;/strong&gt; 每个主要场景文生图一张，同样存下来。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;第三步，逐镜出分镜图。&lt;/strong&gt; 这是保一致性的关键动作：每一镜的图，都用&amp;quot;角色图 + 场景图&amp;quot;连线做参考，走图生图（edit 接口），prompt 里写清楚这一镜的机位、动作、情绪。为什么不直接文生图？因为文生图每一张都在重新掷骰子，你的主角每一镜都会换脸。参考图传递才是确定性的来源。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;第四步，图生视频。&lt;/strong&gt; 每个镜头建一个视频节点，分镜图连线进去，frames 模式。这里有个进阶技巧：&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;把上一镜的尾帧画面（截个图或者直接用下一镜的分镜图）同时作为本镜的 last_frame 传进去&lt;/strong&gt;，两帧之间插值，镜头衔接就顺了。运镜指令——推、拉、摇、移——写进视频的 prompt，不要写进图片的 prompt，这两层提示词管的事情不一样。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;第五步，音频。&lt;/strong&gt; 台词走 TTS 生成，配乐也用它。有个坑要记：音频生成只支持 OpenAI 格式的渠道，Gemini 格式渠道会被明确拒绝。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;第六步，成片。&lt;/strong&gt; 按镜下载视频和音频，去剪辑软件里拼接、加字幕、卡点。它没有时间线，这一步没有捷径。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;营销广告是同一套流程换皮：把&amp;quot;角色锚点&amp;quot;换成&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;产品图&lt;/strong&gt;（产品细节的一致性比人脸更较真，务必全程参考图传递），分镜围绕卖点展开，首尾帧衔接做产品转场，最后压上口播和 BGM。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; white-space: normal;&quot;&gt;嫌逐镜点太慢？有 Agent 通道&lt;/h2&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;这个工程带了个挺有意思的东西：canvas-agent。本机跑一个 &lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;npx @basketikun/canvas-agent&lt;/code&gt;，它会桥接你电脑上的 Codex 或者 Claude Code，然后在网页右上角填地址和 token 连接。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;连上之后，Agent 拿到一组画布操作工具：批量建节点（add_node）、连线（connect_nodes）、触发生成（run_generation），一次 apply 一串 ops。实际用法就是：20 个分镜，让 Agent 一口气把节点全铺出来、连好线、批量提交生成，你只需要回来看结果，哪个镜头崩了再单独回画布上重roll。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;批量铺场用 Agent，单镜精调用画布——两条通道各干各的活，这是这套工具效率最高的姿势。&lt;/p&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; white-space: normal;&quot;&gt;想做好视频，这几条是从工程机制里推出来的&lt;/h2&gt;&lt;ol style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;首尾帧衔接保连贯。&lt;/strong&gt; 模型视频本质是帧间插值，镜头之间的连贯性不靠运气，靠&amp;quot;尾帧 = 下镜首帧&amp;quot;这个纪律。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;参考图永远连线传入，别在 prompt 里重述角色。&lt;/strong&gt; &amp;quot;一个穿红裙子的长发女孩&amp;quot;这种描述，十次生成能出十个女孩。图才是唯一可靠的锚。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;竖屏比例在图片生成期就锁定。&lt;/strong&gt; 视频 size 参数只是画布尺寸，源图比例不对，后面全歪。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;单镜单动作，5~10 秒封顶。&lt;/strong&gt; 一个 prompt 塞三个动作必崩，这是插值模型的天性，不是你能调好的。复杂调度拆镜头。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;认清它的边界。&lt;/strong&gt; 管生成不管剪辑。拼接、字幕、节奏，最后都要落回专业剪辑工具。把它的产出当成剪辑软件的素材，而不是成片。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; white-space: normal;&quot;&gt;写在最后&lt;/h2&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;这套工具做短剧和广告的思路，其实和传统影视流程暗暗对上了：定妆照、分镜脚本、逐镜拍摄、后期剪辑——只是每一环都被压进了&amp;quot;连线 + 生成&amp;quot;这个动作里。它把 AI 视频生产里最难的两件事，角色一致性和镜头连贯性，分别交给了&amp;quot;参考图传递&amp;quot;和&amp;quot;首尾帧插值&amp;quot;两个机制来解决，剩下的交给你的分镜功底。&lt;/p&gt;&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; white-space: normal;&quot;&gt;工具不欠你一部好片子。分镜想清楚了，它才是个好工厂；分镜没想清楚，它只是个快速出废片的工厂。&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Mon, 05 Oct 2026 12:56:47 +0800</pubDate></item><item><title>没有服务器的画布，数据到底存在哪？——扒一扒 infinite-canvas 的存储设计</title><link>https://www.webgou.info/?id=719</link><description>&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    最近在用 infinite-canvas 这个开源项目（就是 Linux.do 社区比较火的那款无限画布工具， basketikun/infinite-canvas）。用着用着产生了一个疑问：它明明没有自己的后端服务器，模型 API 也是浏览器直连的，那我生成的图片、视频、还有画布上的那堆节点，到底存在哪？会不会哪天一刷新全没了？
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    带着这个疑问我把源码翻了一遍，把它的存储机制彻底搞清楚了。结论先说：&lt;strong style=&quot;color: rgb(192, 57, 43);&quot;&gt;所有东西都在你浏览器的 IndexedDB 里，浏览器就是它唯一的数据库。&lt;/strong&gt;
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;
    三个库，各管一摊
&lt;/h2&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    打开 DevTools 的 Application 面板，IndexedDB 下能看到一个叫&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;infinite-canvas&lt;/code&gt;&amp;nbsp;的库，里面分成三个 store，由 localforage 统一管理：
&lt;/p&gt;
&lt;ul style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot; class=&quot; list-paddingleft-2&quot;&gt;
    &lt;li&gt;
        &lt;p&gt;
            &lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;app_state&lt;/code&gt;：画布工程本体。节点、连线、会话记录，全是 JSON，通过 zustand 的 persist 中间件写进来。
        &lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;
            &lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;image_files&lt;/code&gt;：生成的图片 Blob，外加一份缩略图缓存。
        &lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;
            &lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;media_files&lt;/code&gt;：视频和音频 Blob。
        &lt;/p&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    配置（API Key、模型选择）也在这套体系里，zustand persist 挂了六个 store，localforage 挂了就降到 localStorage。所以理论上你把浏览器数据一清，这个工具就回到了出厂状态。
&lt;/p&gt;

&lt;svg viewBox=&quot;0 0 680 520&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; font-family=&quot;system-ui, sans-serif&quot;&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
      &lt;path d=&quot;M0,0 L10,5 L0,10 z&quot; fill=&quot;#8b8fa3&quot;/&gt;
    &lt;/marker&gt;
  &lt;/defs&gt;
  &lt;rect width=&quot;680&quot; height=&quot;520&quot; fill=&quot;#16171d&quot;/&gt;
  &lt;style&gt;
    .t1{fill:#e8e9f0;font-size:13px;font-weight:600}
    .t2{fill:#9a9db1;font-size:11px}
    .t3{fill:#c8cad8;font-size:10.5px}
    .box{fill:#1f2130;stroke:#33364a;stroke-width:1;rx:8}
    .hl{stroke:#4f8ef7;stroke-width:1.4}
    .grn{stroke:#3fae6a}
    .org{stroke:#c98a2d}
    .lbl{fill:#6b6f85;font-size:10px;letter-spacing:1px}
  &lt;/style&gt;

  &lt;text x=&quot;24&quot; y=&quot;30&quot; class=&quot;lbl&quot;&gt;生成链路（浏览器内闭环，无服务器）&lt;/text&gt;

  &lt;!-- 用户配置 --&gt;
  &lt;rect x=&quot;24&quot; y=&quot;46&quot; width=&quot;180&quot; height=&quot;58&quot; rx=&quot;8&quot; class=&quot;box&quot;/&gt;
  &lt;text x=&quot;40&quot; y=&quot;70&quot; class=&quot;t1&quot;&gt;模型渠道配置&lt;/text&gt;
  &lt;text x=&quot;40&quot; y=&quot;90&quot; class=&quot;t3&quot;&gt;AiConfig: url / key / model&lt;/text&gt;

  &lt;!-- 节点提示词 --&gt;
  &lt;rect x=&quot;24&quot; y=&quot;130&quot; width=&quot;180&quot; height=&quot;58&quot; rx=&quot;8&quot; class=&quot;box&quot;/&gt;
  &lt;text x=&quot;40&quot; y=&quot;154&quot; class=&quot;t1&quot;&gt;画布节点 + 提示词&lt;/text&gt;
  &lt;text x=&quot;40&quot; y=&quot;174&quot; class=&quot;t3&quot;&gt;上游连线 = 参考图/视频&lt;/text&gt;

  &lt;!-- API 调用 --&gt;
  &lt;rect x=&quot;264&quot; y=&quot;46&quot; width=&quot;180&quot; height=&quot;142&quot; rx=&quot;8&quot; class=&quot;box hl&quot;/&gt;
  &lt;text x=&quot;280&quot; y=&quot;70&quot; class=&quot;t1&quot;&gt;直调模型 API&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;92&quot; class=&quot;t3&quot;&gt;图片: requestGeneration /&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;108&quot; class=&quot;t3&quot;&gt;requestEdit (multipart)&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;130&quot; class=&quot;t3&quot;&gt;视频: createVideoTask +&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;146&quot; class=&quot;t3&quot;&gt;pollVideoTask (openai/gemini)&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;168&quot; class=&quot;t3&quot; fill=&quot;#c98a2d&quot;&gt;taskId 存入节点 metadata&lt;/text&gt;

  &lt;!-- 返回 --&gt;
  &lt;rect x=&quot;264&quot; y=&quot;216&quot; width=&quot;180&quot; height=&quot;46&quot; rx=&quot;8&quot; class=&quot;box&quot;/&gt;
  &lt;text x=&quot;280&quot; y=&quot;236&quot; class=&quot;t1&quot;&gt;返回结果&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;254&quot; class=&quot;t3&quot;&gt;dataUrl / video blob&lt;/text&gt;

  &lt;!-- 落库 --&gt;
  &lt;rect x=&quot;264&quot; y=&quot;290&quot; width=&quot;180&quot; height=&quot;86&quot; rx=&quot;8&quot; class=&quot;box grn&quot;/&gt;
  &lt;text x=&quot;280&quot; y=&quot;312&quot; class=&quot;t1&quot;&gt;落 IndexedDB&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;332&quot; class=&quot;t3&quot;&gt;image:nanoid → image_files&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;348&quot; class=&quot;t3&quot;&gt;video:nanoid → media_files&lt;/text&gt;
  &lt;text x=&quot;280&quot; y=&quot;366&quot; class=&quot;t3&quot;&gt;+ 缩略图 previewStore&lt;/text&gt;

  &lt;!-- 写回节点 --&gt;
  &lt;rect x=&quot;24&quot; y=&quot;290&quot; width=&quot;180&quot; height=&quot;86&quot; rx=&quot;8&quot; class=&quot;box org&quot;/&gt;
  &lt;text x=&quot;40&quot; y=&quot;312&quot; class=&quot;t1&quot;&gt;写回节点 metadata&lt;/text&gt;
  &lt;text x=&quot;40&quot; y=&quot;332&quot; class=&quot;t3&quot;&gt;content = objectURL(临时)&lt;/text&gt;
  &lt;text x=&quot;40&quot; y=&quot;348&quot; class=&quot;t3&quot;&gt;storageKey = 持久键&lt;/text&gt;
  &lt;text x=&quot;40&quot; y=&quot;364&quot; class=&quot;t3&quot;&gt;尺寸/字节/primaryImageId&lt;/text&gt;

  &lt;!-- zustand persist --&gt;
  &lt;rect x=&quot;24&quot; y=&quot;410&quot; width=&quot;420&quot; height=&quot;50&quot; rx=&quot;8&quot; class=&quot;box&quot;/&gt;
  &lt;text x=&quot;40&quot; y=&quot;431&quot; class=&quot;t1&quot;&gt;zustand persist → app_state (IndexedDB)&lt;/text&gt;
  &lt;text x=&quot;40&quot; y=&quot;449&quot; class=&quot;t3&quot;&gt;画布工程 JSON：节点/连线/会话（含 storageKey，不含 objectURL）&lt;/text&gt;

  &lt;!-- hydration --&gt;
  &lt;rect x=&quot;476&quot; y=&quot;410&quot; width=&quot;180&quot; height=&quot;50&quot; rx=&quot;8&quot; class=&quot;box hl&quot;/&gt;
  &lt;text x=&quot;492&quot; y=&quot;431&quot; class=&quot;t1&quot;&gt;刷新后 hydration&lt;/text&gt;
  &lt;text x=&quot;492&quot; y=&quot;449&quot; class=&quot;t3&quot;&gt;按 storageKey 重建 objectURL&lt;/text&gt;

  &lt;!-- arrows --&gt;
  &lt;line x1=&quot;204&quot; y1=&quot;117&quot; x2=&quot;258&quot; y2=&quot;90&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;204&quot; y1=&quot;159&quot; x2=&quot;258&quot; y2=&quot;150&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;354&quot; y1=&quot;188&quot; x2=&quot;354&quot; y2=&quot;210&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;354&quot; y1=&quot;262&quot; x2=&quot;354&quot; y2=&quot;284&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;258&quot; y1=&quot;333&quot; x2=&quot;210&quot; y2=&quot;333&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;114&quot; y1=&quot;376&quot; x2=&quot;114&quot; y2=&quot;404&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;450&quot; y1=&quot;435&quot; x2=&quot;470&quot; y2=&quot;435&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;566&quot; y1=&quot;404&quot; x2=&quot;566&quot; y2=&quot;382&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1.2&quot; marker-end=&quot;url(#arr)&quot;/&gt;
  &lt;line x1=&quot;566&quot; y1=&quot;382&quot; x2=&quot;380&quot; y2=&quot;382&quot; stroke=&quot;#8b8fa3&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4 3&quot;/&gt;

  &lt;text x=&quot;480&quot; y=&quot;378&quot; class=&quot;t2&quot; fill=&quot;#4f8ef7&quot;&gt;重读 Blob&lt;/text&gt;
&lt;/svg&gt;

&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;
    一张图的完整旅程
&lt;/h2&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    看代码最有意思的是&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;services/file-storage.ts&lt;/code&gt;&amp;nbsp;里那个&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;uploadMediaFile&lt;/code&gt;&amp;nbsp;函数。名字叫&amp;quot;上传&amp;quot;，但它根本没有网络请求——就是把 Blob 塞进 IndexedDB，然后&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;URL.createObjectURL&lt;/code&gt;&amp;nbsp;生成一个临时链接。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    真实的生成流程是这样的：你在画布上点生成，前端拿着你在设置里填的 API 地址和 Key，用 axios 直接请求模型接口（文生图或者带参考图的编辑接口）。模型返回一张 base64 的 dataUrl，前端把它转成 Blob，生成一个&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;image:&amp;lt;nanoid&amp;gt;&lt;/code&gt;&amp;nbsp;这样的 key，Blob 落进&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;image_files&lt;/code&gt;，同时把 objectURL 写进节点的 metadata。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    这里有个设计我觉得挺讲究：节点的 metadata 里同时存了两个字段——&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;content&lt;/code&gt;&amp;nbsp;和&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;storageKey&lt;/code&gt;。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    &lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;content&lt;/code&gt;&amp;nbsp;存的是 objectURL，这东西只在当前会话有效。浏览器刷新之后，所有 objectURL 全部失效，哪怕 Blob 还好好躺在 IndexedDB 里，句柄也没了。&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;storageKey&lt;/code&gt;&amp;nbsp;才是持久键，跟着画布 JSON 一起被 zustand persist 存下来。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    于是每次刷新页面，前端都要做一遍&amp;quot;补水&amp;quot;（hydration）：遍历所有节点，拿着&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;storageKey&lt;/code&gt;&amp;nbsp;回 IndexedDB 把 Blob 读出来，重新 createObjectURL，再把新的 URL 写回&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;content&lt;/code&gt;。顺带还干了一件事：老版本节点里直接存 base64 的 dataUrl，会在这次遍历中迁移成 storageKey 形态。base64 直接进 JSON 会让画布文件膨胀得很难看，这个迁移等于做了一次瘦身。
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;
    视频多了一层保险
&lt;/h2&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    图片是同步等结果的，视频不行——视频生成都要几分钟，总不能让用户按着刷新键等。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    infinite-canvas 的做法是任务创建成功后，立刻把 taskId 写进视频节点的 metadata（&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;videoTaskId&lt;/code&gt;&amp;nbsp;和&amp;nbsp;&lt;code style=&quot;background: rgb(242, 243, 245); padding: 2px 6px; border-radius: 4px; font-size: 14.4px;&quot;&gt;videoTaskProvider&lt;/code&gt;&amp;nbsp;两个字段）。因为 metadata 会跟着画布一起持久化，所以你中途刷新页面甚至关掉浏览器，重新打开后前端能认出&amp;quot;这个节点还有个没完成的任务&amp;quot;，接着轮询要结果。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    这是我在这套纯前端架构里看到的唯一一处异步韧性设计。没有任务队列，没有服务端重试，就靠这一条：把 taskId 塞进持久化的节点数据里，剩下的交给轮询。
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;
    连线即引用
&lt;/h2&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    画布上把一个图片节点连线到视频节点，连线不是装饰——上游节点会自动成为下游生成的参考输入。比如视频的 frames 模式，参考图第一张作为 first_frame、第二张作为 last_frame，两图之间插值出视频。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    引用传递时有个细节：发给模型 API 之前，前端要把 storageKey 转回 dataUrl（从 IndexedDB 读 Blob，转 base64）。也就是说同一份图片数据，显示走 objectURL，喂给模型走 dataUrl，持久化靠 storageKey——三种形态各司其职。
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;
    这套设计的边界
&lt;/h2&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    好处显而易见：零部署成本，打开网页就能用，不依赖任何服务器，隐私数据不经过第三方。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    代价也很直白。浏览器就是全部，意味着：
&lt;/p&gt;
&lt;ol style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot; class=&quot; list-paddingleft-2&quot;&gt;
    &lt;li&gt;
        &lt;p&gt;
            清浏览器缓存 = 全部画布和素材蒸发。项目 README 自己也用 CAUTION 标了&amp;quot;不保证历史数据兼容&amp;quot;。
        &lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;
            换设备？IndexedDB 不跟着走。
        &lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
        &lt;p&gt;
            大量视频 Blob 堆在 IndexedDB 里，会碰到浏览器的存储配额。
        &lt;/p&gt;
    &lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    它留了两条退路：一是 WebDAV 同步，配置一个自己的 WebDAV 服务器（坚果云就行），可以把画布、素材、生图/生视频工作台的数据同步过去，带 manifest 和删除日志；二是画布导出，把工程 JSON 和媒体文件打包成一个 zip 下载。
&lt;/p&gt;
&lt;h2 style=&quot;border-left: 4px solid rgb(74, 144, 217); padding-left: 12px; margin-top: 2em; color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; text-wrap-mode: wrap;&quot;&gt;
    写在最后
&lt;/h2&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    看完这套实现，我对&amp;quot;纯前端 AI 工具&amp;quot;的上限有了新的认识。它没有把存储问题甩给用户，而是在浏览器这个沙箱里，用三个 IndexedDB store、storageKey 持久键、刷新后 hydration、taskId 恢复这几招，把一个没有后端的产品做出了七八成的可用性。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    剩下那两成——多设备、数据安全、大文件——它选择交给用户自己解决（WebDAV 或者导出备份）。这个取舍是否合理，取决于你怎么用。如果只是偶尔画画图，无所谓；如果是认真的生产环境，建议把 WebDAV 同步配上，或者养成定期导出的习惯。
&lt;/p&gt;
&lt;p style=&quot;color: rgb(34, 34, 34); font-family: &amp;quot;Microsoft YaHei&amp;quot;, sans-serif; font-size: 16px; text-wrap-mode: wrap;&quot;&gt;
    毕竟，你的&amp;quot;数据库&amp;quot;是浏览器给的那几 GB 配额，别等清缓存的时候才想起来。
&lt;/p&gt;
&lt;p&gt;
    &lt;br/&gt;
&lt;/p&gt;</description><pubDate>Mon, 05 Oct 2026 12:39:00 +0800</pubDate></item><item><title>AI时代，游戏买量还值得做吗？</title><link>https://www.webgou.info/?id=718</link><description>&lt;p&gt;十年前，“买量”还是没人愿意干的脏活；十年后，它成了游戏行业最大的支出项。当投放成本一年涨了 80% 多、素材 48 小时就被抄袭、平台算法夺走定价权，这个行业的天花板和入口，到底在哪？&lt;/p&gt;&lt;h2&gt;开篇：一个被重新回答的问题&lt;/h2&gt;&lt;p&gt;十年前第一次接触游戏买量时，这还是个没人愿意干的脏活。渠道联运是大哥，品牌投放是门面，买量就是去百度搜狗投关键词——谁点进来算谁。&lt;/p&gt;&lt;p&gt;十年过去，买量已经是游戏行业最大的支出项。有数据显示：全球游戏获客总支出 2025 年已达 250 亿美元（AppsFlyer）；国内流水 TOP100 移动游戏的买量成本，在 2025 上半年同比暴涨 86.6%（伽马数据）。&lt;/p&gt;&lt;p&gt;更扎心的是那句行内话：研发团队几十号人吭哧吭哧做一年，不如投放团队一套素材跑三天带来的用户多。&lt;/p&gt;&lt;p&gt;在 AI 时代，这个问题值得重新回答一遍。&lt;/p&gt;&lt;h2&gt;一、什么是买量&lt;/h2&gt;&lt;p&gt;简单说，买量就是&lt;strong&gt;付费获取用户&lt;/strong&gt;。游戏公司在巨量引擎、腾讯广告等平台投放广告素材，用户点击 → 下载 → 注册 → 付费，整个链条可追踪、可归因。&lt;/p&gt;&lt;p&gt;它和传统品牌广告的区别在于：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;品牌广告&lt;/strong&gt;花钱买曝光——一个曝光多少钱不重要；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;买量&lt;/strong&gt;花钱买结果——一个付费用户多少钱才重要。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;二、行业现状：黄金时代已经过去了&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;2017–2020 是买量的黄金期。&lt;/strong&gt;CPI（单用户安装成本）低，回本周期短。那时候的投放逻辑很简单：测素材 → ROI 正向就放量 → 放量不够就加预算。简单粗暴，人人赚钱。&lt;/p&gt;&lt;p&gt;转折点出现在 &lt;strong&gt;2021 年前后&lt;/strong&gt;，两个因素叠加，直接把行业从“红利期”推向“内卷期”：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;一是流量红利见顶。&lt;/strong&gt;抖音日活不再大幅增长，所有游戏公司都在同一个池子里抢用户。2025 上半年流水 TOP100 移动游戏的买量成本同比暴涨 86.6%——注意，这只是头部产品，长尾产品的成本涨幅只会更夸张。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;二是苹果 IDFA 新政。&lt;/strong&gt;iOS 端用户可以选择不被追踪，广告系统失去了精准定向的能力。以前你能把广告精准投给“最近 30 天内玩过 SLG 且付费超过 500 元”的用户，现在只能投给“性别男，年龄 25–40”。精准度断崖式下降，同样的预算买不到同样质量的用户了。&lt;/p&gt;&lt;p&gt;两个因素叠加的结果：&lt;strong&gt;买量成本翻倍，用户质量腰斩。&lt;/strong&gt;&lt;/p&gt;&lt;h2&gt;三、大盘数据：量还在涨，但结构已经变了&lt;/h2&gt;&lt;p&gt;根据 DataEye《2025 年度手游 APP 买量数据报告》，几个关键数字：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;国内手游 APP 投放素材量突破 &lt;strong&gt;5162 万组&lt;/strong&gt;，连续三年增长，但增速从 98.93% 一路下滑到 &lt;strong&gt;17.78%&lt;/strong&gt;；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;在投游戏数：超 &lt;strong&gt;2.3 万款&lt;/strong&gt;，同比增长 17%，背后是 2025 年版号大增 25%，优质供给在恢复；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;投放主体数：&lt;strong&gt;6511 家&lt;/strong&gt;，同比下降 4.43%，中小主体在批量出清，头部在收缩整合；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;新增在投游戏：&lt;strong&gt;9212 款&lt;/strong&gt;，同比下滑 6.32%；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;日均素材使用天数：&lt;strong&gt;6.66 天&lt;/strong&gt;，同比增长 29.9%——素材“死”得更快了。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;品类维度&lt;/strong&gt;（DataEye 数据）：&lt;/p&gt;&lt;table border=&quot;1&quot; cellpadding=&quot;6&quot; cellspacing=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr class=&quot;firstRow&quot;&gt;&lt;th&gt;品类&lt;/th&gt;&lt;th&gt;投放变化&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;休闲游戏&lt;/td&gt;&lt;td&gt;+37%（增长最快）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;轻度射击&lt;/td&gt;&lt;td&gt;+28%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MMORPG&lt;/td&gt;&lt;td&gt;-10% 以上（持续萎缩）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;卡牌&lt;/td&gt;&lt;td&gt;-10% 以上&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;休闲游戏成为拉动投放增长的核心品类；而 MMORPG 和卡牌这些曾经的重度买量品类反而在收缩，主因是套皮同质化严重、用户付费意愿走低。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;小游戏市场更是惊人。&lt;/strong&gt;2025 年小游戏日消耗买量费用已达 &lt;strong&gt;1.44 亿元&lt;/strong&gt;，在投小游戏约 &lt;strong&gt;5.1 万款&lt;/strong&gt;（+54%），投放素材总量超过 &lt;strong&gt;5012 万组&lt;/strong&gt;（+97%）。市场规模 &lt;strong&gt;610 亿元&lt;/strong&gt;，预计 2026 年突破 &lt;strong&gt;700 亿元&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;一句话总结：&lt;strong&gt;量还在涨，但钱越来越集中，增量越来越集中在休闲和小游戏身上。&lt;/strong&gt;&lt;/p&gt;&lt;h2&gt;四、行业里的核心角色&lt;/h2&gt;&lt;p&gt;买量是个三方游戏，每个人都压力山大。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;甲方（游戏公司投放团队）&lt;/strong&gt;：负责制定投放策略、管理预算、优化账户，核心 KPI 是 ROAS（广告支出回报率）。压力极大——流水压力全压在投放端：产品不行？投放背锅。素材不行？投放背锅。大盘成本上涨？还是投放背锅。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;乙方（代投公司）&lt;/strong&gt;：帮游戏公司管理投放账户，抽成或收服务费。行业里大量中小厂商没有自建投放团队，全权交给代投。但平台越来越透明、平台 AI 算法取代了人工经验，乙方的议价能力在下降。传统“换人群包、改标签”的投放模式，空间已经快被压缩殆尽了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;三方（素材团队）&lt;/strong&gt;：包括视频制作、平面设计、文案。这是目前行业内卷最严重的环节——&lt;strong&gt;一条跑量的素材，48 小时内就会被竞品像素级模仿。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;而 AI 正在加速这个“卷”：头部厂商如网易智选，2025 年 Q4 的 AI 素材占比已超 80%；三七互娱的《生存 33 天》用 AI 素材跑出了 10.1% 的广告点击率。素材生产正在从劳动密集转向 AI 密集，&lt;strong&gt;中间层的素材制作人员是最直接被冲击的。&lt;/strong&gt;&lt;/p&gt;&lt;h2&gt;五、现在做买量，核心痛点在哪里&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1. 素材的消耗速度超过生产速度。&lt;/strong&gt;这是最痛苦的一点。素材投放量仍在增长（+17.78%），但增速已大幅放缓，说明低效素材在减少。剩下的竞争变成：谁能用 AI 以更低的成本产出有效的素材。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 算不过来账。&lt;/strong&gt;大多数品类 LTV 增长远远跑不赢买量成本增长，很多品类已逼近倒挂。还在猛投的品类，要么是产品足够好（用户长期留存高），要么是用大 DAU 产品做交叉导量，要么……是在赌。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 对平台的深度依赖。&lt;/strong&gt;游戏买量高度集中在字节系（巨量引擎）和腾讯系（腾讯广告），定价权不在我们手里。平台的广告分发逻辑已不只是标签匹配，更多转向内容和语义匹配——创意是撬动流量的绝对杠杆，但杠杆的支点还是平台定的。&lt;strong&gt;平台算法调整一次，你的 ROI 可能直接腰斩。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4. 回款压力与账期。&lt;/strong&gt;买量的钱是日结的，广告费每天从预充值里扣；而用户的付费分散在几个月甚至更长时间内。这意味着公司必须垫付大量资金。投放主体数量在减少，部分原因正是垫资压力把现金流不够扎实的中小团队挤出了牌桌。&lt;/p&gt;&lt;h2&gt;六、这个行业还值得做吗&lt;/h2&gt;&lt;p&gt;分人。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;如果你是想做买量投放的从业者：&lt;/strong&gt;纯投放优化师的价值在快速缩水。平台越来越自动化，人的干预空间越来越小，你的对手已经从其他广告主变成了平台 AI 算法。未来有竞争力的投放人才，一定是能理解产品、能判断素材方向、能搭建数据归因体系的人。另外，&lt;strong&gt;AI 素材方向的技能（提示词工程、AI 视频工具）正在成为硬通货&lt;/strong&gt;，这是全行业的走向。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;如果你是游戏团队，想靠买量发行产品：&lt;/strong&gt;先想清楚一个问题——在买量成本同比涨了 80% 多的大盘下，你的产品 LTV 能不能覆盖买量成本的两到三倍？如果不能，请慎重；如果能，也要准备一笔足够支撑长回本周期的现金流。&lt;/p&gt;&lt;p&gt;现在，90% 以上的头部产品关注的是 30 天付费和 ROI，说明行业已经把回本周期拉到按月计算了。&lt;/p&gt;&lt;h2&gt;结语&lt;/h2&gt;&lt;p&gt;2025 年游戏市场收入首次突破 3500 亿元，小程序游戏也上涨了 30% 多——&lt;strong&gt;整个市场是在变大的&lt;/strong&gt;，但买量的蛋糕分配越来越集中了。&lt;/p&gt;&lt;p&gt;买量已经从“帮你赚钱的工具”，变成了&lt;strong&gt;你入场的基本成本&lt;/strong&gt;。&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;&lt;em&gt;数据来源：AppsFlyer、伽马数据、DataEye《2025 年度手游 APP 买量数据报告》等。本文整理自知乎作者“游连接”的深度回答，仅供行业交流参考。&lt;/em&gt;&lt;/p&gt;</description><pubDate>Mon, 28 Sep 2026 10:43:49 +0800</pubDate></item><item><title>不引一个 npm 包：用 Node + FFmpeg 自建游戏买量混剪工坊</title><link>https://www.webgou.info/?id=717</link><description>&lt;h2&gt;一、为什么要自建&lt;/h2&gt;&lt;p&gt;做游戏买量的人都懂那个循环：素材要得急、量要得大、单价要得低。市面上的路子无非几条——&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;云端 AI 视频工具&lt;/strong&gt;：按积分计费，批量跑起来钱烧得肉疼；素材要传到别人服务器，合规心里没底；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;剪映类手工工具&lt;/strong&gt;：质量可控，但一条一条做，人就是产能瓶颈；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;外包&lt;/strong&gt;：更贵，也更慢。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;而我的场景其实很「窄」：一个 Unity 小游戏，竖屏录屏是唯一的内容源，要做的是把这些录屏切成标准件、按模板拼成成片、烧上钩子大字 / 卖点 / CTA / 字幕，再派生出横屏版本。流程高度模板化——这正是自建性价比最高的场景。&lt;/p&gt;&lt;p&gt;于是有了这个「混剪工坊」：一个跑在本地的 Web 工具，双击启动、浏览器打开，九个页面走完「素材 → 切割 → 模板 → 编排 → 渲染 → 成品」全流程。&lt;/p&gt;&lt;h2&gt;二、零依赖是执念吗&lt;/h2&gt;&lt;p&gt;先交代技术栈，你可能会笑：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;服务端：Node 内置 http 模块，没用 Express；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;前端：原生 HTML / JS / CSS，没有框架、没有构建；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;视频处理：FFmpeg 子进程；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;存储：JSON 文件，没有数据库；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;部署：双击 .cmd 启动，没有 Docker。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;零 npm 依赖不是炫技，是三个很实际的理由：&lt;/p&gt;&lt;ol class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;生存周期&lt;/strong&gt;。这类内部小工具的经典死法是「半年后想改，依赖装不上了」——依赖树烂掉了。零依赖意味着只要 Node 和 FFmpeg 还在，它就能跑。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;ol class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;审计成本&lt;/strong&gt;。买量素材涉及字体授权、音频授权这类合规问题，供应链越短越好审。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;ol class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;改动信心&lt;/strong&gt;。所有代码都是自己写的，没有黑盒，改坏了回归测试会告诉我。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;代价当然有：路由自己写、静态资源自己伺候、JSON 并发写自己处理。这些活儿加起来几百行，对内部工具完全可接受。&lt;/p&gt;&lt;h2&gt;三、几条核心设计&lt;/h2&gt;&lt;h3&gt;3.1 竖屏是唯一内容源&lt;/h3&gt;&lt;p&gt;不搞双源录制。所有素材先归一成 1080×1920 @30fps 的「标准件」，横屏版本由竖屏&lt;strong&gt;成片级补边&lt;/strong&gt;派生——存储不翻倍，标准化只跑一遍。&lt;/p&gt;&lt;p&gt;归一化的关键动作是「等比铺满 + 居中裁切」，而不是直接缩放到目标分辨率。我们吃过亏：某个供料方出的原片是 736×1280 @24fps，宽高比和标准 9:16 差 2.2%，肉眼根本看不出来，但直接缩放就会把变形&lt;strong&gt;永久烧进&lt;/strong&gt;素材，后面怎么调都救不回来。&lt;/p&gt;&lt;h3&gt;3.2 字体池与授权闸门&lt;/h3&gt;&lt;p&gt;字体是买量素材最容易被忽视的合规雷。我们的字体池只收两类授权：OFL 开源（思源黑体 / 宋体，由可变字体离线切出静态字重）和明确「永久免费商用」的阿里系字体，目前 20 条、8 个字族。&lt;/p&gt;&lt;p&gt;关键在于：授权登记是&lt;strong&gt;物理防线&lt;/strong&gt;而不是提醒。渲染前的闸门逐条检查，字体不在池内、或授权类型没登记，直接拒绝渲染——没有「跳过」这个选项。&lt;/p&gt;&lt;h3&gt;3.3 输入指纹&lt;/h3&gt;&lt;p&gt;素材换源但文件名没变，是最阴险的复用 bug：新素材顶着旧名字进了池，混出来的片子看着正常，内容却不是你以为的那个。解法是给每个入池片段按&lt;strong&gt;内容&lt;/strong&gt;算指纹，指纹变了，就算同名也当新素材处理。&lt;/p&gt;&lt;h2&gt;四、一个样式字段的三份镜像&lt;/h2&gt;&lt;p&gt;字幕系统教我做人。&lt;/p&gt;&lt;p&gt;以「文字位置」为例，它在系统里有三份实现：成片渲染（FFmpeg drawtext 的 y 表达式）、字幕样式页的 CSS 实时预览、服务端的「渲一帧」预览接口。早期锚点硬编码在渲染代码里，改一个字段要人肉同步三处——漏一处，就是「预览动了、成片没动」，用户对着预览调半天，出的片子完全不是那回事。&lt;/p&gt;&lt;p&gt;后来定下三条规矩：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;参数算式收进一个&lt;strong&gt;唯一真源&lt;/strong&gt;模块，另外两处只做镜像；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;回归测试里，前端镜像&lt;strong&gt;不写期望值&lt;/strong&gt;，直接跟后端真源逐例对拍——镜像走样立刻变红，而不是等哪天我重新抄一遍期望值抄错了；&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;新增样式字段必须走完三步：默认值、归一化白名单、落到滤镜参数。少一步就是静默失效，UI 上能调、预览也像变了、成片纹丝不动——最坑的一类 bug。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;五、两个预览不是重复&lt;/h2&gt;&lt;p&gt;字幕样式页有两个预览，看着像功能重复，其实是分工：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;CSS 实时预览&lt;/strong&gt;负责「快」：拖字号、切字体、点样式胶囊，零延迟。调样式是高频动作，等一秒渲染都嫌久。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;ffmpeg 渲一帧&lt;/strong&gt;负责「准」：走成片同一套画字逻辑。描边往外扩多少、底色条多宽、字体回退长什么样，只有真渲能看出来。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;「实时」的前提是一个硬约束：CSS 预览的&lt;strong&gt;位置和字号必须等比算准&lt;/strong&gt;——预览框宽除以画布宽得到缩放系数，锚点照渲染代码的公式换算。「大概」只指观感细节，位置对不上的预览比没有预览更糟。&lt;/p&gt;&lt;p&gt;一个值得记下的 CSS 细节：用 -webkit-text-stroke 做描边时必须配 paint-order: stroke fill。CSS 描边以文字轮廓为中心往两边扩，而成片是往外扩的，预览里把描边宽度乘二抵消，再压一个「不超过字号一半」的上限——否则「重描边」这个胶囊渲染出来就是一坨黑块。这个 bug 截图上才能看出来，肉眼调样式时根本意识不到。&lt;/p&gt;&lt;h2&gt;六、怎么证明「改了，但没改坏」&lt;/h2&gt;&lt;p&gt;内部工具最怕的不是缺功能，是不敢改。这套验证组合拳是这个项目最值钱的遗产：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 测「发布的那份」。&lt;/strong&gt; 前端回归测试从 app.js 源码里把真函数抽出来执行，而不是抄一份副本进测试用例——源码改坏了，测试会跟着红。为了验证这一点，我故意把一个已修复的 bug 注回去：113 项全绿变成 112 项 1 红，改回来即恢复。不做过这一步，你永远不知道自己的测试是不是假绿。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 两实例逐字节对拍。&lt;/strong&gt; 证明「默认观感没变」最省事的手法：用户正在跑的旧实例不动，用新代码在另一个端口起一个实例，同一个请求打两边，比较返回 PNG 的 SHA256。比逐条读滤镜字符串可靠得多——那次改文字位置功能，五类文案的预览图逐字节相同，一句话证明老模板观感零变化。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. CDP 截图看真面目。&lt;/strong&gt; 前端 bug 最典型的表现是「按钮点了没反应」，这在截图上完全看不出来。所以截图脚本在导航&lt;strong&gt;之前&lt;/strong&gt;就往页面注入错误收集器（onerror、unhandledrejection、console.error）——装晚了，第一波报错就丢了。实现上零依赖：Node 22 自带 WebSocket，直连 Chrome 的调试协议，截图、读 DOM、模拟点击全够用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;4. 破坏性实验前，先确认还原路径真的存在。&lt;/strong&gt; 做过一次「先备份再注入 bug」的实验，备份到 /tmp 成功，还原时把路径写错，工作区一度停在 bug 复现态。教训：备份命令跑完，先 ls 一下那个文件真的在。&lt;/p&gt;&lt;h2&gt;七、Windows 批处理的黑暗角落&lt;/h2&gt;&lt;p&gt;工具靠双击 .cmd 启动，于是踩进批处理的经典泥潭。记两条最疼的：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;编码&lt;/strong&gt;。这个仓库的 .cmd 是 GBK + CRLF，脚本里调 chcp 切码页反而会把输出打成乱码；而我另一个仓库的惯例恰好相反（UTF-8 + chcp 65001）。同一台机器上两套惯例并存，规则只能靠文档钉死，否则每次改脚本都是一次赌运气。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;失败可见&lt;/strong&gt;。启动脚本必须做就绪轮询（探测健康检查接口，而不是固定 sleep 几秒），且失败分支要打印原因并 pause。否则错误信息随最小化的窗口一闪而过，用户只看到「启动不了」，而你永远收不到现场的报错截图。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;八、下一步：口播配音的三层模型&lt;/h2&gt;&lt;p&gt;配音能力接不接、怎么接，我想清楚分层再说。它其实分三层：&lt;/p&gt;&lt;p&gt;&lt;strong&gt;第一层：导入现成配音——已具备。&lt;/strong&gt; 做好的音频放进人声池，标注来源与授权，渲染时整条混入成片，可调的只有音量。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;第二层：选音色生成配音——未接。&lt;/strong&gt; 也就是很多工具里那个「音色列表 + 试听 + 确认」的弹窗。需要 TTS 引擎，两条路：云端 API（用 Node 原生 https 直调就行，不破坏零依赖，代价是密钥、联网、按字计费）或本地模型（免费、离线，但要下模型，没 GPU 会很慢，音色数量和自然度通常不如云端）。还有一道合规关：AI 生成的配音属于 AI 合成内容，要亮标识；那些拟人化音色（方言、情感人设类）用于商业投放，各家的商用条款不一样，选型时得逐家核。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;第三层：配音驱动分镜时长——未接，但这是关键层。&lt;/strong&gt; 现在的成片节奏是模板定死的时间窗（钩子几秒 → 主体 → CTA，素材按时长切），配音只是贴上去的一条轨。如果配音是一句一句的，不改这一层就必然音画错位——接了 TTS 也只是多一条对不上的音轨。&lt;/p&gt;&lt;p&gt;很多工具做到第二层就宣传「支持配音」，用起来才发现，第三层才是体验的分水岭。&lt;/p&gt;&lt;h2&gt;九、结语&lt;/h2&gt;&lt;p&gt;自建不适用于所有场景：要炫酷特效、要复杂转场、要真人出镜，还是老老实实上专业工具。但当需求收窄到「模板化批量生产」时，一个用零散时间搭起来的本地工具，边际成本几乎为零，而且每一行都长在自己的合规要求上。&lt;/p&gt;&lt;p&gt;真正难的不是写代码，是敢改。验证体系，才是这类工具的核心资产。&lt;/p&gt;&lt;p&gt;&lt;sc-clipboard block-data=&quot;[{&amp;quot;blockId&amp;quot;:&amp;quot;aVZEel8u73si799acGWbbP&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;aVZEel8u73si799acGWbbP&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;aVZEel8u73si799acGWbbP&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;一、为什么要自建&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;5xcRk36QeMfJ7zWjS0eCIi&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;5xcRk36QeMfJ7zWjS0eCIi&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;5xcRk36QeMfJ7zWjS0eCIi&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;做游戏买量的人都懂那个循环：素材要得急、量要得大、单价要得低。市面上的路子无非几条——&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;sDgSxNgAxK9x9HW0UxpD6k&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;sDgSxNgAxK9x9HW0UxpD6k&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;sDgSxNgAxK9x9HW0UxpD6k&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;云端 AI 视频工具&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;：按积分计费，批量跑起来钱烧得肉疼；素材要传到别人服务器，合规心里没底；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;vvKpt3VwRTa4KHT5YTWsb7&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;vvKpt3VwRTa4KHT5YTWsb7&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;vvKpt3VwRTa4KHT5YTWsb7&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;剪映类手工工具&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;：质量可控，但一条一条做，人就是产能瓶颈；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;Lerv9X0fwVzSxrlXCdchPp&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;Lerv9X0fwVzSxrlXCdchPp&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;Lerv9X0fwVzSxrlXCdchPp&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;外包&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;：更贵，也更慢。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;KCFICxZZ9q8M6zqHF676RW&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;KCFICxZZ9q8M6zqHF676RW&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;KCFICxZZ9q8M6zqHF676RW&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;而我的场景其实很「窄」：一个 Unity 小游戏，竖屏录屏是唯一的内容源，要做的是把这些录屏切成标准件、按模板拼成成片、烧上钩子大字 / 卖点 / CTA / 字幕，再派生出横屏版本。流程高度模板化——这正是自建性价比最高的场景。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;UjXYO6WLsR4261UCv6u3TK&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;UjXYO6WLsR4261UCv6u3TK&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;UjXYO6WLsR4261UCv6u3TK&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;于是有了这个「混剪工坊」：一个跑在本地的 Web 工具，双击启动、浏览器打开，九个页面走完「素材 → 切割 → 模板 → 编排 → 渲染 → 成品」全流程。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;9vMNalarDpCKngdUosAXGP&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;9vMNalarDpCKngdUosAXGP&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;9vMNalarDpCKngdUosAXGP&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;二、零依赖是执念吗&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;fvUaW43C4wmDPCkRO7p4NI&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;fvUaW43C4wmDPCkRO7p4NI&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;fvUaW43C4wmDPCkRO7p4NI&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;先交代技术栈，你可能会笑：&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;tEWpiZ9ZkYR99bgNiVPIMY&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;tEWpiZ9ZkYR99bgNiVPIMY&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;tEWpiZ9ZkYR99bgNiVPIMY&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;服务端：Node 内置 http 模块，没用 Express；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;Rys66pgB4rsa8nH0Kw7xc6&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;Rys66pgB4rsa8nH0Kw7xc6&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;Rys66pgB4rsa8nH0Kw7xc6&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;前端：原生 HTML / JS / CSS，没有框架、没有构建；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;xgfuqYQvOKfPgQybmPp1ei&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;xgfuqYQvOKfPgQybmPp1ei&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;xgfuqYQvOKfPgQybmPp1ei&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;视频处理：FFmpeg 子进程；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;s5veIUHcGSRiFJ3qEDzHiS&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;s5veIUHcGSRiFJ3qEDzHiS&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;s5veIUHcGSRiFJ3qEDzHiS&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;存储：JSON 文件，没有数据库；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;aXaXaMbyc6A39O5DNPXVuW&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;aXaXaMbyc6A39O5DNPXVuW&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;aXaXaMbyc6A39O5DNPXVuW&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;部署：双击 .cmd 启动，没有 Docker。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;uJwewRkQE4QVttncYm7xL8&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;uJwewRkQE4QVttncYm7xL8&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;uJwewRkQE4QVttncYm7xL8&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;零 npm 依赖不是炫技，是三个很实际的理由：&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;YIbODrhb3mDTJ4rKrlXfB1&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;YIbODrhb3mDTJ4rKrlXfB1&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;YIbODrhb3mDTJ4rKrlXfB1&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;numbered_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;生存周期&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;。这类内部小工具的经典死法是「半年后想改，依赖装不上了」——依赖树烂掉了。零依赖意味着只要 Node 和 FFmpeg 还在，它就能跑。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;cT3aPpujD5kHmuKDFNsHfc&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;cT3aPpujD5kHmuKDFNsHfc&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;cT3aPpujD5kHmuKDFNsHfc&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;numbered_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;审计成本&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;。买量素材涉及字体授权、音频授权这类合规问题，供应链越短越好审。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;8NlsM3vvTLH9XxxIiBVJ6F&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;8NlsM3vvTLH9XxxIiBVJ6F&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;8NlsM3vvTLH9XxxIiBVJ6F&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;numbered_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;改动信心&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;。所有代码都是自己写的，没有黑盒，改坏了回归测试会告诉我。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;k7WAptEEZ4hTvwXpL9G9eH&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;k7WAptEEZ4hTvwXpL9G9eH&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;k7WAptEEZ4hTvwXpL9G9eH&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;代价当然有：路由自己写、静态资源自己伺候、JSON 并发写自己处理。这些活儿加起来几百行，对内部工具完全可接受。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;8Gy8yWhiDD3tO9Um8wre0b&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;8Gy8yWhiDD3tO9Um8wre0b&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;8Gy8yWhiDD3tO9Um8wre0b&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;三、几条核心设计&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;SmQL2K7efzVNlXmeYL9oDc&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;SmQL2K7efzVNlXmeYL9oDc&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;SmQL2K7efzVNlXmeYL9oDc&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header3&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;3.1 竖屏是唯一内容源&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;72WgrhwGme8QLjCIRGv8eU&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;72WgrhwGme8QLjCIRGv8eU&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;72WgrhwGme8QLjCIRGv8eU&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;不搞双源录制。所有素材先归一成 1080×1920 @30fps 的「标准件」，横屏版本由竖屏&amp;quot;,null],[&amp;quot;成片级补边&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;派生——存储不翻倍，标准化只跑一遍。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;jkSuxZyHG6Yl4ToKGDOagO&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;jkSuxZyHG6Yl4ToKGDOagO&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;jkSuxZyHG6Yl4ToKGDOagO&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;归一化的关键动作是「等比铺满 + 居中裁切」，而不是直接缩放到目标分辨率。我们吃过亏：某个供料方出的原片是 736×1280 @24fps，宽高比和标准 9:16 差 2.2%，肉眼根本看不出来，但直接缩放就会把变形&amp;quot;,null],[&amp;quot;永久烧进&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;素材，后面怎么调都救不回来。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;Se7rctsfs6hcpQWa8v7oKg&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;Se7rctsfs6hcpQWa8v7oKg&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;Se7rctsfs6hcpQWa8v7oKg&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header3&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;3.2 字体池与授权闸门&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;MCezdwnu3e7YqaHPeIEzFk&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;MCezdwnu3e7YqaHPeIEzFk&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;MCezdwnu3e7YqaHPeIEzFk&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;字体是买量素材最容易被忽视的合规雷。我们的字体池只收两类授权：OFL 开源（思源黑体 / 宋体，由可变字体离线切出静态字重）和明确「永久免费商用」的阿里系字体，目前 20 条、8 个字族。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;rzrdCCVIyHvxQUaidd4g9p&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;rzrdCCVIyHvxQUaidd4g9p&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;rzrdCCVIyHvxQUaidd4g9p&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;关键在于：授权登记是&amp;quot;,null],[&amp;quot;物理防线&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;而不是提醒。渲染前的闸门逐条检查，字体不在池内、或授权类型没登记，直接拒绝渲染——没有「跳过」这个选项。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;UQYJYFGNkGq69xOBk5oUz4&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;UQYJYFGNkGq69xOBk5oUz4&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;UQYJYFGNkGq69xOBk5oUz4&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header3&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;3.3 输入指纹&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;IaPr4zteD2knWFfWP799oW&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;IaPr4zteD2knWFfWP799oW&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;IaPr4zteD2knWFfWP799oW&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;素材换源但文件名没变，是最阴险的复用 bug：新素材顶着旧名字进了池，混出来的片子看着正常，内容却不是你以为的那个。解法是给每个入池片段按&amp;quot;,null],[&amp;quot;内容&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;算指纹，指纹变了，就算同名也当新素材处理。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;k9JtkxLTBfODH2oHqv7rt1&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;k9JtkxLTBfODH2oHqv7rt1&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;k9JtkxLTBfODH2oHqv7rt1&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;四、一个样式字段的三份镜像&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;FV28faAXdy5VHbxkkqZoJV&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;FV28faAXdy5VHbxkkqZoJV&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;FV28faAXdy5VHbxkkqZoJV&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;字幕系统教我做人。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;4hKNOXPhyMb8VkKCXiapNs&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;4hKNOXPhyMb8VkKCXiapNs&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;4hKNOXPhyMb8VkKCXiapNs&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;以「文字位置」为例，它在系统里有三份实现：成片渲染（FFmpeg drawtext 的 y 表达式）、字幕样式页的 CSS 实时预览、服务端的「渲一帧」预览接口。早期锚点硬编码在渲染代码里，改一个字段要人肉同步三处——漏一处，就是「预览动了、成片没动」，用户对着预览调半天，出的片子完全不是那回事。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;zI8mDFJQpKvWHxHK3A2I4a&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;zI8mDFJQpKvWHxHK3A2I4a&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;zI8mDFJQpKvWHxHK3A2I4a&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;后来定下三条规矩：&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;4UXvGYaIEvt95C4O2ZuING&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;4UXvGYaIEvt95C4O2ZuING&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;4UXvGYaIEvt95C4O2ZuING&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;参数算式收进一个&amp;quot;,null],[&amp;quot;唯一真源&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;模块，另外两处只做镜像；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;jIPfR5e4Aar8JQPifjSXJ0&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;jIPfR5e4Aar8JQPifjSXJ0&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;jIPfR5e4Aar8JQPifjSXJ0&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;回归测试里，前端镜像&amp;quot;,null],[&amp;quot;不写期望值&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;，直接跟后端真源逐例对拍——镜像走样立刻变红，而不是等哪天我重新抄一遍期望值抄错了；&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;MDo92qgrVay9Py2MKnlSY2&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;MDo92qgrVay9Py2MKnlSY2&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;MDo92qgrVay9Py2MKnlSY2&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;新增样式字段必须走完三步：默认值、归一化白名单、落到滤镜参数。少一步就是静默失效，UI 上能调、预览也像变了、成片纹丝不动——最坑的一类 bug。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;ZuNlTI1lXacGtX6RUfgnX3&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;ZuNlTI1lXacGtX6RUfgnX3&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;ZuNlTI1lXacGtX6RUfgnX3&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;五、两个预览不是重复&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;5p76oRGmOp9KI0w5h57Ub7&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;5p76oRGmOp9KI0w5h57Ub7&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;5p76oRGmOp9KI0w5h57Ub7&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;字幕样式页有两个预览，看着像功能重复，其实是分工：&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;IgheufibB3Ti4wBLo3ofeN&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;IgheufibB3Ti4wBLo3ofeN&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;IgheufibB3Ti4wBLo3ofeN&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;CSS 实时预览&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;负责「快」：拖字号、切字体、点样式胶囊，零延迟。调样式是高频动作，等一秒渲染都嫌久。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;bhXIQ8I49LSOywaUfgVny1&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;bhXIQ8I49LSOywaUfgVny1&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;bhXIQ8I49LSOywaUfgVny1&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;ffmpeg 渲一帧&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;负责「准」：走成片同一套画字逻辑。描边往外扩多少、底色条多宽、字体回退长什么样，只有真渲能看出来。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;tr0ks1m3wcEXv6dJg77FRo&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;tr0ks1m3wcEXv6dJg77FRo&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;tr0ks1m3wcEXv6dJg77FRo&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;「实时」的前提是一个硬约束：CSS 预览的&amp;quot;,null],[&amp;quot;位置和字号必须等比算准&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;——预览框宽除以画布宽得到缩放系数，锚点照渲染代码的公式换算。「大概」只指观感细节，位置对不上的预览比没有预览更糟。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;WNYawh1MU5YxOLZ3DdnnGW&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;WNYawh1MU5YxOLZ3DdnnGW&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;WNYawh1MU5YxOLZ3DdnnGW&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;一个值得记下的 CSS 细节：用 -webkit-text-stroke 做描边时必须配 paint-order: stroke fill。CSS 描边以文字轮廓为中心往两边扩，而成片是往外扩的，预览里把描边宽度乘二抵消，再压一个「不超过字号一半」的上限——否则「重描边」这个胶囊渲染出来就是一坨黑块。这个 bug 截图上才能看出来，肉眼调样式时根本意识不到。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;D26Sd0BJtLYfzXEKPoDfGS&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;D26Sd0BJtLYfzXEKPoDfGS&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;D26Sd0BJtLYfzXEKPoDfGS&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;六、怎么证明「改了，但没改坏」&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;aHBBNuGc3JRE89CciAUMlY&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;aHBBNuGc3JRE89CciAUMlY&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;aHBBNuGc3JRE89CciAUMlY&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;内部工具最怕的不是缺功能，是不敢改。这套验证组合拳是这个项目最值钱的遗产：&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;CGDjnH7mT1HckXIM7fma5P&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;CGDjnH7mT1HckXIM7fma5P&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;CGDjnH7mT1HckXIM7fma5P&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;1. 测「发布的那份」。&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot; 前端回归测试从 app.js 源码里把真函数抽出来执行，而不是抄一份副本进测试用例——源码改坏了，测试会跟着红。为了验证这一点，我故意把一个已修复的 bug 注回去：113 项全绿变成 112 项 1 红，改回来即恢复。不做过这一步，你永远不知道自己的测试是不是假绿。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;9262lgQgEFP76uypGa9AJu&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;9262lgQgEFP76uypGa9AJu&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;9262lgQgEFP76uypGa9AJu&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;2. 两实例逐字节对拍。&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot; 证明「默认观感没变」最省事的手法：用户正在跑的旧实例不动，用新代码在另一个端口起一个实例，同一个请求打两边，比较返回 PNG 的 SHA256。比逐条读滤镜字符串可靠得多——那次改文字位置功能，五类文案的预览图逐字节相同，一句话证明老模板观感零变化。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;krmfbBqlZqT5TuJMoczl38&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;krmfbBqlZqT5TuJMoczl38&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;krmfbBqlZqT5TuJMoczl38&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;3. CDP 截图看真面目。&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot; 前端 bug 最典型的表现是「按钮点了没反应」，这在截图上完全看不出来。所以截图脚本在导航&amp;quot;,null],[&amp;quot;之前&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;就往页面注入错误收集器（onerror、unhandledrejection、console.error）——装晚了，第一波报错就丢了。实现上零依赖：Node 22 自带 WebSocket，直连 Chrome 的调试协议，截图、读 DOM、模拟点击全够用。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;odpWW8D3gZCu5Ez88X1fFW&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;odpWW8D3gZCu5Ez88X1fFW&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;odpWW8D3gZCu5Ez88X1fFW&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;4. 破坏性实验前，先确认还原路径真的存在。&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot; 做过一次「先备份再注入 bug」的实验，备份到 /tmp 成功，还原时把路径写错，工作区一度停在 bug 复现态。教训：备份命令跑完，先 ls 一下那个文件真的在。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;kTmtD7RM4CNgp2gO7nxbiD&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;kTmtD7RM4CNgp2gO7nxbiD&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;kTmtD7RM4CNgp2gO7nxbiD&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;七、Windows 批处理的黑暗角落&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;tcK24gdNMKWBfCcxpbI2Vn&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;tcK24gdNMKWBfCcxpbI2Vn&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;tcK24gdNMKWBfCcxpbI2Vn&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;工具靠双击 .cmd 启动，于是踩进批处理的经典泥潭。记两条最疼的：&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;2GCamXECmqsWI9XBNofhsV&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;2GCamXECmqsWI9XBNofhsV&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;2GCamXECmqsWI9XBNofhsV&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;编码&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;。这个仓库的 .cmd 是 GBK + CRLF，脚本里调 chcp 切码页反而会把输出打成乱码；而我另一个仓库的惯例恰好相反（UTF-8 + chcp 65001）。同一台机器上两套惯例并存，规则只能靠文档钉死，否则每次改脚本都是一次赌运气。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;OXVRGte3FpVTJnPSmiEeyn&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;OXVRGte3FpVTJnPSmiEeyn&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;OXVRGte3FpVTJnPSmiEeyn&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;bulleted_list&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;失败可见&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot;。启动脚本必须做就绪轮询（探测健康检查接口，而不是固定 sleep 几秒），且失败分支要打印原因并 pause。否则错误信息随最小化的窗口一闪而过，用户只看到「启动不了」，而你永远收不到现场的报错截图。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;U4GXxqeWzyZqUxGP8MFLoU&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;U4GXxqeWzyZqUxGP8MFLoU&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;U4GXxqeWzyZqUxGP8MFLoU&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;八、下一步：口播配音的三层模型&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;6e7tvva9SMdrWGDiGgCeEV&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;6e7tvva9SMdrWGDiGgCeEV&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;6e7tvva9SMdrWGDiGgCeEV&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;配音能力接不接、怎么接，我想清楚分层再说。它其实分三层：&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;0XRPl3cRSIwv4mmOuk7ZUK&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;0XRPl3cRSIwv4mmOuk7ZUK&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;0XRPl3cRSIwv4mmOuk7ZUK&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;第一层：导入现成配音——已具备。&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot; 做好的音频放进人声池，标注来源与授权，渲染时整条混入成片，可调的只有音量。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;1ymDpCRo6m2GsfTnkohFnp&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;1ymDpCRo6m2GsfTnkohFnp&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;1ymDpCRo6m2GsfTnkohFnp&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;第二层：选音色生成配音——未接。&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot; 也就是很多工具里那个「音色列表 + 试听 + 确认」的弹窗。需要 TTS 引擎，两条路：云端 API（用 Node 原生 https 直调就行，不破坏零依赖，代价是密钥、联网、按字计费）或本地模型（免费、离线，但要下模型，没 GPU 会很慢，音色数量和自然度通常不如云端）。还有一道合规关：AI 生成的配音属于 AI 合成内容，要亮标识；那些拟人化音色（方言、情感人设类）用于商业投放，各家的商用条款不一样，选型时得逐家核。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;VMtLjz53beJGvSpjSkjCC4&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;VMtLjz53beJGvSpjSkjCC4&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;VMtLjz53beJGvSpjSkjCC4&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;第三层：配音驱动分镜时长——未接，但这是关键层。&amp;quot;,[[&amp;quot;b&amp;quot;]]],[&amp;quot; 现在的成片节奏是模板定死的时间窗（钩子几秒 → 主体 → CTA，素材按时长切），配音只是贴上去的一条轨。如果配音是一句一句的，不改这一层就必然音画错位——接了 TTS 也只是多一条对不上的音轨。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;9muGMVQuExX46zLEUmVbRe&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;9muGMVQuExX46zLEUmVbRe&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;9muGMVQuExX46zLEUmVbRe&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;很多工具做到第二层就宣传「支持配音」，用起来才发现，第三层才是体验的分水岭。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;l7xzk03PA1XaqHKN6Bqjd5&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;l7xzk03PA1XaqHKN6Bqjd5&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;l7xzk03PA1XaqHKN6Bqjd5&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;header2&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;九、结语&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;oH7Phe4kJyJQKwBmMwidEY&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;oH7Phe4kJyJQKwBmMwidEY&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;oH7Phe4kJyJQKwBmMwidEY&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;自建不适用于所有场景：要炫酷特效、要复杂转场、要真人出镜，还是老老实实上专业工具。但当需求收窄到「模板化批量生产」时，一个用零散时间搭起来的本地工具，边际成本几乎为零，而且每一行都长在自己的合规要求上。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}},{&amp;quot;blockId&amp;quot;:&amp;quot;eCtA0PrWAiSDlvi82sGIcn&amp;quot;,&amp;quot;blockSubtree&amp;quot;:{&amp;quot;block&amp;quot;:{&amp;quot;eCtA0PrWAiSDlvi82sGIcn&amp;quot;:{&amp;quot;role&amp;quot;:&amp;quot;editor&amp;quot;,&amp;quot;value&amp;quot;:{&amp;quot;id&amp;quot;:&amp;quot;eCtA0PrWAiSDlvi82sGIcn&amp;quot;,&amp;quot;parentId&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;props&amp;quot;:{&amp;quot;title&amp;quot;:[[&amp;quot;真正难的不是写代码，是敢改。验证体系，才是这类工具的核心资产。&amp;quot;,null]]},&amp;quot;children&amp;quot;:[],&amp;quot;parentTable&amp;quot;:&amp;quot;block&amp;quot;,&amp;quot;enabled&amp;quot;:true}}}}}]&quot;&gt;&lt;/sc-clipboard&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 24 Sep 2026 11:30:06 +0800</pubDate></item></channel></rss>