<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>GooseForum</title>
    <link>https://gooseforum.online</link>
    <description>🦢 大鹅栖息地 | 自由漫谈的江湖茶馆</description>
    <managingEditor>abandoncoding@outlook.com (GooseForum)</managingEditor>
    <pubDate>Fri, 25 Sep 2026 19:55:25 +0800</pubDate>
    <lastBuildDate>Fri, 25 Sep 2026 19:55:25 +0800</lastBuildDate>
    <item>
      <title>Bubble-aware AI manga translation tool for digital comic chapters</title>
      <link>https://gooseforum.online/p/post/545</link>
      <description>AI Manga Translator bridges the language divide for manga readers. Its OCR module reads panel text, translates foreign lines, and refills dialogue balloons while preserving graphic art. Supported form...</description>
      <content:encoded><![CDATA[<p>AI Manga Translator bridges the language divide for manga readers. Its OCR module reads panel text, translates foreign lines, and refills dialogue balloons while preserving graphic art. Supported formats include WEBP, PNG, JPG, and PDF.  Every new account receives 10 free credits upon signup. Translations cost 10 credits per page, and failed runs refund automatically. Choose between flexible credit packs, pay-as-you-go pricing, or Stripe subscription billing.  Product: [AI Manga Translator](<a href="/outbound?url=https%3A%2F%2Faimangatranslator.app%2F" target="_blank" rel="nofollow ugc noopener noreferrer">https://aimangatranslator.app/</a>)</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/545</guid>
      <pubDate>Fri, 25 Sep 2026 19:55:23 +0800</pubDate>
    </item>
    <item>
      <title>AI Agent Skills：收录 Claude Code / Codex CLI 开源技能包的独立目录</title>
      <link>https://gooseforum.online/p/post/544</link>
      <description>Reusable instructions help coding agents execute complex engineering tasks reliably. AI Agent Skills indexes capability packages, usually encapsulated in a SKILL.md file, that work alongside Claude Co...</description>
      <content:encoded><![CDATA[<p>Reusable instructions help coding agents execute complex engineering tasks reliably. AI Agent Skills indexes capability packages, usually encapsulated in a SKILL.md file, that work alongside Claude Code, Codex CLI, and similar tools. As an independent repository catalog, it has no commercial affiliation with Anthropic or OpenAI.</p>
<p>Visit <a href="/outbound?url=https%3A%2F%2Faiagentskills.net%2F" target="_blank" rel="nofollow ugc noopener noreferrer">https://aiagentskills.net/</a> to freely browse open-source contributions crafted by developer communities worldwide.</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/544</guid>
      <pubDate>Fri, 25 Sep 2026 19:47:17 +0800</pubDate>
    </item>
    <item>
      <title>可以支持一下 把静态资源转移存储到 对象存储之类的吗?</title>
      <link>https://gooseforum.online/p/post/518</link>
      <description>静态资源转存对象存储 看了代码目前还没支持</description>
      <content:encoded><![CDATA[<p>静态资源转存对象存储</p>
<p>看了代码目前还没支持</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/518</guid>
      <pubDate>Tue, 25 Aug 2026 16:12:24 +0800</pubDate>
    </item>
    <item>
      <title>大家好，我做了 ReWords AI：一个免费试用的 AI 改写润色工具，欢迎大家体验</title>
      <link>https://gooseforum.online/p/post/543</link>
      <description>平时写博客、产品页和邮件，草稿往往意思到了但表达不顺。我用 ReWords AI（https://rewordsai.app/）来做 AI 改写和润色：粘贴原文，选语气，它会保留原意重新表述，中英文都能处理，对非母语写作者特别有用。 主要功能：改写、降重、语法纠错、语气调整，支持博客、电商文案、邮件和日常写作场景。可以直接免费试用，不需要装软件，网页打开即用。 我的产品收录了一些 AI 导航站，论...</description>
      <content:encoded><![CDATA[<p>平时写博客、产品页和邮件，草稿往往意思到了但表达不顺。我用 ReWords AI（https://rewordsai.app/）来做 AI 改写和润色：粘贴原文，选语气，它会保留原意重新表述，中英文都能处理，对非母语写作者特别有用。</p>
<p>主要功能：改写、降重、语法纠错、语气调整，支持博客、电商文案、邮件和日常写作场景。可以直接免费试用，不需要装软件，网页打开即用。</p>
<p>我的产品收录了一些 AI 导航站，论坛里第一次发布，欢迎大家试试并提意见。项目主页：ReWords AI  <a href="/outbound?url=https%3A%2F%2Frewordsai.app%2F" target="_blank" rel="nofollow ugc noopener noreferrer">https://rewordsai.app/</a></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/543</guid>
      <pubDate>Tue, 22 Sep 2026 07:21:22 +0800</pubDate>
    </item>
    <item>
      <title>Slacker Office 面向个人与 AI Agent 的项目轨迹工具</title>
      <link>https://gooseforum.online/p/post/542</link>
      <description>搞了一个新工具。主要是最近并行的事情有点多， 有的进入了验收阶段，一般验收到上线很少在工作管理上排期，尤其是一些比较小的任务。所以搞了一个agent office面板，方便知道那些还处于未撤底完成。</description>
      <content:encoded><![CDATA[<p>搞了一个新工具。主要是最近并行的事情有点多， 有的进入了验收阶段，一般验收到上线很少在工作管理上排期，尤其是一些比较小的任务。所以搞了一个agent office面板，方便知道那些还处于未撤底完成。</p>
<p><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fabandon1a2b%2Fslacker-office" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/abandon1a2b/slacker-office</a></p>
<p><img src="/file/img/2026/09/20/08ef2a28-4f63-4885-9c32-9d6c3a6f7687.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/542</guid>
      <pubDate>Sun, 20 Sep 2026 19:44:52 +0800</pubDate>
    </item>
    <item>
      <title>关于大家所提功能的后续开发计划整理(附未来主题原型图)-20260919</title>
      <link>https://gooseforum.online/p/post/541</link>
      <description>近期收到不少功能建议，其中部分已经完成。这里简单整理一下后续考虑推进的方向。以下内容不代表确定的开发顺序或发布时间，具体安排会根据实际情况和使用反馈调整。 基础能力与安全 完善账号封禁、登录日志、注册限制等功能 支持邀请码注册及更多人机验证方式 增加分类级帖子、回复审核规则 完善附件上传和文件管理 支持 SQLite 数据库备份至 S3 提供更友好的后台及前端数据导入、导出功能 完善站点条款、用户...</description>
      <content:encoded><![CDATA[<blockquote>
<p>近期收到不少功能建议，其中部分已经完成。这里简单整理一下后续考虑推进的方向。以下内容不代表确定的开发顺序或发布时间，具体安排会根据实际情况和使用反馈调整。</p>
</blockquote>
<h3 id="基础能力与安全">基础能力与安全</h3>
<ul>
<li>完善账号封禁、登录日志、注册限制等功能</li>
<li>支持邀请码注册及更多人机验证方式</li>
<li>增加分类级帖子、回复审核规则</li>
<li>完善附件上传和文件管理</li>
<li>支持 SQLite 数据库备份至 S3</li>
<li>提供更友好的后台及前端数据导入、导出功能</li>
<li>完善站点条款、用户名规则等后台配置</li>
<li>正文直接 @ 通知其他用户</li>
</ul>
<h3 id="内容发布能力">内容发布能力</h3>
<ul>
<li>文章内容密码保护</li>
<li>修改文章发布日期和时间</li>
<li>支持未来时间发布、定时发布</li>
<li>支持已发布、草稿等状态切换</li>
<li>增加版权协议、关闭回复等文章设置</li>
</ul>
<h3 id="社区与账号功能">社区与账号功能</h3>
<ul>
<li>TOTP 二次验证</li>
<li>账号注销与冷静期</li>
<li>编辑历史及差异查看</li>
<li>浏览器通知</li>
<li>更多 OAuth 和社交平台支持</li>
</ul>
<h3 id="需要进一步设计的功能">需要进一步设计的功能</h3>
<p>投票、正文部分隐藏、选中内容引用、树状回复等功能都比较重要，但可能涉及<strong>正文存储</strong>结构、编辑器协议和主题展示方式的调整，需要先认真设计，不会为了赶进度仓促实现。</p>
<p>其中，树状回复可以先完善服务端数据能力，再由不同<strong>主题</strong>选择列表式或树状展示；默认主题不一定直接改成嵌套结构。</p>
<p>以上内容仅作为未来开发方向说明，不是固定的开发清单和发布时间表。会优先保证基础能力、稳定性和安全性，再逐步推进涉及底层结构的功能，也欢迎大家继续补充具体使用场景和建议。</p>
<hr/>
<p>以下是之前制作的几套主题参考原型，分别偏向传统论坛、社区门户、问答、编辑精选和作品展示。它们不代表最终实现，也不一定全部支持，主要想了解大家更喜欢哪种方向，以及实际需要哪些展示能力。</p>
<p><img src="/file/img/2026/09/19/d1399114-5acb-4547-9a34-d2af93c0cc9b.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/541</guid>
      <pubDate>Sat, 19 Sep 2026 21:19:52 +0800</pubDate>
    </item>
    <item>
      <title>其他功能 &amp; feat: add Next SSR host with SPA navigation 敬请期待</title>
      <link>https://gooseforum.online/p/post/538</link>
      <description></description>
      <content:encoded><![CDATA[<p>rt</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/538</guid>
      <pubDate>Wed, 16 Sep 2026 19:40:14 +0800</pubDate>
    </item>
    <item>
      <title>一些小建议</title>
      <link>https://gooseforum.online/p/post/532</link>
      <description>无意中看到了佬的论坛程序，体验了一下整体还不错，但是有几点建议： 敏感词检测：如果有成员在帖子里输入了敏感词包含的内容则不允许发布 验证码功能：现在只有一个图形验证码，是否可以接入像Cloudflare Turnstile，Google reCAPTCHA这样的人机验证？且可以设置发帖时是否需要进行验证 附件上传：可以支持一下7z，rar，zip，tar.gz这些压缩包格式，有些时候需要直接分享点...</description>
      <content:encoded><![CDATA[<p>无意中看到了佬的论坛程序，体验了一下整体还不错，但是有几点建议：</p>
<ol>
<li>
<p>敏感词检测：如果有成员在帖子里输入了敏感词包含的内容则不允许发布</p>
</li>
<li>
<p>验证码功能：现在只有一个图形验证码，是否可以接入像Cloudflare Turnstile，Google reCAPTCHA这样的人机验证？且可以设置发帖时是否需要进行验证</p>
</li>
<li>
<p>附件上传：可以支持一下7z，rar，zip，tar.gz这些压缩包格式，有些时候需要直接分享点文件资源但是上传不了，还得弄个网盘，怪费劲的，压缩包可以上传到S3或者本地服务器</p>
</li>
<li>
<p>帖子审核：后台好像没有找到这个选项，可以开发一下</p>
</li>
<li>
<p>邀请码注册：适合一些私有小论坛，开启后只有受邀用户可以注册</p>
</li>
<li>
<p>账号封禁：被封禁的用户在用户主页显示封禁状态和封禁原因，且登录后出现相关提示（例：您的账号已被封禁，部分功能将被限制使用，如存在误封请通过xxx@example.com发送邮件申诉），同时增加可选封禁时间（有些人可能情况不严重，临时封禁几天那种）</p>
</li>
<li>
<p>帖子功能：可以设置帖子部分内容或全部内容隐藏（登录后查看/回复后查看），以及在帖子中设置投票，并且可以关闭回复（类似于锁帖）</p>
</li>
<li>
<p>S3配置可视化：把S3的配置从配置文件移动到管理后台，更加方便和理解</p>
</li>
<li>
<p>版权信息展示：开启后自动增加到帖子尾部，用于一些教程类/知识类帖子，比如CC BY、CC BY-SA、CC BY-NC、CC BY-NC-SA、CC BY-ND、CC BY-NC-ND（示例：本帖采用 CC BY-NC-SA 4.0 许可协议发布）</p>
</li>
<li>
<p>搜索功能：移动端现在貌似不会展示搜索按钮，只能通过URL进搜索页面</p>
</li>
<li>
<p>修改密码功能优化：有时候忘记了密码需要重置，但是现在重置又需要输入旧密码，就很尬，可以增加一个使用邮箱验证的方式重置密码作为备选</p>
</li>
<li>
<p>帖子表情：增加一些emoji表情，丰富帖子内容</p>
</li>
</ol>
<p>上面是目前体验到的不足，如果有些做不了就算了，不强求，之前用过Discourse很强，但是唯一的问题就是性能开销太大，这个论坛程序简直是低配服/卡预算站长的福音</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/532</guid>
      <pubDate>Thu, 10 Sep 2026 10:36:50 +0800</pubDate>
    </item>
    <item>
      <title>大家希望提供一个什么群或者什么联系方式呀</title>
      <link>https://gooseforum.online/p/post/537</link>
      <description>tg/qq/feishu or 其他？ wechat 就算了。gf同步消息不方便。</description>
      <content:encoded><![CDATA[<p>tg/qq/feishu or 其他？ wechat 就算了。gf同步消息不方便。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/537</guid>
      <pubDate>Tue, 15 Sep 2026 16:53:53 +0800</pubDate>
    </item>
    <item>
      <title>后台可以自定义侧边栏文字功能，这样就可以适应很多场景</title>
      <link>https://gooseforum.online/p/post/481</link>
      <description>首页侧边栏菜单可以自定义文字添加和排序，后台添加个菜单栏管理功能，更灵活，页面头部链接也能在后台自定义就很好使了</description>
      <content:encoded><![CDATA[<p>首页侧边栏菜单可以自定义文字添加和排序，后台添加个菜单栏管理功能，更灵活，页面头部链接也能在后台自定义就很好使了</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/481</guid>
      <pubDate>Thu, 02 Jul 2026 19:36:35 +0800</pubDate>
    </item>
    <item>
      <title>紧张刺激的代码大迁移即将开始</title>
      <link>https://gooseforum.online/p/post/536</link>
      <description>不是因为react 抛弃vue ，而是为了更好的使用shadcn和更好的使用基于shadcn的相关生态，包括两种不同的前端驱动方式。 React + shadcn 迁移与 Next 并存架构 决策状态：方向已确定，隔离的 React workspace 与开发入口已经初始化。 下一步：将当前 Vue 客户端迁移为 React，并采用 React 官方 shadcn/ui 生态。 长期并存能力：Ne...</description>
      <content:encoded><![CDATA[<blockquote>
<p>不是因为react 抛弃vue ，而是为了更好的使用shadcn和更好的使用基于shadcn的相关生态，包括两种不同的前端驱动方式。</p>
</blockquote>
<h1 id="react-shadcn-迁移与-next-并存架构">React + shadcn 迁移与 Next 并存架构</h1>
<h2 id="状态">状态</h2>
<ul>
<li>决策状态：方向已确定，隔离的 React workspace 与开发入口已经初始化。</li>
<li>下一步：将当前 Vue 客户端迁移为 React，并采用 React 官方 shadcn/ui 生态。</li>
<li>长期并存能力：Next 作为可选渲染方式接入，不取代 Go SSR，也不是 React 迁移的下一阶段或完成条件。</li>
<li>历史基线：<code>docs/shadcn-vue-site-migration.md</code> 记录了当前 shadcn-vue/Reka UI 基础层的迁移结果；该实现继续作为迁移前的行为与视觉基线。</li>
</ul>
<h2 id="背景">背景</h2>
<p>GooseForum 当前由 Go 提供页面 payload、HTML 模板、SEO/no-js 内容与业务 API，浏览器端由 Vue 3 应用接管主站和管理后台。基础 UI 已统一到 shadcn-vue 与 Reka UI，但 Vue 侧的 shadcn 生态在官方组件、registry、示例、第三方模板和工具支持方面弱于 React 侧。</p>
<p>迁移的直接目标是使用 React 官方 shadcn/ui 生态，同时保留现有 Go 页面渲染体系。Next 的目标不同：它是与 Go SSR 并存的另一种可选渲染方式，未来可由 GooseForum 主进程按配置启动并承接指定页面路由。</p>
<h2 id="核心决策">核心决策</h2>
<ol>
<li>React + shadcn 是当前前端演进方向。</li>
<li>Go 继续拥有业务逻辑、认证授权、数据库访问、API、文件服务和现有 SSR/payload 能力。</li>
<li>React 业务组件不得直接依赖 Next；通过小型运行时适配层接入不同宿主。</li>
<li>Go SSR 是长期受支持的运行方式，不视为等待 Next 替换的临时实现。</li>
<li>Next 是可选并存能力。未启用 Next 时，程序必须能够只依赖 Go 正常运行。</li>
<li>Next 不成为 React 迁移的验收条件；React 版本完成后即可独立交付。</li>
<li>不在 Next 中复制 Go 业务逻辑。Next 只负责页面渲染、路由集成和必要的数据编排。</li>
</ol>
<h2 id="目标结构">目标结构</h2>
<pre><code class="language-text">resource/
├── packages/
│   ├── client/             现有框架无关 payload、API 与浏览器协议
│   └── react/              React 业务组件、hooks、shadcn/ui 与宿主适配接口
├── apps/
│   ├── react/              C 端与后台双入口的 Vite 开发应用和 Go payload 适配
│   └── next/               可选 Next App Router 适配与服务端入口
├── templates/              长期保留的 Go HTML/SEO/no-js 模板
└── static/                 Go 模式使用的浏览器端构建产物
</code></pre>
<p>具体目录可以在实现阶段根据 pnpm workspace 调整，但依赖方向必须保持：</p>
<pre><code class="language-text">@gooseforum/client
        ↑
@gooseforum/react
    ↑          ↑
Go 客户端适配   Next 适配
</code></pre>
<p><code>@gooseforum/react</code> 不能反向导入 Next 应用代码。</p>
<h2 id="react-运行时适配层">React 运行时适配层</h2>
<p>适配层只解决宿主差异，不抽象论坛业务。候选边界包括：</p>
<ul>
<li>页面 payload 的初始读取和后续获取。</li>
<li>链接渲染与客户端导航。</li>
<li>当前路径、查询参数和滚动恢复。</li>
<li>locale、主题和页面元数据的宿主接入。</li>
<li>服务端与浏览器环境差异。</li>
</ul>
<p>页面数据结构、权限判断结果和 API 请求继续使用 <code>@gooseforum/client</code>。主题 token 和现有视觉规范继续作为迁移基线。</p>
<p>避免为了同时支持两个宿主而构造庞大的通用运行时。普通组件应优先接收数据与回调；只有确实依赖路由或宿主环境的能力才进入适配接口。</p>
<h2 id="react-shadcn-迁移原则">React + shadcn 迁移原则</h2>
<ol>
<li>使用 React 官方 shadcn/ui 组件源码和官方支持的 primitives。</li>
<li>不逐文件翻译当前 <code>resource/src/components/ui</code>。根据真实调用重新生成组件，再迁移 GooseForum 的主题、variant 和产品行为。</li>
<li>迁移目标是完整保留功能和设计意图，不是逐像素、逐 DOM 或逐行代码复刻。旧实现是重要参考，但不默认代表最优实现。</li>
<li>开发每个页面或功能前，先通过旧版源码理解其功能、排版、响应式行为、交互流程、状态变化及异常分支，整理清楚功能契约和设计目的，再用符合 React 生态的方式实现。默认不要求运行旧版逐页比对。</li>
<li>在功能完整、信息层级和整体体验一致的前提下，允许优化间距、层级、反馈、组件组合和实现细节。与旧版产生的差异应当是有理由、可验证的正向差异，不能以“优化”为由遗漏具体功能。</li>
<li>Vue 和 React 即使都使用 shadcn，也存在生命周期、缓存、路由、状态管理和组件行为上的差异。只有效果明确、替换后稳定性很高的部分可以直接迁移。</li>
<li>遇到行为等价性不明确、可能改变用户体验或存在多种合理方案的部分，必须在实现前与维护者讨论并确认，不能自行选一种近似实现。典型例子包括 Vue <code>KeepAlive</code> 的页面状态保留语义，以及详情页时间轴的结构、滚动和交互行为。</li>
<li>保持现有页面信息架构、内容密度、键盘行为、焦点管理和移动端体验；任何有意改变都应在对应功能的迁移记录中明确说明。</li>
<li>复用框架无关代码，包括 <code>@gooseforum/client</code>、API、Markdown、ProseMirror、图片处理、格式化和 payload 类型。</li>
<li>实现方式和依赖选择应符合当前 React 主流实践，优先采用官方、稳定、广泛验证且与项目边界匹配的方案，不为机械对应 Vue 结构而引入非惯用写法。</li>
<li>React 业务组件不导入 <code>next/link</code>、<code>next/navigation</code>、Server Actions 或 Next 缓存 API。</li>
<li>Next 专属的 Server Component 边界、metadata 和路由文件只存在于 Next 适配应用。</li>
<li>React 版本采用旁路集中开发：现有 Vue 版本在整个开发与验证期间保持可运行且不感知 React 改造。先完成新的 React 版本并进行整体测试，确认无误后再统一切换；迁移阶段不讨论或执行逐页替换、逐步删除旧实现。</li>
</ol>
<h3 id="开发与审查方式">开发与审查方式</h3>
<ol>
<li>首先阅读旧版源码和相关 payload、API、样式与测试，通过代码理解功能和设计意图。</li>
<li>列出必须保留的功能、数据、权限、交互状态、响应式行为、无障碍行为和异常处理。</li>
<li>如果旧版代码较复杂，且仅靠代码无法可靠判断视觉层级、真实布局或交互效果，再请维护者提供对应页面和状态的截图，不默认要求先运行旧版。</li>
<li>标记 Vue 与 React 无法直接等价的部分；凡是不容易判断且不能确认稳定替换的，先讨论再实现。</li>
<li>基于 shadcn/ui 和主流 React 模式设计实现，不受旧组件拆分方式约束。</li>
<li>对照功能清单验证新实现，同时检查允许的视觉和交互优化没有造成能力退化。</li>
<li>记录有意保留的差异和仍待确认的问题，供 React 版本整体测试和最终切换前统一审查。</li>
</ol>
<h3 id="组件位置与依赖方向">组件位置与依赖方向</h3>
<ul>
<li>shadcn/ui 只作为基础组件层，不是页面和业务组件的替代品。不能因为已有 shadcn primitives，就在每个页面中重复堆叠一整套相同的结构、交互和状态处理。</li>
<li>shadcn/ui primitives 放在 <code>resource/packages/react/src/components/ui/</code>，保持通用、无业务语义；通用 variant 和视觉基础可以留在这一层，论坛业务规则不得下沉到 primitives。</li>
<li>具有稳定产品语义或重复交互模式的组合应封装为 GooseForum 业务组件，例如用户摘要、主题列表项、页面标题区、管理表格操作区和内容状态反馈。页面负责组织业务流程，不重复拼装这些细节。</li>
<li>组件封装以清晰职责、稳定语义和实际复用为依据。既避免所有内容都直接“一把梭”式使用 shadcn，也避免只为减少几行 JSX 而制造过度抽象。</li>
<li>可同时被 Vite 和未来 Next 使用的论坛业务组件、hooks 与宿主接口放在 <code>resource/packages/react/</code>，不得依赖具体应用入口。</li>
<li>仅属于 C 端或后台 SPA 的布局、路由组合和页面组件分别放在 <code>resource/apps/react/src/site/</code> 与 <code>resource/apps/react/src/admin/</code>。</li>
<li>仅被单个页面使用的组件优先与页面就近放置；出现清晰、稳定的跨页面复用后再提升到共享层，不提前制造抽象。</li>
<li>payload、API、路由和主题等宿主差异通过明确的适配层接入，展示组件优先接收数据和回调，不直接读取全局环境。</li>
<li>引入新库前确认其维护状态、社区采用度、React 19 兼容性、无障碍表现和是否真的优于现有依赖，避免同一能力长期并存多套实现。</li>
</ul>
<h2 id="实施顺序">实施顺序</h2>
<h3 id="阶段一-react-基础设施">阶段一：React 基础设施</h3>
<ul>
<li>建立 React workspace、TypeScript 和构建入口。</li>
<li>使用同一 Vite 应用的两个 HTML 入口：根 <code>index.html</code> 对应 C 端，<code>admin/index.html</code> 对应管理后台；两套源码分别位于 <code>src/site/</code> 和 <code>src/admin/</code>。</li>
<li>管理后台保持纯 SPA 模型；开发环境中的 <code>/admin</code> 与 <code>/admin/*</code> 始终回退到后台 HTML，<code>admin.shell</code> 仅提供启动所需的用户、权限和主题数据。</li>
<li>未检测到 Go 注入 payload 时，通过 Vite 代理读取真实 Go 页面 payload。</li>
<li>React 开发构建产物保留在新 app 自己的 <code>dist/</code>，不进入现有 <code>resource/static/</code> 或 Go <code>embed.FS</code>。</li>
<li>初始化官方 shadcn/ui，映射现有主题 token；管理后台 shell 以官方 <code>dashboard-01</code> block 为起点，C 端按 GooseForum 的信息架构自行设计。</li>
<li>建立 Go payload、导航、i18n、主题和 flash message 的 React 适配。</li>
<li>保持现有 Go 模板与 <code>X-Goose-Page</code> 协议。</li>
<li>为核心交互增加浏览器级回归测试。</li>
</ul>
<h3 id="阶段二-集中开发-react-版本">阶段二：集中开发 React 版本</h3>
<p>以下顺序只用于组织开发精力，不代表逐页上线、逐页替换或逐步删除 Vue：</p>
<ol>
<li>登录、重置密码、目录和静态信息页面。</li>
<li>管理后台 CRUD 页面。</li>
<li>首页、分类、搜索和用户页。</li>
<li>设置、通知、消息、审核和发布。</li>
<li>Topic、PostComposer、编辑器、滚动窗口和内容增强。</li>
<li>AppShell、共享状态和全局交互收尾。</li>
</ol>
<p>该阶段始终保持旧运行环境不变。完整 React 版本完成并通过功能、交互、视觉和回归测试后，再单独执行整体切换。Go SSR + React 届时即为独立、完整的目标运行方式，无需等待 Next；旧实现的清理不属于当前迁移开发阶段。</p>
<h3 id="独立工作流-next-并存能力">独立工作流：Next 并存能力</h3>
<p>Next 接入建立在可复用的 React 组件和适配边界之上，但属于独立能力，不是上述迁移的后续替换阶段。</p>
<p>预期运行拓扑：</p>
<pre><code class="language-text">浏览器
  └── Go 公共监听端口
      ├── /api/*、/file/*、/oauth2/*、SEO 资源  → Go
      ├── Go 渲染路由                         → Go SSR + React
      └── 配置给 Next 的页面与 /_next/*       → Next 子进程
</code></pre>
<p>约束如下：</p>
<ul>
<li>Go 是主进程和统一公开入口。</li>
<li>Next 仅监听 loopback 地址。</li>
<li>Go 根据明确配置启动 Next，并通过反向代理路由请求。</li>
<li>Next 服务端携带原始 Cookie 向 Go 获取 payload；Go 始终是认证和权限事实来源。</li>
<li>必须设计内部回源标识或内部 page-data endpoint，避免 Next 请求再次被代理回 Next。</li>
<li>初期按固定配置或路由白名单选择渲染器，不做随机灰度。</li>
<li>Next 不可用时采用“启动失败”还是“降级到 Go SSR”，必须由配置明确决定，不能静默切换。</li>
</ul>
<h2 id="next-构建与-embed-边界">Next 构建与 embed 边界</h2>
<p>Next SSR 是需要 Node 运行时的服务，不能像普通 Vite 静态资源一样直接从 Go <code>embed.FS</code> 执行。</p>
<p>预期方案是：</p>
<ol>
<li>构建 Next standalone 产物。</li>
<li>将 standalone、<code>.next/static</code> 和 <code>public</code> 作为发布产物；如要求单 Go 文件携带，可将其嵌入 Go 二进制。</li>
<li>启动时把嵌入产物释放到临时目录。</li>
<li>Go 通过 <code>exec</code> 启动 Next 服务，并管理健康检查、退出和清理。</li>
<li>Node 运行时采用宿主依赖、发布包 sidecar 或平台专属嵌入方案，另行决策。</li>
</ol>
<p>“Next 产物可被 Go 携带”与“Next 不需要独立运行时”是两件事。是否把 Node 可执行文件也嵌入最终二进制，需要结合发布体积、平台矩阵、签名和安全更新成本单独评估。</p>
<h2 id="配置方向">配置方向</h2>
<p>最终配置名称在实现时确定，语义至少应覆盖：</p>
<pre><code class="language-toml">[frontend]
renderer = &#34;go&#34;

[frontend.next]
enabled = false
command = &#34;node&#34;
host = &#34;127.0.0.1&#34;
startupTimeout = &#34;15s&#34;
failurePolicy = &#34;fail-startup&#34;
routes = []
</code></pre>
<p>其中：</p>
<ul>
<li><code>renderer = &#34;go&#34;</code> 表示使用长期支持的 Go SSR + React 路径。</li>
<li>启用 Next 不代表关闭或删除 Go SSR。</li>
<li><code>routes</code> 允许稳定地把部分页面交给 Next；空列表的具体含义必须在实现时定义清楚。</li>
<li><code>failurePolicy</code> 必须显式配置是否允许回退。</li>
</ul>
<h2 id="非目标">非目标</h2>
<ul>
<li>不以 React 迁移为契机重写 Go 业务服务。</li>
<li>不要求把所有数据修改改造成 Next Server Actions。</li>
<li>不把 Next 作为 GooseForum 的唯一部署方式。</li>
<li>不在 React 迁移阶段实现 Next 进程管理和代理。</li>
<li>不承诺首版就把 Node 运行时嵌入单个 Go 二进制。</li>
<li>不同时长期维护两套 React 业务组件。</li>
</ul>
<h2 id="验收标准">验收标准</h2>
<h3 id="react-shadcn">React + shadcn</h3>
<ul>
<li>Go SSR、SEO/no-js 模板与现有 URL 行为保持有效。</li>
<li>主站和管理后台达到当前 Vue 版本的功能与无障碍基线。</li>
<li>明亮、暗色和自定义主题表现一致。</li>
<li>页面导航、返回滚动、登录态、编辑器和上传流程通过回归测试。</li>
<li>React 开发和验证期间不改变旧 Vue 运行路径；最终切换作为独立步骤执行。</li>
<li>Next 未实现或未启用时不影响 React 版本交付。</li>
</ul>
<h3 id="next-并存能力">Next 并存能力</h3>
<ul>
<li>配置关闭时不启动 Node/Next，Go 模式独立工作。</li>
<li>配置开启时由 Go 启动、检查和停止 Next 子进程。</li>
<li><code>/api</code>、文件、OAuth/OIDC 和认证仍由 Go 处理。</li>
<li>Cookie、状态码、重定向、流式响应和代理头行为正确。</li>
<li>Next 故障策略符合配置，且不会形成代理循环。</li>
<li>同一业务组件不因 Next 接入产生第二份实现。</li>
</ul>
<h2 id="待后续决策">待后续决策</h2>
<ul>
<li>Next 路由按全局模式、固定白名单还是更细粒度规则切换。</li>
<li>Node 由宿主提供、作为 sidecar 发布，还是按平台嵌入。</li>
<li>Next 启动失败时的默认策略。</li>
<li>Next 内部回源使用独立 loopback endpoint 还是受保护的内部请求头。</li>
<li>Next 缓存、个性化 payload 和多实例部署策略。</li>
</ul>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/536</guid>
      <pubDate>Mon, 14 Sep 2026 00:00:56 +0800</pubDate>
    </item>
    <item>
      <title>「终极路线」GooseForum未来前端技术升级路线</title>
      <link>https://gooseforum.online/p/post/535</link>
      <description>这个路线是我经过对比，以及查询相关作品得出的一个上限较高的即使路线，可以极大的提高GooseForum的体验上限未来会在这个基础上渐进的实现。 shadcn 无论是能力是使用范围上 要比 Naive UI 这种重 base 框架有着更广的应用空间。 在 有着丰富的面向c端的模板例子，足以撑起一个年轻现代化的论坛项目。具体流程如下。 1. GFUI → shadcn-vue 必要性： 减少基础 UI...</description>
      <content:encoded><![CDATA[<blockquote>
<p>这个路线是我经过对比，以及查询相关作品得出的一个上限较高的即使路线，可以极大的提高GooseForum的体验上限未来会在这个基础上渐进的实现。 shadcn 无论是能力是使用范围上 要比  Naive UI 这种重 base 框架有着更广的应用空间。 在 <a href="/outbound?url=https%3A%2F%2Fwww.shadcn.io%2Ftemplate" target="_blank" rel="nofollow ugc noopener noreferrer">https://www.shadcn.io/template</a>  有着丰富的面向c端的模板例子，足以撑起一个年轻现代化的论坛项目。具体流程如下。</p>
</blockquote>
<pre><code class="language-text">GFUI
  ↓
shadcn-vue
  ↓
稳定
  ↓
React + shadcn
  ↓
内置多主题
  ↓
可选 Next Runtime
</code></pre>
<h3 id="1-gfui-shadcn-vue">1. GFUI → shadcn-vue</h3>
<p>必要性：</p>
<ul>
<li>
<p>减少基础 UI 自研成本。</p>
</li>
<li>
<p>避免 Naive UI 这类完整 UI Framework 的运行时负担。</p>
</li>
<li>
<p>保留 Vue 当前优势。</p>
</li>
<li>
<p>提前统一组件语义和 Design Token，为 React 迁移做准备。</p>
</li>
</ul>
<p>原则：</p>
<blockquote>
<p>shadcn 负责基础 UI，论坛业务组件继续自己维护。</p>
</blockquote>
<h3 id="2-稳定后迁移-react-shadcn">2. 稳定后迁移 React + shadcn</h3>
<p>必要性：</p>
<ul>
<li>
<p>shadcn React 生态、组件、模板、动效明显更丰富。</p>
</li>
<li>
<p>Payload 等周边对 React 支持更深。</p>
</li>
<li>
<p>迁移时可继续保留 Tailwind、Design Token、ProseMirror、Markdown、API Client 和纯 TS 逻辑。</p>
</li>
</ul>
<h3 id="3-react-稳定后支持内置多主题">3. React 稳定后支持内置多主题</h3>
<p>默认提供约 3 套真正不同的 C 端主题，而不只是多配色。</p>
<p>主题可以改变：</p>
<pre><code class="language-text">布局
信息密度
圆角
边框
Typography
组件表现
</code></pre>
<p>Admin 不受 C 端主题控制。</p>
<h3 id="4-支持两种前端运行模式">4. 支持两种前端运行模式</h3>
<pre><code class="language-text">GooseForum React Core
       │
   ┌───┴───┐
   │       │
Static    Next
默认       可选
</code></pre>
<p>Static：</p>
<pre><code class="language-text">Go + embedded React/Vite dist
</code></pre>
<p>Next：</p>
<pre><code class="language-text">Go
→ 检测 Node
→ 启动 Next
→ Reverse Proxy
</code></pre>
<h3 id="5-next-保持薄">5. Next 保持薄</h3>
<blockquote>
<p><strong>React 是产品层，Next 只是运行时宿主。</strong></p>
</blockquote>
<p>Next 只负责 SSR、SEO、Metadata 等增强能力，业务组件不绑定 Next。</p>
<h3 id="6-支持运行时切换">6. 支持运行时切换</h3>
<pre><code class="language-text">Static
  ↓
启动 Next
  ↓
健康检查
  ↓
切流
  ↓
Next
</code></pre>
<p>Next 异常时可降级回 Static。</p>
<p>最终目标：</p>
<blockquote>
<p><strong>默认模式足够轻，高级模式有更高上限，同时尽量避免框架绑定。</strong></p>
</blockquote>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/535</guid>
      <pubDate>Sun, 13 Sep 2026 01:59:11 +0800</pubDate>
    </item>
    <item>
      <title>一些建议和bug</title>
      <link>https://gooseforum.online/p/post/432</link>
      <description>Footer 中的 Primary 类使用 Html，无法编译 url 和 a 标签，会显示纯 Html 代码 下方文字内容 （Primary）&#34;，还是会出现原html， Power by &lt;a href=&#34;https://github.com/leancodebox/GooseForum&#34;&gt;GooseForum&lt;/a&gt;. “外部资源链接 / Meta 标签” 若为空，则会导致无法保存，500错误...</description>
      <content:encoded><![CDATA[<ol>
<li>
<p>Footer 中的 Primary 类使用 Html，无法编译 url 和 a 标签，会显示纯 Html 代码</p>
<ul>
<li>“下方文字内容 （Primary）&#34;，还是会出现原html，<code>Power by &lt;a href=&#34;https://github.com/leancodebox/GooseForum&#34;&gt;GooseForum&lt;/a&gt;.</code></li>
</ul>
</li>
<li>
<p>“外部资源链接 / Meta 标签” 若为空，则会导致无法保存，500错误</p>
</li>
<li>
<p>站点标签的 title 不能随后台更改而发生变化，始终是 GooseForum</p>
</li>
<li>
<p>邮箱存在无法通过链接进行验证，仍然会显示“账户邮箱未验证，请先验证您的邮箱”，从而无法登陆</p>
<ul>
<li>发件人名称填写，实际会显示邮件原登陆用户名称；</li>
<li>当“站点信息”中 URL 结尾存在 “/” 时，导致链接失效，错误格式：<code>https://xxxx//activate?token</code>；正确格式：<code>https://xxxx/activate?token</code></li>
</ul>
</li>
<li>
<p>“赞助&#34;内容中的联系我们无更改链接选项，部分内容也没法后台更改</p>
</li>
<li>
<p>当分类被帖子占用时，不能直接删除分类，而是要将该分类中的所有帖子收到一个一个去除掉才可以删除分类</p>
</li>
<li>
<p>友情链接清空所以后，仅新建分组并不添加内容时，会500错误导致无法使用友情链接功能</p>
<ul>
<li>/admin/links-management 页面问题还是存在，index-C-eCsYM6.js:9 TypeError: Cannot read properties of undefined (reading ’length&#39;)</li>
</ul>
</li>
<li>
<p>MD编辑，插入代码块显示不正确</p>
</li>
<li>
<p><del>建议悬停卡片中，底部展示个人网站、勋章等信息，若未填写介绍则不显示介绍内容</del></p>
</li>
<li>
<p><del>建议在站点统计中显示当前社区基于版本号</del></p>
</li>
<li>
<p><del>建议增加删除自己回复的功能</del></p>
</li>
<li>
<p>建议增加用户组权限，如部分tags只对某用户组可看</p>
</li>
<li>
<p>建议增加文章内容密码、文章日期时间更改功能（含选择未来时间/定时发布）、发布与草稿状态切换</p>
</li>
<li>
<p>建议增加个人主页的说说功能，简单笔记那种（分仅个人查看和公共查看，即显示在个人主页）</p>
</li>
<li>
<p>建议增加后台即前端的数据导入和导出功能，比较友好的操作</p>
</li>
<li>
<p>建议增加发帖时 -&gt; 当有人回复时通知我</p>
</li>
</ol>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/432</guid>
      <pubDate>Wed, 20 May 2026 11:26:42 +0800</pubDate>
    </item>
    <item>
      <title>rooster我之前开发的一个方便的本地任务调度工具，前端时间更新了一波</title>
      <link>https://gooseforum.online/p/post/534</link>
      <description>是一个托盘程序，最初版本是我完全手撸的，这个新版本是我上周收集了老的功能然后完全ai重构的。公司的和我家里的电脑都装了，就是方便维护一些常驻程序和定时程序。 是应用软件，托盘维护的。</description>
      <content:encoded><![CDATA[<p><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fleancodebox%2Frooster" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/leancodebox/rooster</a></p>
<p>是一个托盘程序，最初版本是我完全手撸的，这个新版本是我上周收集了老的功能然后完全ai重构的。公司的和我家里的电脑都装了，就是方便维护一些常驻程序和定时程序。</p>
<p>是应用软件，托盘维护的。</p>
<p><img src="/file/img/2026/09/11/adbe4fae-dabc-491c-9804-962d4292585f.webp" alt="image" loading="lazy" decoding="async"/></p>
<p><img src="/file/img/2026/09/11/ed3e6a2a-daff-4bf4-9bdf-3c6d3d9cba56.webp" alt="image" loading="lazy" decoding="async"/></p>
<p><img src="/file/img/2026/09/11/511ede86-df72-4d66-ba83-20e7344f56ff.webp" alt="image" loading="lazy" decoding="async"/></p>
<p><img src="/file/img/2026/09/11/3c7fd247-eaad-48d2-8464-db6287fe3a3b.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/534</guid>
      <pubDate>Fri, 11 Sep 2026 19:54:34 +0800</pubDate>
    </item>
    <item>
      <title>大家好，我写了个 AI 导航工具 收录了 1000 个 AI，分享给大家</title>
      <link>https://gooseforum.online/p/post/533</link>
      <description>欢迎收藏 刚刚写的工具站 maichongbo.com 脉冲波AI工具合集 收集了全网最全AI工具 和分好类 并且每周保持更新 公益项目 如果遇到访问不了的情况请联系我 绝不死链! 公益项目</description>
      <content:encoded><![CDATA[<p>欢迎收藏  刚刚写的工具站</p>
<p>maichongbo.com  脉冲波AI工具合集</p>
<p>收集了全网最全AI工具  和分好类</p>
<p>并且每周保持更新   公益项目</p>
<p>如果遇到访问不了的情况请联系我</p>
<p>绝不死链! 公益项目</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/533</guid>
      <pubDate>Fri, 11 Sep 2026 04:16:29 +0800</pubDate>
    </item>
    <item>
      <title>准备更新---新头像</title>
      <link>https://gooseforum.online/p/post/531</link>
      <description>准备更新</description>
      <content:encoded><![CDATA[<p>准备更新</p>
<p><img src="/file/img/2026/09/09/c4470e7b-64d0-436e-b7fb-2b699c5b3cc4.webp" alt="image" loading="lazy" decoding="async"/></p>
<p><img src="/file/img/2026/09/09/df8f8e41-fc9a-418e-ba09-1a05f7152c28.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/531</guid>
      <pubDate>Wed, 09 Sep 2026 20:38:58 +0800</pubDate>
    </item>
    <item>
      <title>我发现ai改老项目，cr的一个特点是需要判断他声称的代码数量是否符合心中大改更改数量</title>
      <link>https://gooseforum.online/p/post/530</link>
      <description>我认为一个功能最多3行+一个函数，那么如果ai生成了50行，这就需要仔细看一下了。</description>
      <content:encoded><![CDATA[<p>我认为一个功能最多3行+一个函数，那么如果ai生成了50行，这就需要仔细看一下了。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/530</guid>
      <pubDate>Wed, 09 Sep 2026 11:31:12 +0800</pubDate>
    </item>
    <item>
      <title>golang 库推荐 脚本/压测/热重载/发布</title>
      <link>https://gooseforum.online/p/post/529</link>
      <description>推荐1个库，3个go软件，第一个是如果需要扩展脚本的时候可以用到，traefik官方的，traefik的插件就是用的这个，还行。 后面3个分别是压测/热重载/发布</description>
      <content:encoded><![CDATA[<p>推荐1个库，3个go软件，第一个是如果需要扩展脚本的时候可以用到，traefik官方的，traefik的插件就是用的这个，还行。 后面3个分别是压测/热重载/发布</p>
<pre><code>github.com/traefik/yaegi/interp  
go install github.com/codesenberg/bombardier@latest
go install github.com/cosmtrek/air@latest
go install github.com/goreleaser/goreleaser@latest
</code></pre>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/529</guid>
      <pubDate>Fri, 04 Sep 2026 16:16:36 +0800</pubDate>
    </item>
    <item>
      <title>怀念手撸樱花爬虫（后面并不打算自己手写）</title>
      <link>https://gooseforum.online/p/post/528</link>
      <description>看到工具箱的几个工具，怀念当初手撸爬虫。</description>
      <content:encoded><![CDATA[<p>看到工具箱的几个工具，怀念当初手撸爬虫。</p>
<pre><code>  yh:download    Download YH video by film ID
  yh:films       List YH films
  yh:get         YH website crawler
  yh:save        Save YH video to file
  yh:videos      List YH film videos
</code></pre>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/528</guid>
      <pubDate>Thu, 03 Sep 2026 14:23:31 +0800</pubDate>
    </item>
    <item>
      <title>Wails-v3, are u kidding me ?</title>
      <link>https://gooseforum.online/p/post/527</link>
      <description>上个月就有好多关于 wails 庆祝进入 bate 阶段的的介绍文章。截图是他最后一次alpha 的 （alpha 能100多也是没谁了） 接下来看bate的表演 are u kidding me??</description>
      <content:encoded><![CDATA[<p>上个月就有好多关于 wails 庆祝进入 bate 阶段的的介绍文章。截图是他最后一次alpha 的</p>
<p><img src="/file/img/2026/09/03/5d5f7337-9f65-4c44-ba47-c49ab46c534d.webp" alt="image" loading="lazy" decoding="async"/>（alpha 能100多也是没谁了）</p>
<p>接下来看bate的表演</p>
<p><img src="/file/img/2026/09/03/e9f2f521-79df-49c2-a037-4814a51d3067.webp" alt="image" loading="lazy" decoding="async"/></p>
<p><strong>are u kidding me??</strong></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/527</guid>
      <pubDate>Thu, 03 Sep 2026 10:03:53 +0800</pubDate>
    </item>
    <item>
      <title>如果 Sub2API 不能用了：一次备用链路搭建记录 (虽然我也不知道谁说sub2api后面可能不能用了)</title>
      <link>https://gooseforum.online/p/post/525</link>
      <description>背景是有人和我说sub2api 可能不被codex 支持了，另外就是 CLIProxyAPI 被官方支持，但是 CLIProxyAPI 基本上可以认为是一个服务端的 ccswitch，如果只是 CLIProxyAPI 还不足以公司内部分配使用/监控。 这次尝试并不是为了主动替换 Sub2API。 起因是一个更直接的问题：如果有一天 Sub2API 因为版本、维护、部署环境或其他原因无法继续使用，现...</description>
      <content:encoded><![CDATA[<blockquote>
<p>背景是有人和我说sub2api 可能不被codex 支持了，另外就是 CLIProxyAPI 被官方支持，但是 CLIProxyAPI 基本上可以认为是一个服务端的 ccswitch，如果只是 CLIProxyAPI 还不足以公司内部分配使用/监控。</p>
</blockquote>
<p>这次尝试并不是为了主动替换 Sub2API。</p>
<p>起因是一个更直接的问题：如果有一天 Sub2API 因为版本、维护、部署环境或其他原因无法继续使用，现有的模型账号和内部用户是否还有一条可以较快恢复的服务链路？</p>
<p>基于这个问题，我们在沙箱中搭建并验证了一个组合方案：</p>
<pre><code class="language-text">New API + CLIProxyAPI
</code></pre>
<p>它的目标不是复刻 Sub2API 的全部实现，而是在原系统不可用时，先恢复几个最基本的能力：</p>
<ul>
<li>给内部用户提供统一 API 地址。</li>
<li>为不同使用者签发独立 API Key。</li>
<li>接入现有模型账号。</li>
<li>提供基础模型权限、额度和调用日志。</li>
<li>保留后续迁移或回切的空间。</li>
</ul>
<p>本文记录这套备用链路的结构、已验证范围和仍然存在的缺口。</p>
<h2 id="备用链路结构">备用链路结构</h2>
<pre><code class="language-text">Codex / OpenAI SDK / 内部应用
              |
              | New API Key
              v
       New API（对外网关）
       - 用户与 API Key
       - 模型和分组权限
       - 额度与调用日志
       - 渠道路由
              |
              | 内部专用 Key
              v
    CLIProxyAPI（上游适配）
       - OAuth 认证文件
       - 多账号选择
       - 账号状态维护
       - 协议转换
              |
              v
        官方模型服务
</code></pre>
<p>部署环境需要统一出口时，再增加一层本机代理：</p>
<pre><code class="language-text">CLIProxyAPI -&gt; Hushsocks -&gt; 上游服务
</code></pre>
<p>普通使用者只接触 New API。CLIProxyAPI、认证目录和 Hushsocks 都只监听本机地址，不直接暴露给下游用户。</p>
<h2 id="为什么需要两个项目">为什么需要两个项目</h2>
<p>单独使用其中任何一个项目，都不能直接覆盖我们需要的最小范围。</p>
<p>New API 有用户、API Key、分组、额度和日志，但它并不擅长完成订阅账号的首次登录和账号池维护。</p>
<p>CLIProxyAPI 可以管理 Codex 等账号并提供兼容接口，但它的多个入口 Key 更接近多个访问凭据，不是完整的多用户、额度和运营体系。</p>
<p>因此在备用方案中，两者分别承担一部分工作：</p>
<pre><code class="language-text">New API：面向内部使用者
CLIProxyAPI：面向上游模型账号
</code></pre>
<p>这只是为了补齐应急链路，不代表这种拆分一定优于 Sub2API 的一体化实现。</p>
<h2 id="应急覆盖范围">应急覆盖范围</h2>
<table>
<thead>
<tr>
<th>能力</th>
<th>Sub2API</th>
<th>当前备用链路</th>
<th>验证情况</th>
</tr>
</thead>
<tbody>
<tr>
<td>统一 API 地址</td>
<td>内置</td>
<td>New API</td>
<td>已验证</td>
</tr>
<tr>
<td>下游 API Key</td>
<td>内置</td>
<td>New API</td>
<td>已验证</td>
</tr>
<tr>
<td>用户与分组</td>
<td>内置</td>
<td>New API</td>
<td>基础能力已验证</td>
</tr>
<tr>
<td>模型权限</td>
<td>内置</td>
<td>New API</td>
<td>已验证</td>
</tr>
<tr>
<td>OAuth 账号接入</td>
<td>内置</td>
<td>CLIProxyAPI</td>
<td>已验证</td>
</tr>
<tr>
<td>多账号选择</td>
<td>内置</td>
<td>CLIProxyAPI</td>
<td>基础能力已验证</td>
</tr>
<tr>
<td>OpenAI 兼容接口</td>
<td>内置</td>
<td>两层组合</td>
<td>已验证</td>
</tr>
<tr>
<td>模型列表</td>
<td>内置</td>
<td>两层组合</td>
<td>已验证</td>
</tr>
<tr>
<td>调用日志</td>
<td>内置</td>
<td>New API</td>
<td>基础能力已验证</td>
</tr>
<tr>
<td>精细计费</td>
<td>内置</td>
<td>New API 配置</td>
<td>尚未完整对齐</td>
</tr>
<tr>
<td>运营管理</td>
<td>内置</td>
<td>New API</td>
<td>尚未完整对齐</td>
</tr>
<tr>
<td>全协议兼容</td>
<td>内置</td>
<td>依赖两层转换</td>
<td>需要继续测试</td>
</tr>
<tr>
<td>故障恢复</td>
<td>单服务体系</td>
<td>多服务组合</td>
<td>需要额外运维</td>
</tr>
</tbody>
</table>
<p>备用链路能够先恢复日常调用，但不能直接声明为完整替代。特别是计费口径、协议细节、错误处理和运营流程，需要单独核对。</p>
<h2 id="存储方式">存储方式</h2>
<p>New API 和 CLIProxyAPI 的存储方式不同。</p>
<p>New API 的用户、渠道、Key、额度和日志存放在数据库。沙箱使用 PostgreSQL，并在现有数据库中创建独立 schema：</p>
<pre><code class="language-text">PostgreSQL database
├── public    -&gt; Sub2API
└── new_api   -&gt; New API
</code></pre>
<p>New API 的连接固定为：</p>
<pre><code class="language-text">search_path=new_api
</code></pre>
<p>没有配置 <code>new_api,public</code> 的回退路径，避免 New API 在迁移期间命中 <code>public</code> 中的同名表。实际验证中，New API 的表全部创建在 <code>new_api</code>，Sub2API 的 <code>public</code> 表没有发生变化。</p>
<p>CLIProxyAPI 主要使用文件：</p>
<pre><code class="language-text">config.yaml       服务配置和内部 Key
auth/*.json       OAuth 认证凭据
plugins/          可选插件
logs/             可选日志
</code></pre>
<p>这意味着认证目录必须放在持久化磁盘，并纳入权限控制和备份。它不像数据库那样方便做集中查询和变更审计，是备用方案中需要接受的运维成本。</p>
<h2 id="单机沙箱部署">单机沙箱部署</h2>
<p>目前的目标规模是单企业、100 人以内团队，先用单机验证恢复链路是否成立。</p>
<p>沙箱中的服务布局为：</p>
<pre><code class="language-text">New API       0.0.0.0:3000
Sub2API       0.0.0.0:8080
CLIProxyAPI   127.0.0.1:8317
Hushsocks     127.0.0.1:1080
Prompt Guard  127.0.0.1:8000
</code></pre>
<p>目录结构如下：</p>
<pre><code class="language-text">/opt/sub2apideployhome/
├── app4yun/
├── sub2api/
├── newapi/
├── cliproxyapi/
│   ├── config.yaml
│   └── auth/
├── hushsocks/
├── prompt_guard_stub
└── sub2api.start.sh
</code></pre>
<p>统一启动脚本按顺序启动并探活各个服务。任一关键进程退出时，启动脚本结束整组进程，由云平台重新拉起。</p>
<p>这种方式便于沙箱部署，但也意味着单个新增服务启动失败时，其他进程会一起退出。它适合作为当前验证方式，不应直接视为最终高可用设计。</p>
<h2 id="搭建中遇到的问题">搭建中遇到的问题</h2>
<h3 id="1-linux-amd64-不等于一定兼容">1. Linux amd64 不等于一定兼容</h3>
<p>首次使用的 New API 官方 Linux amd64 二进制是动态链接版本，要求较新的 glibc：</p>
<pre><code class="language-text">GLIBC_2.32
GLIBC_2.34
</code></pre>
<p>沙箱系统只有 glibc 2.28，因此二进制在启动前就无法加载。由于统一启动脚本会结束整组进程，最终表现为所有服务都没有运行。</p>
<p>处理方式是基于同一版本源码重新构建静态二进制：</p>
<pre><code class="language-bash">CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
</code></pre>
<p>重新打包后确认：</p>
<pre><code class="language-text">ELF 64-bit x86-64
statically linked
</code></pre>
<p>这次问题说明，应急包不能只检查文件名中的 <code>linux_amd64</code>，还要检查：</p>
<pre><code class="language-bash">file binary
ldd binary
</code></pre>
<h3 id="2-new-api-模型需要配置渠道和价格策略">2. New API 模型需要配置渠道和价格策略</h3>
<p>New API 创建渠道后，不能只填写上游地址和 Key。还需要同步实际模型列表，并选择合适的价格或自用模式，否则测试请求可能在到达上游前被 New API 拒绝。</p>
<p>沙箱采用自用模式，只用于验证内部链路，不代表正式计费配置已经完成。</p>
<h3 id="3-cliproxyapi-的认证目录需要单独维护">3. CLIProxyAPI 的认证目录需要单独维护</h3>
<p>CLIProxyAPI 的账号信息保存在文件中。账号导入、备份、权限和迁移都需要明确操作流程。对少量管理员维护的单机环境尚可接受，但如果后续发展为多节点，需要重新评估存储和同步方式。</p>
<h2 id="当前已验证内容">当前已验证内容</h2>
<p>沙箱中已经完成以下检查：</p>
<ul>
<li>New API PostgreSQL schema 初始化。</li>
<li>New API 连续启动迁移。</li>
<li>New API 与 Sub2API 表空间隔离。</li>
<li>CLIProxyAPI 读取认证文件。</li>
<li>New API 通过内部 Key 访问 CLIProxyAPI。</li>
<li>New API <code>/v1/models</code> 返回模型列表。</li>
<li>New API 和 Sub2API 页面探活。</li>
<li>Hushsocks 建立上游连接。</li>
<li>Linux 静态二进制在旧 glibc 环境下的兼容修复。</li>
<li>整体部署包的 SHA-256 和文件权限检查。</li>
</ul>
<p>尚未完成或需要扩大验证的内容：</p>
<ul>
<li>长时间并发稳定性。</li>
<li>所有模型和协议的逐项测试。</li>
<li>流式响应、工具调用和图片接口的完整回归。</li>
<li>与 Sub2API 一致的计费结果对比。</li>
<li>多用户额度和限流边界测试。</li>
<li>日志清理、数据库备份和恢复演练。</li>
<li>单服务故障时的独立恢复能力。</li>
</ul>
<h2 id="什么时候启用备用链路">什么时候启用备用链路</h2>
<p>这套组合更适合作为预案，而不是在当前系统正常时立即切换。</p>
<p>建议触发条件包括：</p>
<ul>
<li>Sub2API 无法在目标环境启动，短期内无法修复。</li>
<li>Sub2API 发布包或依赖不可获得。</li>
<li>升级后核心接口出现阻断性问题，需要临时回避。</li>
<li>需要在修复主系统期间维持内部模型调用。</li>
</ul>
<p>启用时可以分三步进行：</p>
<ol>
<li>先由少量体验用户验证模型列表和基础请求。</li>
<li>再逐步签发 New API Key，观察错误率和日志。</li>
<li>主系统恢复后，根据实际情况选择回切或继续并行评估。</li>
</ol>
<h2 id="结论">结论</h2>
<p>New API + CLIProxyAPI 是一次面向故障场景的可行性验证。</p>
<p>它证明了当 Sub2API 暂时不可用时，可以通过两个现有项目重新拼出一条基本可用的内部 API 链路。但这套组合增加了服务数量，也带来了认证文件、跨服务日志、兼容性和故障联动等新的运维问题。</p>
<p>因此当前更准确的定位是：</p>
<blockquote>
<p>一套已经跑通基础链路的 Sub2API 应急备选方案。</p>
</blockquote>
<p>它是否值得长期保留，需要等并发、协议、计费和恢复演练完成后再决定。现在的价值主要是降低单一实现不可用时完全中断服务的风险。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/525</guid>
      <pubDate>Wed, 02 Sep 2026 17:01:26 +0800</pubDate>
    </item>
    <item>
      <title>Ohyeah：让 AI 找回做过的工作（自己动手丰衣足食）</title>
      <link>https://gooseforum.online/p/post/526</link>
      <description>我觉得我需要一个类似向量服务的功能维护我多个项目的一些codex上下文，docs以及其他方面，要求要比文本好。正好我也在用meilisearch 我就这么搞了一个。并且类似以半钩子的形式自由的让各个项目自己写收集方式，定义好协议，然后统一收集，并用于后续检索。（不是代码索引） 和编码 Agent 协作久了，一个常见问题是：它并不知道之前发生过什么。 为什么这样改？上次排查得出了什么结论？哪个判断后...</description>
      <content:encoded><![CDATA[<p><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fabandon1a2b%2Fohyeah" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/abandon1a2b/ohyeah</a></p>
<h2 id="人话">人话</h2>
<p>我觉得我需要一个类似向量服务的功能维护我多个项目的一些codex上下文，docs以及其他方面，要求要比文本好。正好我也在用meilisearch 我就这么搞了一个。并且类似以半钩子的形式自由的让各个项目自己写收集方式，定义好协议，然后统一收集，并用于后续检索。（不是代码索引）</p>
<hr/>
<h2 id="机话">机话</h2>
<p>和编码 Agent 协作久了，一个常见问题是：它并不知道之前发生过什么。</p>
<p>为什么这样改？上次排查得出了什么结论？哪个判断后来被推翻了？很多工作明明做过，却不得不重新翻代码、日志和对话。</p>
<p><code>ohyeah</code> 是一个面向编码 Agent 的本地工作记忆与证据检索服务。它从 Codex 对话、项目文档、需求分析和工具输出中采集历史记录，保存结论、决策、纠错、证据与未完成事项，并让每条结果都能回到原始来源。</p>
<p>它不试图成为新的事实源。历史记忆用于帮助定位，时效性信息仍需回到代码、Git、数据库或日志中复核。</p>
<p>运行一个命令：</p>
<pre><code>ohyeah serve
</code></pre>
<p>即可启动后台同步、文件监听、搜索 API 和嵌入式 Web 管理界面。你可以直接搜索历史工作、阅读完整上下文、查看同步状态、调整配置和重建索引。</p>
<p><code>ohyeah</code> 想解决的事情很简单：少做重复调查，让 Agent 从团队和个人已经完成的工作继续向前。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/526</guid>
      <pubDate>Wed, 02 Sep 2026 17:14:57 +0800</pubDate>
    </item>
    <item>
      <title>搞了一个工具，实时监听aiagent帮我ssh操作时的监控</title>
      <link>https://gooseforum.online/p/post/524</link>
      <description>其实就是一个 tmux 实时的监控面板，tmux的会话保持比较好，可以让ai操作的时候同步进行监控查看。</description>
      <content:encoded><![CDATA[<p><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fabandon1a2b%2Ftmux-watchboard%2F" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/abandon1a2b/tmux-watchboard/</a></p>
<p>其实就是一个 tmux 实时的监控面板，tmux的会话保持比较好，可以让ai操作的时候同步进行监控查看。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/524</guid>
      <pubDate>Wed, 02 Sep 2026 16:58:14 +0800</pubDate>
    </item>
    <item>
      <title>本站的配置是2c2g嘛 加载如此之快</title>
      <link>https://gooseforum.online/p/post/523</link>
      <description></description>
      <content:encoded><![CDATA[<p>RT</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/523</guid>
      <pubDate>Wed, 02 Sep 2026 09:26:47 +0800</pubDate>
    </item>
    <item>
      <title>向着星辰与深渊</title>
      <link>https://gooseforum.online/p/post/522</link>
      <description>控制住冲动。先把当前的功能完善好，再做多主题。毕竟如果有新页面增加的话。多主题也要同步增加。</description>
      <content:encoded><![CDATA[<p>控制住冲动。先把当前的功能完善好，再做多主题。毕竟如果有新页面增加的话。多主题也要同步增加。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/522</guid>
      <pubDate>Tue, 01 Sep 2026 21:14:04 +0800</pubDate>
    </item>
    <item>
      <title>今日份的随便研究研究 godot 角色随便试试</title>
      <link>https://gooseforum.online/p/post/521</link>
      <description>我还每天还是有人来论坛的，正常情况下大家可以随意灌水的。 今日份的随便研究研究如下，随便尝试一下godot，看到8方图后，我觉得怎么说呢，2d的一些贴图感觉资源不比3d的少准备的素材还挺多的，每个角度各一张。当然啦，感觉今天token有点少，所以就让codex帮我找一个精灵图搞一个角色展示看看。</description>
      <content:encoded><![CDATA[<p>我还每天还是有人来论坛的，正常情况下大家可以随意灌水的。</p>
<p>今日份的随便研究研究如下，随便尝试一下godot，看到8方图后，我觉得怎么说呢，2d的一些贴图感觉资源不比3d的少准备的素材还挺多的，每个角度各一张。当然啦，感觉今天token有点少，所以就让codex帮我找一个精灵图搞一个角色展示看看。</p>
<p><img src="/file/img/2026/08/27/46f69ac2-9da1-44d0-8bbf-574ecc24253f.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/521</guid>
      <pubDate>Thu, 27 Aug 2026 23:15:36 +0800</pubDate>
    </item>
    <item>
      <title>f5刷新长时间一片都是空白状态怎么办？</title>
      <link>https://gooseforum.online/p/post/509</link>
      <description>如果服务器比较烂访问更差，那么gooseforum首次访问加载完成，但是一旦f5刷新都是长时间空白状态才能加载完好，一直按f5刷新重复也是一片空白，所以建议加一个骨架屏还有service worker，这样离线状态下更流畅更好</description>
      <content:encoded><![CDATA[<p>如果服务器比较烂访问更差，那么gooseforum首次访问加载完成，但是一旦f5刷新都是长时间空白状态才能加载完好，一直按f5刷新重复也是一片空白，所以建议加一个骨架屏还有service worker，这样离线状态下更流畅更好</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/509</guid>
      <pubDate>Wed, 19 Aug 2026 15:51:06 +0800</pubDate>
    </item>
    <item>
      <title>我发现我这种用ai，制作学习游戏的过程，制作的是快，脑子根本没留下多少</title>
      <link>https://gooseforum.online/p/post/520</link>
      <description>如果是学校的学生或者编程初学者用这个，感觉知识体系会炸掉。。到后面无法驾驭程序了。 虽然可以快速出东西，但是一些高级的复杂的，没有知识体系的话，无法更好的指引ai。</description>
      <content:encoded><![CDATA[<p>如果是学校的学生或者编程初学者用这个，感觉知识体系会炸掉。。到后面无法驾驭程序了。</p>
<p>虽然可以快速出东西，但是一些高级的复杂的，没有知识体系的话，无法更好的指引ai。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/520</guid>
      <pubDate>Tue, 25 Aug 2026 23:17:59 +0800</pubDate>
    </item>
    <item>
      <title>从角色运动到世界表现：Godot Platformer、房间切换与 Isometric 完整学习总结</title>
      <link>https://gooseforum.online/p/post/519</link>
      <description>日期：2026-08-25 项目：Platformer → Room Transitions → Isometric 目标读者：已经有后端或 Web 开发经验，正在借助 AI 系统学习 Godot，希望能够理解节点职责、空间转换、场景生命周期和素材工程，而不只是看到 Demo 能运行的人。 1. 今天真正练习的不是三个地图 表面上，今天完成了横版平台、俯视房间切换和 Isometric 地图。真正...</description>
      <content:encoded><![CDATA[<blockquote>
<p>日期：2026-08-25<br/>
项目：Platformer → Room Transitions → Isometric<br/>
目标读者：已经有后端或 Web 开发经验，正在借助 AI 系统学习 Godot，希望能够理解节点职责、空间转换、场景生命周期和素材工程，而不只是看到 Demo 能运行的人。</p>
</blockquote>
<h2 id="1-今天真正练习的不是三个地图">1. 今天真正练习的不是三个地图</h2>
<p>表面上，今天完成了横版平台、俯视房间切换和 Isometric 地图。真正贯穿三者的主题是：</p>
<blockquote>
<p>一个游戏世界怎样定义空间、约束运动、管理内容生命周期，并把同一份状态投影成不同画面。</p>
</blockquote>
<p>三个项目各自负责一个层次：</p>
<table>
<thead>
<tr>
<th>项目</th>
<th>表面功能</th>
<th>主要节点和 API</th>
<th>真正新增的能力</th>
</tr>
</thead>
<tbody>
<tr>
<td>Platformer</td>
<td>跑跳、斜坡、移动与踩落平台</td>
<td><code>CharacterBody2D</code>、<code>TileMapLayer</code>、<code>AnimatableBody2D</code>、<code>Area2D</code>、<code>AnimatedSprite2D</code>、<code>Camera2D</code></td>
<td>用物理公式和碰撞结果控制实时角色运动</td>
</tr>
<tr>
<td>Room Transitions</td>
<td>双向门、NPC、房间切换、状态恢复</td>
<td><code>PackedScene.instantiate()</code>、<code>Node.add_child()</code>、<code>queue_free()</code>、Autoload、Signal、Tween</td>
<td>区分常驻运行时和可卸载内容，并安全地替换场景子树</td>
</tr>
<tr>
<td>Isometric</td>
<td>菱形地图、选格、寻路、高地、遮挡、小地图</td>
<td>Isometric <code>TileSet</code>、<code>map_to_local()</code>、<code>local_to_map()</code>、<code>AStar3D</code>、Y Sort、<code>SubViewport</code></td>
<td>让逻辑网格、屏幕投影、素材脚点和逻辑高度彼此分离</td>
</tr>
</tbody>
</table>
<p>能力递进可以概括为：</p>
<pre><code class="language-mermaid">flowchart LR
    A[连续物理运动] --&gt; B[世界碰撞与平台规则]
    B --&gt; C[场景内容的装载与卸载]
    C --&gt; D[跨场景状态所有权]
    D --&gt; E[逻辑网格与屏幕投影]
    E --&gt; F[高度、遮挡与寻路]
    F --&gt; G[同一模型的多种表现层]
</code></pre>
<p>昨天建立了 Node、Scene、Signal、Resource、状态机和数据驱动的基础；今天进一步回答了三个更接近真实游戏工程的问题：</p>
<ol>
<li>角色为什么能以某种“手感”运动，而不只是修改位置？</li>
<li>一个房间销毁后，什么应该消失，什么必须继续存在？</li>
<li>当逻辑世界不是屏幕上的正方形网格时，怎样保持数据、导航和画面一致？</li>
</ol>
<h2 id="2-先建立今天的总心智模型-世界不是一张图片">2. 先建立今天的总心智模型：世界不是一张图片</h2>
<p>今天反复出现四个彼此不同的层次：</p>
<pre><code class="language-text">Model / Rule
    角色参数、逻辑格、阻挡、房间 ID、Flag
            ↓
World Structure
    Node Tree、TileMapLayer、RoomRoot、Objects
            ↓
Simulation
    Physics、AStar、输入、Signal、生命周期
            ↓
Presentation
    Sprite、Animation、Camera、HUD、SubViewport
</code></pre>
<p>它们不能因为最终都出现在屏幕上，就混成同一件事。</p>
<p>例如 Isometric 高地同时涉及：</p>
<ul>
<li><code>Vector3i(x, y, z)</code>：逻辑表面。</li>
<li><code>AStar3D</code>：哪些表面可以互相到达。</li>
<li><code>HighGround: TileMapLayer</code>：高地的地砖表现。</li>
<li><code>-z × 33px</code>：投影后的视觉高度。</li>
<li><code>z_index = z × 10</code>：覆盖普通 Y Sort 的绘制优先级。</li>
</ul>
<p>只把 Sprite 向上挪 33 像素，不会自动创建一个可寻路的高地；只给导航点增加 <code>z=1</code>，屏幕画面也不会自动抬升。逻辑和表现必须显式连接。</p>
<h2 id="3-platformer-实时运动是每个物理帧的一次求解">3. Platformer：实时运动是每个物理帧的一次求解</h2>
<p><img src="/file/img/2026/08/25/90393b20-50c1-4c6a-a192-918c8a0f7163.webp" alt="Platformer 最终物理实验场：真实素材、地形碰撞与运动遥测" loading="lazy" decoding="async"/></p>
<blockquote>
<p>Platformer 最终画面。左侧是角色和 TileMap 地形，右侧遥测面板实时显示运动状态、速度、地面法线、碰撞对象和跳跃容错计时。</p>
</blockquote>
<h3 id="3-1-为什么使用-characterbody2d">3.1 为什么使用 <code>CharacterBody2D</code></h3>
<p>Player 的根节点是 <code>CharacterBody2D</code>。它适合“由代码决定移动意图、由物理世界修正最终结果”的角色。</p>
<p>基本流程是：</p>
<pre><code class="language-text">读取输入
→ 计算期望 velocity
→ move_and_slide()
→ Godot 检测碰撞并修正位移
→ is_on_floor() / get_floor_normal() / SlideCollision
→ 下一物理帧继续计算
</code></pre>
<p>这里的 <code>velocity</code> 不是“这一帧一定移动到哪里”，而是角色希望采用的速度。<code>move_and_slide()</code> 才会结合 TileMap、平台和斜坡碰撞，决定实际位移。</p>
<p>这与直接写：</p>
<pre><code class="language-gdscript">position += velocity * delta
</code></pre>
<p>完全不同。后者绕过 CharacterBody2D 的滑动、地面判断和碰撞响应，可能直接穿过墙体。</p>
<h3 id="3-2-用跳高和时间推导重力">3.2 用跳高和时间推导重力</h3>
<p><code>MovementProfile</code> 没有让人同时手调“跳跃初速度、上升重力、跳高”三个互相牵制的数字，而是暴露更符合设计意图的字段：</p>
<pre><code class="language-text">jump_height = 120px
time_to_jump_apex = 0.34s
time_from_apex = 0.28s
</code></pre>
<p>然后由运动公式计算：</p>
<pre><code class="language-text">跳跃初速度 v = -(2h / t_up)
上升重力 g_up = 2h / t_up²
下落重力 g_down = 2h / t_down²
</code></pre>
<p>GDScript 对应：</p>
<pre><code class="language-gdscript">func jump_velocity() -&gt; float:
    return -(2.0 * jump_height) / time_to_jump_apex

func rising_gravity() -&gt; float:
    return (2.0 * jump_height) / pow(time_to_jump_apex, 2)
</code></pre>
<p>Godot 的 Y 轴向下为正，因此向上跳跃的初速度是负数。</p>
<p>上下使用不同重力，意味着角色可以慢一些上升、快一些落下。这不是物理模拟必须如此，而是平台游戏手感的设计选择。</p>
<h3 id="3-3-一次物理帧的顺序">3.3 一次物理帧的顺序</h3>
<p>Player 的 <code>_physics_process()</code> 顺序不是随意排列的：</p>
<pre><code class="language-text">记录移动前是否在地面
→ 读取输入
→ 更新 Coyote / Buffer 计时
→ 尝试起跳
→ 处理提前松键
→ 应用分段重力
→ 应用水平加减速
→ move_and_slide()
→ 读取本帧碰撞结果
→ 更新朝向与动画
→ 判断是否刚刚落地
</code></pre>
<p>需要注意一个时间关系：</p>
<ul>
<li><code>is_on_floor()</code> 在调用 <code>move_and_slide()</code> 前，描述上一物理步得到的接触状态。</li>
<li><code>move_and_slide()</code> 完成后，再读取 <code>is_on_floor()</code>，才能知道本帧是否刚刚落地。</li>
</ul>
<p>所以代码先保存：</p>
<pre><code class="language-gdscript">var was_on_floor := is_on_floor()
</code></pre>
<p>移动后再比较：</p>
<pre><code class="language-gdscript">if not was_on_floor and is_on_floor():
    landed.emit(speed_before_move)
</code></pre>
<h3 id="3-4-coyote-time-jump-buffer-与-jump-cut">3.4 Coyote Time、Jump Buffer 与 Jump Cut</h3>
<p>这三项都是输入意图和严格物理条件之间的缓冲。</p>
<h4 id="coyote-time">Coyote Time</h4>
<p>角色刚离开平台边缘后，保留约 <code>0.12s</code> 的起跳资格：</p>
<pre><code class="language-text">上一刻在地面
→ coyote_time_left = 0.12
→ 离地后逐帧递减
→ 计时未归零时仍可起跳
</code></pre>
<h4 id="jump-buffer">Jump Buffer</h4>
<p>玩家在落地前约 <code>0.12s</code> 按下跳跃，输入不会丢失：</p>
<pre><code class="language-text">按下 Space
→ jump_buffer_left = 0.12
→ 稍后获得地面资格
→ 自动消费缓冲并起跳
</code></pre>
<h4 id="jump-cut">Jump Cut</h4>
<p>角色仍在上升时提前松开 Space：</p>
<pre><code class="language-gdscript">velocity.y *= jump_cut_multiplier
</code></pre>
<p>负的上升速度绝对值被缩小，于是更早到达顶点，形成长按高跳、轻按低跳。</p>
<p>起跳条件因此不再只是 <code>is_on_floor() and just_pressed</code>，而是：</p>
<pre><code class="language-text">jump_buffer_left &gt; 0
AND
coyote_time_left &gt; 0
</code></pre>
<h3 id="3-5-characterbody2d-animatablebody2d-与-area2d">3.5 <code>CharacterBody2D</code>、<code>AnimatableBody2D</code> 与 <code>Area2D</code></h3>
<p>Platformer 把三种容易混淆的节点放在了同一关卡：</p>
<table>
<thead>
<tr>
<th>节点</th>
<th>项目中的对象</th>
<th style="text-align:right">是否实体阻挡</th>
<th>谁决定运动</th>
<th>主要职责</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>CharacterBody2D</code></td>
<td>Player</td>
<td style="text-align:right">是</td>
<td>Player 脚本设置 <code>velocity</code> 并调用 <code>move_and_slide()</code></td>
<td>可控角色运动和碰撞响应</td>
</tr>
<tr>
<td><code>AnimatableBody2D</code></td>
<td>移动/踩落木板</td>
<td style="text-align:right">是</td>
<td>平台脚本改变位置</td>
<td>给角色提供可运动的物理表面</td>
</tr>
<tr>
<td><code>Area2D</code></td>
<td>Checkpoint、踩落触发器</td>
<td style="text-align:right">否</td>
<td>不负责实体移动</td>
<td>检测进入、离开和重叠事件</td>
</tr>
</tbody>
</table>
<p>Checkpoint 只表示“玩家进入过这个区域”，所以它使用 <code>Area2D</code>。真正的新出生点由常驻 World 保存：</p>
<pre><code class="language-text">Player 进入 Checkpoint Area
→ World.activate_checkpoint()
→ active_spawn_position 更新
→ Player 跌出 death_y
→ World 把 Player 放回 active_spawn_position
</code></pre>
<p>Player 不应该自己知道关卡里有几个检查点，也不应该决定世界的重生规则。</p>
<h3 id="3-6-tilemaplayer-为什么同时负责画面和地形碰撞">3.6 TileMapLayer 为什么同时负责画面和地形碰撞</h3>
<p>地面、普通平台和斜坡属于大量重复的静态世界数据。它们使用带 Physics Layer 的 <code>TileSet</code>：</p>
<pre><code class="language-text">TileSet Atlas
├── 视觉区域
├── 碰撞多边形
└── Custom Data: surface_type
        ↓
TileMapLayer
├── 画出地形
├── 提供权威碰撞
└── 允许 Player 查询脚下语义
</code></pre>
<p>而移动木板、踩落木板有独立状态和行为，因此保留为 <code>PlatformActor</code> Scene。</p>
<p>判断标准不是“它们看起来都是平台”，而是：</p>
<blockquote>
<p>这是大量静态世界数据，还是一个具有生命周期和行为的 Gameplay Object？</p>
</blockquote>
<h3 id="3-7-地面法线和斜坡">3.7 地面法线和斜坡</h3>
<p><code>get_floor_normal()</code> 返回的是接触面的法线。</p>
<p>平地大致是：</p>
<pre><code class="language-text">(0, -1)
</code></pre>
<p>斜坡法线会同时包含 X 和 Y 分量。CharacterBody2D 根据 <code>up_direction</code> 和接触夹角判断一块表面是否属于地面。</p>
<p>这说明斜坡不是贴图造成的视觉倾斜；TileSet Physics Layer 中实际存在不同形状的碰撞多边形。</p>
<h3 id="3-8-animatedsprite2d-的职责">3.8 AnimatedSprite2D 的职责</h3>
<p>角色动画使用：</p>
<pre><code class="language-text">Player
└── Visuals
    └── Sprite: AnimatedSprite2D
            ↓
       SpriteFrames Resource
       idle / run / rising / apex / falling
</code></pre>
<p>Player 脚本只选择动画名：</p>
<pre><code class="language-gdscript">sprite.play(&amp;&#34;run&#34;)
</code></pre>
<p>帧顺序、FPS 和是否循环属于 <code>SpriteFrames</code> Resource，不应该由 <code>_process()</code> 手动计时切帧。</p>
<h2 id="4-room-transitions-场景切换本质是节点子树的生命周期管理">4. Room Transitions：场景切换本质是节点子树的生命周期管理</h2>
<p><img src="/file/img/2026/08/25/bcfcc3aa-5262-4d15-be85-d320b6d7e237.webp" alt="Room Transitions 诊断场景：常驻 HUD、Player、NPC 与出口" loading="lazy" decoding="async"/></p>
<blockquote>
<p>Room Transitions 刻意保留诊断型表现：HUD、Player 与对话系统常驻，房间地面、NPC 和右侧出口属于当前可卸载 Room。</p>
</blockquote>
<h3 id="4-1-为什么没有直接调用-change-scene-to-file">4.1 为什么没有直接调用 <code>change_scene_to_file()</code></h3>
<p>如果每扇门都直接切换整个主场景：</p>
<pre><code class="language-text">Door
→ change_scene_to_file(next_room)
→ 当前根场景整体销毁
</code></pre>
<p>那么 Player、HUD、对话框和运行时状态也会跟着销毁。之后必须重新创建，并额外恢复所有状态。</p>
<p>当前项目采用常驻 Game：</p>
<pre><code class="language-text">Game（常驻）
├── RoomRoot
│   └── CurrentRoom（可替换）
├── Player（常驻）
└── Interface（常驻）
</code></pre>
<p>切换房间真正执行的是：</p>
<pre><code class="language-text">从 RoomRoot 移除旧房间
→ 实例化新房间
→ 加入 RoomRoot
→ 移动同一个 Player 实例
</code></pre>
<p>这让“内容场景的生命周期”和“游戏会话的生命周期”分开。</p>
<h3 id="4-2-packedscene-和运行时实例不是同一个对象">4.2 <code>PackedScene</code> 和运行时实例不是同一个对象</h3>
<p>房间表保存的是：</p>
<pre><code class="language-gdscript">Dictionary[StringName, PackedScene]
</code></pre>
<p><code>PackedScene</code> 是可以重复实例化的场景模板。调用：</p>
<pre><code class="language-gdscript">var next_room := packed_room.instantiate()
</code></pre>
<p>才得到运行时 Node Tree。</p>
<p>可以类比为：</p>
<pre><code class="language-text">PackedScene ≈ 类定义 / 组件模板
instantiate() ≈ new / 创建组件实例
add_child() ≈ 挂载到运行时树
queue_free() ≈ 延迟销毁实例
</code></pre>
<h3 id="4-3-room-id-entry-id-是稳定地址">4.3 <code>room_id + entry_id</code> 是稳定地址</h3>
<p>出口没有保存另一个房间中的绝对坐标，而是声明：</p>
<pre><code class="language-text">target_room_id = &#34;ruins&#34;
target_entry_id = &#34;from_forest&#34;
</code></pre>
<p>目标房间内部维护：</p>
<pre><code class="language-text">Entries
├── default: Marker2D
├── from_forest: Marker2D
└── from_north_gate: Marker2D
</code></pre>
<p>因此门知道“去哪里”，但目标房间自己决定入口的真实坐标。</p>
<p>这比把 <code>Vector2(742, 318)</code> 写进出口更稳定：房间布局变化时只需移动 Marker2D，不必修改所有引用它的门、存档和任务。</p>
<h3 id="4-4-房间替换为什么要先验证后提交">4.4 房间替换为什么要先验证后提交</h3>
<p>错误流程：</p>
<pre><code class="language-text">销毁当前房间
→ 尝试加载目标
→ 才发现 room_id 或 entry_id 无效
→ 游戏只剩空 RoomRoot
</code></pre>
<p>当前流程：</p>
<pre><code class="language-text">查找 PackedScene
→ instantiate()
→ 验证类型
→ 验证 Entry 是否存在
→ 全部通过
→ 才 mount_room()
</code></pre>
<p>这和数据库事务、Tetris 的“候选—验证—提交”是同一种工程思想：</p>
<blockquote>
<p>先证明新状态可以成立，再破坏旧状态。</p>
</blockquote>
<h3 id="4-5-一次房间切换的完整事件流">4.5 一次房间切换的完整事件流</h3>
<pre><code class="language-mermaid">sequenceDiagram
    participant P as Player
    participant E as RoomExit / Area2D
    participant R as TransitionRoom
    participant G as Game
    participant S as GameSession

    P-&gt;&gt;E: body_entered
    E-&gt;&gt;R: transition_requested(room_id, entry_id)
    R-&gt;&gt;G: exit_requested(room_id, entry_id)
    G-&gt;&gt;G: instantiate_valid_room()
    G-&gt;&gt;P: input_enabled = false
    G-&gt;&gt;G: fade_to(1.0)
    G-&gt;&gt;G: mount_room()
    G-&gt;&gt;P: 设置 Entry 位置并清空 velocity
    G-&gt;&gt;S: record_arrival()
    G-&gt;&gt;G: fade_to(0.0)
    G-&gt;&gt;P: input_enabled = true
</code></pre>
<p>这里故意让 Signal 逐层转发：</p>
<ul>
<li><code>RoomExit</code> 不知道 Game 在哪里。</li>
<li><code>TransitionRoom</code> 负责聚合本房间的出口和交互事件。</li>
<li><code>Game</code> 是唯一有权替换房间的对象。</li>
</ul>
<h3 id="4-6-为什么淡出时锁定输入">4.6 为什么淡出时锁定输入</h3>
<p>淡出和淡入由 Tween 驱动，是异步过程：</p>
<pre><code class="language-gdscript">await fade_to(1.0)
mount_room(...)
await fade_to(0.0)
</code></pre>
<p>如果期间仍接受输入，可能出现：</p>
<ul>
<li>玩家在黑屏中继续移动。</li>
<li>新房间刚挂载就离开入口。</li>
<li>连续触发另一个出口。</li>
<li>同时开始第二次切换。</li>
</ul>
<p>因此同时使用：</p>
<pre><code class="language-text">transition_in_progress
player.input_enabled = false
RoomExit.armed = false
</code></pre>
<p>它们分别保护全局切换流程、角色输入和单个出口的重复触发。</p>
<h3 id="4-7-autoload-保存什么-不保存什么">4.7 Autoload 保存什么，不保存什么</h3>
<p><code>GameSession</code> 是 Autoload：</p>
<pre><code class="language-text">/root/GameSession
├── current_room_id
├── arrival_entry_id
└── flags
</code></pre>
<p>房间销毁时它不会销毁，所以 NPC 第二次实例化后仍能判断：</p>
<pre><code class="language-text">met_forest_guide 是否存在？
</code></pre>
<p>但 Autoload 不应该成为可以随意操纵所有节点的万能 Manager。当前它只保存跨房间会话数据，并发出数据变化 Signal；NPC 对话 UI 仍由 Game 管理。</p>
<h3 id="4-8-onready-的生命周期边界">4.8 <code>@onready</code> 的生命周期边界</h3>
<p><code>@onready var exits = $Exits</code> 只有节点进入 SceneTree、执行 <code>_ready()</code> 前才完成赋值。</p>
<p>但是房间预验证发生在：</p>
<pre><code class="language-text">instantiate()
→ 尚未 add_child()
→ 尚未进入 SceneTree
</code></pre>
<p>因此 <code>has_entry()</code> 不能依赖只在 <code>_ready()</code> 后才可用的缓存引用，而要显式读取：</p>
<pre><code class="language-gdscript">get_node(&#34;Entries&#34;).has_node(entry_id)
</code></pre>
<p>这是 Scene 实例化和 SceneTree 生命周期之间很具体的边界。</p>
<h2 id="5-isometric-逻辑网格没有倾斜-倾斜的是投影">5. Isometric：逻辑网格没有倾斜，倾斜的是投影</h2>
<p><img src="/file/img/2026/08/25/7b7a539f-a384-4ce8-882b-0ab2c687ea20.webp" alt="Isometric 最终场景：等距地图、正式角色、遥测与实时小地图" loading="lazy" decoding="async"/></p>
<blockquote>
<p>Isometric 最终画面。主世界由 Camera2D 观察，右侧 CanvasLayer 显示三种坐标空间，左下 SubViewport 根据共享逻辑数据绘制实时小地图。</p>
</blockquote>
<h3 id="5-1-isometric-不是把地图整体旋转-45">5.1 Isometric 不是把地图整体旋转 45°</h3>
<p>逻辑地图仍然是普通二维网格：</p>
<pre><code class="language-text">(0,0) (1,0) (2,0)
(0,1) (1,1) (2,1)
(0,2) (1,2) (2,2)
</code></pre>
<p>变化发生在 Grid 到屏幕坐标的投影。当前 Tile 逻辑脚印为 <code>132×66</code>：</p>
<pre><code class="language-text">screen_x = (x - y) × 66 + 66
screen_y = (x + y) × 33 + 33
</code></pre>
<p>因此：</p>
<pre><code class="language-text">+X → 屏幕右下 (+66, +33)
+Y → 屏幕左下 (-66, +33)
</code></pre>
<p>这里常说的“45°”是屏幕上的视觉描述，不是 Godot 存在一个只能设置为 45° 的游戏规则。2:1 Isometric 菱形边缘在屏幕坐标中的斜率由宽高比决定。</p>
<h3 id="5-2-三个坐标空间">5.2 三个坐标空间</h3>
<p>项目同时维护：</p>
<table>
<thead>
<tr>
<th>空间</th>
<th>示例</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td>离散逻辑表面</td>
<td><code>Vector3i(10, 12, 1)</code></td>
<td>阻挡、AStar、目标、逻辑高度</td>
</tr>
<tr>
<td>连续 Grid</td>
<td><code>Vector2(3.42, 7.0)</code></td>
<td>小地图中的平滑移动、投影逆变换</td>
</tr>
<tr>
<td>Map-local Pixel</td>
<td><code>Vector2(-198, 363)</code></td>
<td>Node2D 位置、Line2D、Sprite 脚点</td>
</tr>
</tbody>
</table>
<p>正变换由 <code>IsoGridMath.grid_to_world()</code> 实现；逆变换是解同一组方程：</p>
<pre><code class="language-text">grid_x = centered_x / 132 + centered_y / 66
grid_y = centered_y / 66 - centered_x / 132
</code></pre>
<p>连续 Grid 适合数学和插值；真正选择离散菱形格时，使用 TileMapLayer 的：</p>
<pre><code class="language-gdscript">local_to_map()
</code></pre>
<p>让 Godot 根据 TileSet 的 Isometric 几何判断鼠标落在哪个菱形内。</p>
<h3 id="5-3-camera-启用后-鼠标坐标为什么要再转换">5.3 Camera 启用后，鼠标坐标为什么要再转换</h3>
<p>鼠标事件最初处于 Viewport 坐标，但 TileMap 接收世界/局部坐标。Camera2D 启用后，两者不再相等：</p>
<pre><code class="language-text">Viewport Mouse Position
→ Canvas Transform 的逆变换
→ World Position
→ TileMapLayer.to_local()
→ local_to_map()
→ Cell
</code></pre>
<p>项目也可以直接使用 <code>get_global_mouse_position()</code> 取得 Camera 变换后的世界坐标。</p>
<p>如果仍把 <code>event.position</code> 直接传给 TileMap，角色在相机移动后会走向鼠标之外的错误格子。</p>
<h3 id="5-4-图片尺寸-tile-脚印与素材脚点">5.4 图片尺寸、Tile 脚印与素材脚点</h3>
<p>Kenney 地砖图片高度可以是 99px，但 TileSet 的逻辑尺寸是 <code>132×66</code>。</p>
<p>原因是图片还包含地块侧面：</p>
<pre><code class="language-text">顶部菱形：逻辑地面脚印
土壤侧面：视觉厚度
</code></pre>
<p>同样，Player 和建筑根节点放在“脚接触地面的位置”，Sprite 作为子节点向上偏移。</p>
<p>Y Sort 比较 Node2D 原点的 Y，不会自动读取 PNG Alpha 边界或人物脚底。</p>
<h3 id="5-5-y-sort-与遮挡淡化是两个系统">5.5 Y Sort 与遮挡淡化是两个系统</h3>
<p>场景结构：</p>
<pre><code class="language-text">Objects（y_sort_enabled = true）
├── Player（原点是脚点）
└── RedBuilding（原点是建筑脚点）
    ├── Visual: Sprite2D
    └── OcclusionArea: Area2D
</code></pre>
<p>普通前后关系由 Y Sort 决定：</p>
<pre><code class="language-text">Player.y &lt; Building.y → Player 先绘制 → 建筑在前
Player.y &gt; Building.y → Player 后绘制 → Player 在前
</code></pre>
<p>建筑淡化则由 <code>OcclusionArea</code> 检测 Player 的 <code>VisibilityProbe</code>：</p>
<pre><code class="language-text">Area 重叠
→ Tween 修改 Visual.modulate.a
</code></pre>
<p>职责分别是：</p>
<ul>
<li>Y Sort：谁先画、谁后画。</li>
<li>Area2D：玩家是否进入特定遮挡区域。</li>
<li>AStar 阻挡：建筑脚下的 Cell 是否可以通行。</li>
</ul>
<p>三者看起来都与“建筑挡住玩家”有关，但不能合并成同一套数据。</p>
<h3 id="5-6-为什么二维游戏使用了-astar3d">5.6 为什么二维游戏使用了 <code>AStar3D</code></h3>
<p>初始地图只有一层，可以使用：</p>
<pre><code class="language-text">AStarGrid2D + Vector2i(x, y)
</code></pre>
<p>加入高地后，逻辑表面升级为：</p>
<pre><code class="language-text">Vector3i(x, y, z)
</code></pre>
<p><code>AStar3D</code> 不是因为画面变成了 3D，而是它天然接受带三个分量的位置，并允许显式建立跨层连接。</p>
<p>当前规则是：</p>
<pre><code class="language-text">相同 z 的四方向相邻格 → 自动连接
不同 z → 默认不连接
坡道低端与高端 → 显式连接
</code></pre>
<p>所以角色不能从高地边缘直接“爬墙”，只能经过：</p>
<pre><code class="language-text">(9,12,0) ↔ (10,12,1)
</code></pre>
<h3 id="5-7-高度-y-sort-与-z-index">5.7 高度、Y Sort 与 <code>z_index</code></h3>
<p>高地画面向上移动：</p>
<pre><code class="language-text">screen_position = iso_position - Vector2(0, z × 33)
</code></pre>
<p>但角色被视觉抬高后，它的屏幕 Y 反而变小。仅使用 Y Sort，可能把高地角色判断成“更靠后”。</p>
<p>因此逻辑高度需要覆盖普通 Y Sort：</p>
<pre><code class="language-gdscript">z_index = current_surface.z * 10
</code></pre>
<p>这说明：</p>
<blockquote>
<p>Y Sort 适合解决同一逻辑平面上的前后顺序；跨逻辑层级时需要额外的绘制规则。</p>
</blockquote>
<h3 id="5-8-camera2d-canvaslayer-与-subviewport">5.8 Camera2D、CanvasLayer 与 SubViewport</h3>
<p>这三个节点经常同时出现在屏幕系统中，但职责完全不同：</p>
<table>
<thead>
<tr>
<th>节点</th>
<th>当前项目中的作用</th>
<th style="text-align:right">是否产生独立渲染目标</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Camera2D</code></td>
<td>决定主世界哪一部分映射到主 Viewport</td>
<td style="text-align:right">否</td>
</tr>
<tr>
<td><code>CanvasLayer</code></td>
<td>让 HUD 独立于主世界 Camera，固定在屏幕上</td>
<td style="text-align:right">否</td>
</tr>
<tr>
<td><code>SubViewport</code></td>
<td>为小地图建立独立 Canvas 和渲染结果</td>
<td style="text-align:right">是</td>
</tr>
</tbody>
</table>
<p>节点结构：</p>
<pre><code class="language-text">Interface: CanvasLayer
└── Minimap: PanelContainer
    └── SubViewportContainer
        └── SubViewport
            └── MinimapRenderer: Node2D
</code></pre>
<p>小地图没有用第二台 Camera 原样拍摄整个主世界，而是让 <code>MinimapRenderer._draw()</code> 根据共享逻辑数据绘制简化视图：</p>
<pre><code class="language-text">MAP_SIZE / HIGH_REGION / BLOCKED_CELLS / Ramp / Building
                       ↓
              MinimapRenderer._draw()
                       ↓
      地面、高地、阻挡、建筑、路径、目标、Player
</code></pre>
<p>这形成了同一模型的两种表现：</p>
<pre><code class="language-text">地图模型
├── 主世界：Tile、Sprite、遮挡、Camera
└── 小地图：颜色、线段和标记
</code></pre>
<p>Player 的连续 Grid 位置每帧同步；地图结构只初始化一次；路径和目标只在路线改变时更新。不同数据采用不同更新频率。</p>
<h2 id="6-三个项目放在一起后-节点职责更清楚了">6. 三个项目放在一起后，节点职责更清楚了</h2>
<h3 id="6-1-物理节点选择">6.1 物理节点选择</h3>
<pre><code class="language-text">需要主动移动且碰撞响应？
→ CharacterBody2D

需要成为会运动的实体表面？
→ AnimatableBody2D

只需要检测进入、离开、重叠？
→ Area2D

大量静态地形由 Tile 数据描述？
→ TileMapLayer + TileSet Physics Layer
</code></pre>
<p>具体对应：</p>
<table>
<thead>
<tr>
<th>需求</th>
<th>节点</th>
</tr>
</thead>
<tbody>
<tr>
<td>Platformer Player</td>
<td><code>CharacterBody2D</code></td>
</tr>
<tr>
<td>Room Player</td>
<td><code>CharacterBody2D</code></td>
</tr>
<tr>
<td>Moving/Falling Platform</td>
<td><code>AnimatableBody2D</code></td>
</tr>
<tr>
<td>Checkpoint / RoomExit / InteractionDetector</td>
<td><code>Area2D</code></td>
</tr>
<tr>
<td>横版地形与 Isometric 地面</td>
<td><code>TileMapLayer</code></td>
</tr>
</tbody>
</table>
<h3 id="6-2-四种-位置-不是同一个值">6.2 四种“位置”不是同一个值</h3>
<p>今天至少出现了四类位置：</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>示例</th>
<th>所有者</th>
</tr>
</thead>
<tbody>
<tr>
<td>物理世界位置</td>
<td><code>Player.global_position</code></td>
<td>Node2D / Physics</td>
</tr>
<tr>
<td>房间语义入口</td>
<td><code>room_id + entry_id</code></td>
<td>Room / GameSession</td>
</tr>
<tr>
<td>离散网格位置</td>
<td><code>Vector3i(x,y,z)</code></td>
<td>Navigation / Rule</td>
</tr>
<tr>
<td>屏幕与 Viewport 位置</td>
<td>鼠标、Camera 画面、小地图像素</td>
<td>Presentation</td>
</tr>
</tbody>
</table>
<p>它们之间应该通过明确函数转换，不能靠“看起来差不多”直接传递。</p>
<h3 id="6-3-三种生命周期">6.3 三种生命周期</h3>
<pre><code class="language-text">应用生命周期
└── GameSession / Autoload

运行关卡生命周期
└── Game / Player / Interface

内容生命周期
└── CurrentRoom / Props / 临时场景
</code></pre>
<p>对象应该放在哪一层，取决于它需要活多久，而不是它在节点树中看起来适合放哪里。</p>
<h3 id="6-4-三种更新方式">6.4 三种更新方式</h3>
<table>
<thead>
<tr>
<th>更新方式</th>
<th>当前用途</th>
<th>特点</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>_physics_process(delta)</code></td>
<td>Player 物理、平台运动、跌落检测</td>
<td>固定物理步，适合碰撞和运动</td>
</tr>
<tr>
<td><code>_process(delta)</code></td>
<td>Isometric Actor 插值、小地图 Player 点</td>
<td>每个渲染帧，适合非物理表现</td>
</tr>
<tr>
<td>Signal / 事件更新</td>
<td>房间切换、路径变化、Flag、Area 进入</td>
<td>状态变化时才执行</td>
</tr>
</tbody>
</table>
<p>不是所有逻辑都应该放进 <code>_process()</code>。能由事件驱动的状态，不需要每帧轮询。</p>
<h2 id="7-真实素材不是-最后再美化-而是工程输入">7. 真实素材不是“最后再美化”，而是工程输入</h2>
<p>Platformer 和 Isometric 都开始使用真正素材，但素材类型决定处理方式。</p>
<h3 id="7-1-source-与-runtime-分层">7.1 Source 与 Runtime 分层</h3>
<pre><code class="language-text">assets/source/
    完整供应商包、AI 原图、审计基线
            ↓ 选择、检查、转换
assets/runtime/
    游戏实际加载的最小集合
            ↓ 构建工具
TileSet / SpriteFrames / Scene
</code></pre>
<p>完整供应商包通过 <code>.gdignore</code> 避免 Godot 导入数百个不使用的文件；Runtime 目录只保留真正需要进入项目和导出的素材。</p>
<h3 id="7-2-为什么角色动画不继续切生成式大图">7.2 为什么角色动画不继续切生成式大图</h3>
<p>AI 图适合：</p>
<ul>
<li>背景氛围。</li>
<li>单张角色立绘。</li>
<li>概念草图。</li>
<li>对严格像素边界要求较低的素材。</li>
</ul>
<p>逐帧角色动画要求：</p>
<ul>
<li>每帧尺寸一致。</li>
<li>脚点稳定。</li>
<li>动作周期连续。</li>
<li>Alpha 边界可预测。</li>
<li>切片位置精确。</li>
</ul>
<p>Platformer 最终改用 SunnyLand 官方独立帧，而不是继续猜测 AI 大图中的帧边界。Isometric 当前只需要静态角色，因此 AI 透明 PNG 可以胜任。</p>
<p>关键不是坚持某一种素材来源，而是：</p>
<blockquote>
<p>根据资产的技术契约选择来源，并对尺寸、Alpha、脚点、授权和运行效果进行验收。</p>
</blockquote>
<h3 id="7-3-tileset-构建工具的价值">7.3 TileSet 构建工具的价值</h3>
<p>TileSet 包含 Atlas 坐标、Tile 尺寸、碰撞多边形、Custom Data 等结构化信息。用工具脚本生成派生 <code>.tres</code>，可以：</p>
<ul>
<li>固定输入素材和 Atlas 坐标。</li>
<li>避免 Inspector 手工操作无法复现。</li>
<li>自动重建碰撞和元数据。</li>
<li>用测试检查生成结果。</li>
</ul>
<p>所以资产管线也属于代码和测试范围，而不是仓库外的手工步骤。</p>
<h2 id="8-今天反复使用的工程模式">8. 今天反复使用的工程模式</h2>
<h3 id="8-1-数据所有权必须单一">8.1 数据所有权必须单一</h3>
<table>
<thead>
<tr>
<th>数据</th>
<th>权威所有者</th>
</tr>
</thead>
<tbody>
<tr>
<td>横版运动参数</td>
<td><code>MovementProfile</code></td>
</tr>
<tr>
<td>当前检查点</td>
<td><code>PlatformerWorld</code></td>
</tr>
<tr>
<td>当前房间和跨房 Flag</td>
<td><code>GameSession</code></td>
</tr>
<tr>
<td>当前挂载房间</td>
<td><code>RoomTransitionGame</code></td>
</tr>
<tr>
<td>Isometric 表面与连接</td>
<td><code>IsoHeightNavigation</code></td>
</tr>
<tr>
<td>主世界绘制</td>
<td>TileMap / Objects</td>
</tr>
<tr>
<td>小地图绘制</td>
<td><code>IsometricMinimap</code></td>
</tr>
</tbody>
</table>
<p>表现层可以读取或订阅数据，但不应该偷偷建立第二份权威状态。</p>
<h3 id="8-2-候选-验证-提交">8.2 候选—验证—提交</h3>
<p>昨天在 Tetris 旋转中出现，今天又用于房间切换：</p>
<pre><code class="language-text">构造候选状态
→ 验证是否合法
→ 验证通过才替换真实状态
</code></pre>
<p>后续背包交易、装备更换和存档加载都应该继续采用同一模式。</p>
<h3 id="8-3-scene-表达可复用对象-resource-表达可复用数据">8.3 Scene 表达可复用对象，Resource 表达可复用数据</h3>
<pre><code class="language-text">PlatformActor.tscn
→ 节点结构、碰撞、Trigger、Visuals

MovementProfile.tres
→ 速度、跳高、时间、容错参数
</code></pre>
<p>Scene 实例化后进入 SceneTree并拥有生命周期；Resource 通常被节点引用，保存配置和领域数据。</p>
<h3 id="8-4-signal-表达意图-所有者执行改变">8.4 Signal 表达意图，所有者执行改变</h3>
<pre><code class="language-text">Checkpoint body_entered
→ World 修改出生点

RoomExit transition_requested
→ Game 替换房间

Actor path_changed
→ 主场景和小地图更新路线表现
</code></pre>
<p>发出事件的对象不一定有权直接修改最终状态。</p>
<h3 id="8-5-调试表现是理解系统的工具">8.5 调试表现是理解系统的工具</h3>
<p>Platformer HUD 暴露：</p>
<ul>
<li>速度。</li>
<li>运动状态。</li>
<li>地面法线。</li>
<li>Coyote 和 Jump Buffer 计时。</li>
<li>Tile Cell 和 Surface Type。</li>
</ul>
<p>Isometric HUD 暴露：</p>
<ul>
<li>离散 Cell。</li>
<li>连续 Grid。</li>
<li>Map-local Pixel。</li>
<li>Z Level。</li>
<li>Path Steps。</li>
</ul>
<p>调试 UI 的价值不是好看，而是把不可见的运行状态变得可观察。学习项目尤其应该保留这种可解释性。</p>
<h2 id="9-自动测试与人工画面验收分别负责什么">9. 自动测试与人工画面验收分别负责什么</h2>
<h3 id="9-1-自动测试适合验证">9.1 自动测试适合验证</h3>
<ul>
<li>跳跃公式是否满足目标高度和时间。</li>
<li>Coyote、Buffer、Jump Cut 是否按条件发生。</li>
<li>TileSet 是否包含正确碰撞和 Custom Data。</li>
<li>所有平台高度是否在跳跃预算内。</li>
<li>房间与入口映射是否正确。</li>
<li>非法房间请求是否保留当前状态。</li>
<li>Flag 是否跨房间恢复。</li>
<li>Grid 正逆变换是否一致。</li>
<li>AStar 路径是否绕开阻挡并经过坡道。</li>
<li>高地 Player 是否获得正确 z-index。</li>
<li>SubViewport 小地图是否收到共享状态。</li>
<li>素材尺寸、Alpha 和来源记录是否符合契约。</li>
</ul>
<h3 id="9-2-人工运行适合判断">9.2 人工运行适合判断</h3>
<ul>
<li>加速、减速、顶点停留和下落是否舒服。</li>
<li>平台高度理论可达，但实际是否容易跳上去。</li>
<li>斜坡有没有卡顿或视觉错位。</li>
<li>淡出节奏是否自然。</li>
<li>建筑遮挡淡化是否让玩家看得清。</li>
<li>Character Sprite 的大小和脚点是否合适。</li>
<li><code>1152×648</code> Mac 窗口下 HUD 是否遮挡主要画面。</li>
<li>小地图信息是否能辨认。</li>
</ul>
<p>可以概括为：</p>
<blockquote>
<p>自动测试验证规则和契约，人负责判断手感、构图与可读性。</p>
</blockquote>
<h2 id="10-我们主动跳过了什么">10. 我们主动跳过了什么</h2>
<h3 id="10-1-platformer-没有继续加入敌人和战斗">10.1 Platformer 没有继续加入敌人和战斗</h3>
<p>Action Arena 已经实践过攻击、生命、伤害、敌人状态、音效和命中反馈。继续加入只会扩大关卡，而不会显著增加平台物理知识。</p>
<h3 id="10-2-room-transitions-保持诊断型画面">10.2 Room Transitions 保持诊断型画面</h3>
<p>这个短专项的独特价值是 Scene 生命周期、入口映射和跨房间状态。真实素材管线已经在 Platformer 中实践，因此没有再次花大量时间包装两间房。</p>
<h3 id="10-3-isometric-没有继续加入-npc-和战斗">10.3 Isometric 没有继续加入 NPC 和战斗</h3>
<p>Isometric 已覆盖投影、选格、AStar3D、Y Sort、高度、遮挡、Camera 和小地图。继续加入 NPC 战斗会重复 Action Arena 与 Room Transitions 的系统。</p>
<h3 id="10-4-没有把小地图扩展成完整导航产品">10.4 没有把小地图扩展成完整导航产品</h3>
<p>当前没有加入：</p>
<ul>
<li>点击小地图移动。</li>
<li>Camera 可见范围框。</li>
<li>敌人、任务和楼层筛选。</li>
<li>战争迷雾。</li>
<li>图标聚合。</li>
</ul>
<p>这些都可以继续做，但已经超出 Isometric 项目的必要学习上限。</p>
<h2 id="11-今天怎样继续训练-驾驭-ai">11. 今天怎样继续训练“驾驭 AI”</h2>
<h3 id="11-1-不接受只在代码里成立的功能">11.1 不接受只在代码里成立的功能</h3>
<p>AI 完成节点和脚本后，还需要：</p>
<pre><code class="language-text">Godot 导入
→ Parse / Headless Tests
→ 主场景启动
→ 真实渲染截图
→ 人工查看布局和素材
</code></pre>
<p>例如小地图测试通过，只能说明状态连接成立；实际 <code>1152×648</code> 截图才能确认它没有和 Telemetry 重叠。</p>
<h3 id="11-2-要求下一步和下下步">11.2 要求下一步和下下步</h3>
<p>先知道后续两步，可以判断当前实现是否在建立必要接口，还是在没有目标的情况下扩建。</p>
<p>但提前知道后续，不等于提前实现后续。当前 Demo 达到独特学习目标后，应主动停止。</p>
<h3 id="11-3-发现实现偏离预期时-回到原生节点">11.3 发现实现偏离预期时，回到原生节点</h3>
<p>角色动画曾经只有代码绘制表现，没有 <code>AnimatedSprite2D</code>。问题不是“画面能不能动”，而是它绕开了要学习的 Godot 原生动画资源和编辑器工作流。</p>
<p>修正后的标准是：</p>
<pre><code class="language-text">需要学习动画资源
→ AnimatedSprite2D + SpriteFrames

需要学习时间线和 Gameplay 事件
→ AnimationPlayer

需要复杂混合
→ 后续 AnimationTree 专项
</code></pre>
<h3 id="11-4-素材也要有契约和来源">11.4 素材也要有契约和来源</h3>
<p>不能只要求“换成真实贴图”，还应检查：</p>
<ol>
<li>来源和许可证。</li>
<li>原图与 Runtime 文件分层。</li>
<li>尺寸、Alpha 和脚点。</li>
<li>Tile 或动画帧的切割方式。</li>
<li>编辑器能否预览。</li>
<li>构建和导出时是否可用。</li>
</ol>
<h3 id="11-5-用问题审查架构-而不是逐行背代码">11.5 用问题审查架构，而不是逐行背代码</h3>
<p>面对 AI 生成的 Godot 项目，优先回答：</p>
<ol>
<li>根节点是谁？</li>
<li>哪些节点是常驻的，哪些会销毁？</li>
<li>权威状态保存在哪里？</li>
<li>谁只发出意图，谁真正提交修改？</li>
<li>坐标从哪个空间转换到哪个空间？</li>
<li>物理、导航和绘制各自负责什么？</li>
<li>哪些数据每帧更新，哪些只在事件发生时更新？</li>
<li>如何自动验证，如何人工验收？</li>
</ol>
<h2 id="12-关键词词典">12. 关键词词典</h2>
<h3 id="物理与运动">物理与运动</h3>
<ul>
<li><code>CharacterBody2D</code>：由代码控制速度，并通过 <code>move_and_slide()</code> 接受碰撞约束的角色物理体。</li>
<li><code>AnimatableBody2D</code>：适合移动平台等由脚本或动画改变位置、同时影响其他物理体的对象。</li>
<li><code>Area2D</code>：检测重叠，不提供普通实体阻挡。</li>
<li><code>velocity</code>：期望速度，不等于未经物理修正的最终位移。</li>
<li><code>Floor Normal</code>：角色与地面接触面的法向量。</li>
<li>One-way Collision：通常只从上方阻挡角色的平台碰撞。</li>
<li>Coyote Time：离开平台后短暂保留的起跳资格。</li>
<li>Jump Buffer：起跳条件满足前短暂保存的输入意图。</li>
<li>Jump Cut：松开跳跃键时削减上升速度，形成可变跳高。</li>
</ul>
<h3 id="场景与生命周期">场景与生命周期</h3>
<ul>
<li><code>PackedScene</code>：尚未实例化的可复用 Scene 资源。</li>
<li><code>instantiate()</code>：从 PackedScene 创建运行时节点树。</li>
<li><code>add_child()</code>：把节点加入 SceneTree，使其开始接收完整生命周期。</li>
<li><code>queue_free()</code>：在安全时机延迟销毁节点。</li>
<li>Autoload：在项目启动时挂载到根节点、可跨普通场景存在的全局节点。</li>
<li>Entry Marker：房间内部有语义名称的到达位置。</li>
<li>Mount：把已经验证的内容节点挂载到指定父节点。</li>
</ul>
<h3 id="tile-与空间">Tile 与空间</h3>
<ul>
<li><code>TileSet</code>：Tile 的纹理区域、几何、碰撞和元数据定义。</li>
<li><code>TileMapLayer</code>：使用 TileSet 在地图坐标上放置 Tile 的单层地图节点。</li>
<li>Grid Space：规则使用的逻辑格坐标。</li>
<li>Map-local Space：TileMapLayer 内部的二维像素坐标。</li>
<li>Viewport Space：窗口或渲染目标中的屏幕坐标。</li>
<li>Canvas Transform：世界 Canvas 与 Viewport 之间由 Camera 等产生的变换。</li>
<li>Isometric Projection：将正交逻辑网格映射到菱形屏幕布局的投影。</li>
<li>Foot Point：Sprite 对应地面接触位置的节点原点。</li>
</ul>
<h3 id="导航与绘制">导航与绘制</h3>
<ul>
<li><code>AStar3D</code>：在任意三维点图上寻找低成本路径；本项目用第三维表达逻辑高度。</li>
<li>Y Sort：根据同一排序上下文中的 CanvasItem Y 位置决定绘制顺序。</li>
<li><code>z_index</code>：显式调整 CanvasItem 绘制层级。</li>
<li><code>Camera2D</code>：决定主 Canvas 的观察位置、缩放和边界。</li>
<li><code>CanvasLayer</code>：为 HUD 建立不受主世界 Camera 影响的 Canvas 层。</li>
<li><code>SubViewport</code>：独立渲染一棵子节点树并产生 ViewportTexture。</li>
<li><code>SubViewportContainer</code>：在 Control UI 中显示 SubViewport 的渲染结果。</li>
<li><code>_draw()</code>：CanvasItem 的自定义绘制回调。</li>
<li><code>queue_redraw()</code>：请求 Godot 在后续绘制阶段再次调用 <code>_draw()</code>。</li>
</ul>
<h2 id="13-读完后应该能够回答的问题">13. 读完后应该能够回答的问题</h2>
<ol>
<li>为什么 Platformer Player 应调用 <code>move_and_slide()</code>，而不是直接修改 position？</li>
<li>为什么跳跃参数使用高度和时间，而不是同时手调初速度与重力？</li>
<li>Coyote Time 和 Jump Buffer 分别保存什么？</li>
<li><code>CharacterBody2D</code>、<code>AnimatableBody2D</code> 和 <code>Area2D</code> 在三个项目中分别对应哪些对象？</li>
<li>为什么静态地形使用 TileMapLayer，而移动木板使用独立 Scene？</li>
<li><code>get_floor_normal()</code> 怎样证明斜坡底层碰撞确实不同？</li>
<li>为什么 Player 和 HUD 不放在 CurrentRoom 里面？</li>
<li><code>PackedScene</code> 和实例化后的 Room Node 有什么区别？</li>
<li>为什么房间切换必须先验证新房间，再卸载旧房间？</li>
<li>为什么用 <code>room_id + entry_id</code>，而不是在门上写目标坐标？</li>
<li>Autoload 应该保存什么，为什么不应该控制所有节点？</li>
<li>未进入 SceneTree 的实例为什么不能依赖 <code>@onready</code> 字段？</li>
<li>Isometric 地图的逻辑网格是否真的旋转了 45°？</li>
<li>离散 Cell、连续 Grid 和 Map-local Pixel 分别用在什么地方？</li>
<li>Camera2D 启用后，为什么鼠标事件需要转换回世界坐标？</li>
<li>为什么 99px 高的地砖图片可以拥有 66px 高的逻辑 Tile 脚印？</li>
<li>Y Sort、Occlusion Area 和 AStar 阻挡分别解决什么问题？</li>
<li>二维游戏为什么会选择 AStar3D？</li>
<li>为什么高地角色还需要显式 z-index？</li>
<li>Camera2D、CanvasLayer 和 SubViewport 的底层职责有什么不同？</li>
<li>为什么小地图没有直接重复渲染主世界的所有 Sprite？</li>
<li>哪些状态应该每帧同步，哪些应该由 Signal 更新？</li>
<li>为什么真正素材也需要自动测试和授权记录？</li>
<li>自动测试与人工画面验收各自不能替代什么？</li>
<li>怎样判断一个教学 Demo 已经达到学习上限，应当停止扩建？</li>
</ol>
<h2 id="14-下一步">14. 下一步</h2>
<p>下一项目进入：</p>
<pre><code class="language-text">07-inventory-shop/
</code></pre>
<p>它承担长期路线中的“背包 + 商店 + 装备”，重点第一次系统学习数据层：</p>
<pre><code class="language-text">ItemDefinition: Resource
→ Inventory Model
→ Inventory Slot / Stack Rule
→ Control UI
→ Drag and Drop
→ Shop Transaction
→ Equipment Rule
→ Serialization / Save
</code></pre>
<p>这里会继续复用今天的原则：</p>
<ul>
<li>Resource 定义共享物品数据。</li>
<li>背包模型是权威状态，UI 只是表现。</li>
<li>买卖采用候选—验证—提交，避免金币和物品只改了一边。</li>
<li>拖放事件表达用户意图，Inventory 决定操作是否合法。</li>
<li>存档加载先验证，再替换当前状态。</li>
</ul>
<p>真正的新增目标不是画出一排物品格，而是让数据模型、UI、交易和持久化第一次形成完整闭环。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/519</guid>
      <pubDate>Tue, 25 Aug 2026 23:09:51 +0800</pubDate>
    </item>
    <item>
      <title>您当天已发布较多，为保证质量，请明天再发布新主题</title>
      <link>https://gooseforum.online/p/post/517</link>
      <description>管理员自己发布出现这个提示绷不住了，可否解除这个限制？</description>
      <content:encoded><![CDATA[<p>管理员自己发布出现这个提示绷不住了，可否解除这个限制？</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/517</guid>
      <pubDate>Tue, 25 Aug 2026 13:59:12 +0800</pubDate>
    </item>
    <item>
      <title>gooseforum 0.2.61第一次出现报错？</title>
      <link>https://gooseforum.online/p/post/515</link>
      <description>报错错误：Error: rebuild topic main category search index: Meilisearch is configured but unavailable 0.2.60以下都正常没有报错 Meilisearch这个0.2.60以下都有吧？</description>
      <content:encoded><![CDATA[<p>报错错误：Error: rebuild topic main category search index: Meilisearch is configured but unavailable</p>
<p>0.2.60以下都正常没有报错</p>
<p>Meilisearch这个0.2.60以下都有吧？</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/515</guid>
      <pubDate>Tue, 25 Aug 2026 10:02:52 +0800</pubDate>
    </item>
    <item>
      <title>怀念之前空闲的时候从php官方看文档发现好玩的函数的日子</title>
      <link>https://gooseforum.online/p/post/516</link>
      <description></description>
      <content:encoded><![CDATA[<p>RT</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/516</guid>
      <pubDate>Tue, 25 Aug 2026 11:18:43 +0800</pubDate>
    </item>
    <item>
      <title>从 AI 生成代码到驾驭游戏工程：Godot 三个练习的完整学习总结</title>
      <link>https://gooseforum.online/p/post/514</link>
      <description>日期：2026-08-24 项目：Snake → Tetris → Action Arena 目标读者：准备借助 AI 入门游戏开发，但不满足于“代码能跑”，希望能理解、判断、修改和继续扩展的人。 1. 今天真正练习的不是三个小游戏 表面上，我们实现了贪吃蛇、俄罗斯方块和俯视角动作竞技场。真正的学习路线是： 先理解 Godot 如何启动、更新和连接节点。 再学习如何用数据表达游戏世界，而不是用画面...</description>
      <content:encoded><![CDATA[<blockquote>
<p>日期：2026-08-24<br/>
项目：Snake → Tetris → Action Arena<br/>
目标读者：准备借助 AI 入门游戏开发，但不满足于“代码能跑”，希望能理解、判断、修改和继续扩展的人。</p>
</blockquote>
<h2 id="1-今天真正练习的不是三个小游戏">1. 今天真正练习的不是三个小游戏</h2>
<p>表面上，我们实现了贪吃蛇、俄罗斯方块和俯视角动作竞技场。真正的学习路线是：</p>
<ol>
<li>先理解 Godot 如何启动、更新和连接节点。</li>
<li>再学习如何用数据表达游戏世界，而不是用画面节点代替数据。</li>
<li>再把规则、角色能力、状态、配置、AI 和表现拆成可以独立思考的系统。</li>
<li>最后学习怎样让 AI 生成的代码仍然可检查、可替换、可测试、可继续扩展。</li>
</ol>
<p>三个项目分别承担了不同职责：</p>
<table>
<thead>
<tr>
<th>项目</th>
<th>表面玩法</th>
<th>核心学习领域</th>
<th>最重要的认知变化</th>
</tr>
</thead>
<tbody>
<tr>
<td>Snake</td>
<td>网格移动、吃食物、增长</td>
<td>Godot 生命周期、Node、Scene、Signal、Timer、输入、绘制</td>
<td>画面只是数据的显示结果</td>
</tr>
<tr>
<td>Tetris</td>
<td>方块移动、旋转、锁定、消行</td>
<td>二维数组、坐标变换、候选状态、规则模型、随机算法</td>
<td>先验证候选结果，再提交状态修改</td>
</tr>
<tr>
<td>Action Arena</td>
<td>移动、攻击、敌人、受击、特效</td>
<td>组件、状态机、Resource、事件载荷、寻路、动画、音频、VFX</td>
<td>Gameplay、AI、数据和表现应该解耦</td>
</tr>
</tbody>
</table>
<p>这条路线可以概括为：</p>
<pre><code class="language-mermaid">flowchart LR
    A[Godot 运行模型] --&gt; B[数据表达游戏状态]
    B --&gt; C[规则与表现分离]
    C --&gt; D[组件化与状态机]
    D --&gt; E[数据驱动与事件解耦]
    E --&gt; F[AI / 动画 / 音频 / VFX]
    F --&gt; G[能够审查和驾驭 AI 生成的项目]
</code></pre>
<h2 id="2-先建立-godot-的总心智模型">2. 先建立 Godot 的总心智模型</h2>
<h3 id="2-1-godot-没有传统意义上的-main">2.1 Godot 没有传统意义上的 <code>main()</code></h3>
<p>Godot 的入口不是某个由我们手写的 <code>main()</code> 函数，而是：</p>
<pre><code class="language-text">project.godot
    ↓ run/main_scene
入口 .tscn 场景
    ↓ Godot 实例化节点树
各节点收到生命周期回调
</code></pre>
<p>常见回调包括：</p>
<ul>
<li><code>_ready()</code>：节点已经进入 SceneTree，并且子节点已经准备完成。</li>
<li><code>_process(delta)</code>：每个渲染帧调用，适合 UI、普通动画和视觉时间。</li>
<li><code>_physics_process(delta)</code>：按固定物理频率调用，适合移动与物理逻辑。</li>
<li><code>_unhandled_input(event)</code>：接收尚未被 UI 等系统处理掉的输入事件。</li>
<li><code>_draw()</code>：自定义绘制函数；调用 <code>queue_redraw()</code> 后，Godot 会安排重新绘制。</li>
</ul>
<p>开头的下划线不是“私有”的语法标记。对于 <code>_ready()</code>、<code>_process()</code> 等函数，它表示 Godot 约定的引擎回调；对于 <code>_on_timer_timeout()</code>，则只是常用命名风格，真正使它运行的是 Signal Connection。</p>
<p>例如：</p>
<pre><code class="language-text">Timer 发出 timeout
    ↓ 场景中的 connection
_on_move_timer_timeout()
</code></pre>
<p>把函数改名为 <code>move_snake_now()</code> 也可以，只要 Signal 连接同步修改。因此：</p>
<blockquote>
<p>函数名帮助人理解，连接关系决定事件最终调用谁。</p>
</blockquote>
<h3 id="2-2-scene-node-script-的关系">2.2 Scene、Node、Script 的关系</h3>
<p>可以把 Godot 的核心关系理解为：</p>
<pre><code class="language-text">Scene（可保存、可复用的节点树）
└── Node（运行时对象）
    ├── 属性
    ├── 子节点
    ├── Signal
    └── Script（附加行为）
</code></pre>
<ul>
<li>Node 是组成游戏的基本运行对象。</li>
<li>Scene 是一棵可以保存为 <code>.tscn</code>、以后重复实例化的节点树。</li>
<li>Script 是附着在节点上的行为，不等于节点本身。</li>
<li>SceneTree 是当前正在运行的整棵节点树。</li>
<li>Main Scene 是项目启动时首先实例化的场景。</li>
</ul>
<h3 id="2-3-与-web-dom-js-的类比">2.3 与 Web/DOM/JS 的类比</h3>
<p>这个类比非常有用，但不是完全等价：</p>
<table>
<thead>
<tr>
<th>Godot</th>
<th>Web 类比</th>
<th>共同点</th>
<th>需要注意的差异</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>project.godot</code></td>
<td>应用配置、构建配置和入口配置</td>
<td>声明项目如何启动</td>
<td>它同时包含渲染、窗口、输入、物理等引擎配置</td>
</tr>
<tr>
<td><code>.tscn</code> Scene</td>
<td>HTML 模板或 React 组件树</td>
<td>描述结构与组合关系</td>
<td>Scene 可以包含物理体、音频、Timer、资源引用等游戏对象</td>
</tr>
<tr>
<td>Node Tree</td>
<td>DOM Tree</td>
<td>都是父子层级结构</td>
<td>Node 不一定可见，也可能只是规则、计时器或音频对象</td>
</tr>
<tr>
<td><code>.gd</code> Script</td>
<td>JavaScript/TypeScript 模块</td>
<td>提供行为和事件处理</td>
<td>GDScript 深度集成引擎生命周期、场景树和资源系统</td>
</tr>
<tr>
<td><code>$Node/Child</code></td>
<td><code>querySelector()</code> 或 React ref</td>
<td>获取已存在对象的引用</td>
<td><code>$</code> 使用 NodePath，不是 CSS Selector</td>
</tr>
<tr>
<td>Signal</td>
<td>DOM Event、CustomEvent、EventEmitter</td>
<td>发送方不必知道全部接收方</td>
<td>Signal Connection 可以保存在场景资源里</td>
</tr>
<tr>
<td><code>_ready()</code></td>
<td>mounted、<code>connectedCallback()</code></td>
<td>结构准备完成后初始化</td>
<td>Godot 明确依赖 SceneTree 生命周期</td>
</tr>
<tr>
<td><code>_process(delta)</code></td>
<td><code>requestAnimationFrame()</code></td>
<td>每帧更新</td>
<td><code>delta</code> 是上一帧经过的秒数</td>
</tr>
<tr>
<td><code>_physics_process(delta)</code></td>
<td>固定步长模拟循环</td>
<td>稳定推进运动规则</td>
<td>浏览器没有完全对应的默认物理循环</td>
</tr>
<tr>
<td>Timer</td>
<td><code>setTimeout</code> / <code>setInterval</code></td>
<td>时间到后发出事件</td>
<td>Godot Timer 是节点，可暂停、受 time scale 影响、进入场景树</td>
</tr>
<tr>
<td>Group</td>
<td>class、tag、语义标记</td>
<td>不依赖具体节点名称识别对象</td>
<td>Group 还可以用于批量调用场景树对象</td>
</tr>
<tr>
<td><code>@export</code></td>
<td>Component props + 可视化配置面板</td>
<td>从外部注入配置</td>
<td>Godot Inspector 可以直接编辑资源和节点引用</td>
</tr>
<tr>
<td><code>.tres</code> Resource</td>
<td>JSON 配置对象、可序列化数据资产</td>
<td>数据与逻辑分离</td>
<td>Resource 有类型、Inspector、引用和资源缓存语义</td>
</tr>
<tr>
<td><code>PackedScene</code></td>
<td>组件模板、构造器</td>
<td>尚未实例化的可复用模板</td>
<td>实例化后得到真正的节点树</td>
</tr>
<tr>
<td><code>instantiate()</code></td>
<td><code>createElement()</code>、组件 mount</td>
<td>创建运行时实例</td>
<td>创建后还需进入 SceneTree 才接收完整生命周期</td>
</tr>
<tr>
<td><code>add_child()</code></td>
<td><code>appendChild()</code></td>
<td>加入树结构</td>
<td>同时影响处理、绘制、物理和销毁生命周期</td>
</tr>
<tr>
<td><code>queue_free()</code></td>
<td>unmount、<code>remove()</code></td>
<td>从运行结构移除</td>
<td>Godot 延迟到安全时机销毁对象</td>
</tr>
<tr>
<td>Tween</td>
<td>Web Animations API、GSAP Tween</td>
<td>插值改变属性</td>
<td>Godot Tween 可直接操作 Node/Resource 属性</td>
</tr>
<tr>
<td>AnimationPlayer</td>
<td>GSAP Timeline、CSS/WAAPI 时间线</td>
<td>多轨道、关键帧、事件点</td>
<td>可以在时间线上调用 Gameplay 方法</td>
</tr>
</tbody>
</table>
<p>最重要的类比是：</p>
<blockquote>
<p><code>.tscn</code> 更像结构模板，<code>.gd</code> 更像行为模块；但 Godot 的节点不仅是 DOM 元素，也可能是物理、音频、导航、计时和纯逻辑对象。</p>
</blockquote>
<h3 id="2-4-常见文件与路径">2.4 常见文件与路径</h3>
<table>
<thead>
<tr>
<th>后缀或路径</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>project.godot</code></td>
<td>项目配置，并通过 <code>run/main_scene</code> 指向入口场景</td>
</tr>
<tr>
<td><code>.tscn</code></td>
<td>文本格式的 Scene，保存节点树和资源引用</td>
</tr>
<tr>
<td><code>.gd</code></td>
<td>GDScript 源代码</td>
</tr>
<tr>
<td><code>.tres</code></td>
<td>文本格式的 Resource 数据资产</td>
</tr>
<tr>
<td><code>.uid</code></td>
<td>Godot 为资源生成的稳定身份，用于资源重命名或移动后的引用追踪</td>
</tr>
<tr>
<td><code>.import</code></td>
<td>Godot 对图片、音频等外部资产的导入配置</td>
</tr>
<tr>
<td><code>.godot/</code></td>
<td>本机导入缓存和编辑器缓存，通常不提交 Git</td>
</tr>
<tr>
<td><code>res://</code></td>
<td>当前 Godot 项目的资源根目录</td>
</tr>
</tbody>
</table>
<p>并不是所有字符串都要加 <code>res://</code>：</p>
<ul>
<li>加载项目文件时使用：<code>preload(&#34;res://scripts/game.gd&#34;)</code>。</li>
<li>场景内查找子节点时使用 NodePath：<code>$StateMachine/Idle</code>。</li>
<li>普通字符串、Signal 名称、Group 名称不需要 <code>res://</code>。</li>
</ul>
<h2 id="3-项目目录-领域边界比文件数量更重要">3. 项目目录：领域边界比文件数量更重要</h2>
<p>省略 <code>.uid</code>、<code>.import</code> 和编辑器缓存后，仓库的主要结构是：</p>
<pre><code class="language-text">godot-learning-roadmap/
├── 01-snake/
│   ├── project.godot
│   ├── main.tscn
│   ├── scripts/
│   │   ├── main.gd
│   │   ├── snake_game.gd
│   │   └── grid_utils.gd
│   └── tests/
├── 02-tetris/
│   ├── project.godot
│   ├── main.tscn
│   ├── scripts/
│   │   ├── main.gd
│   │   ├── tetris_board.gd
│   │   ├── tetromino.gd
│   │   ├── tetromino_catalog.gd
│   │   └── tetromino_bag.gd
│   └── tests/
└── 03-action-arena/
    ├── assets/audio/
    ├── resources/attacks/
    ├── scenes/
    │   ├── world.tscn
    │   ├── player.tscn
    │   ├── enemy.tscn
    │   └── effects/hit_effect.tscn
    └── scripts/
        ├── actors/
        │   ├── player.gd
        │   ├── enemy.gd
        │   ├── player_states/
        │   ├── enemy_states/
        │   └── shared_states/
        ├── combat/
        ├── components/
        ├── data/
        ├── presentation/
        ├── state_machine/
        └── world.gd
</code></pre>
<p>目录不是为了“看起来专业”，而是在表达领域：</p>
<ul>
<li><code>actors/</code>：角色拥有哪些能力。</li>
<li><code>states/</code>：角色在什么条件下使用能力。</li>
<li><code>components/</code>：可组合、职责单一的 Gameplay 功能。</li>
<li><code>data/</code> 和 <code>resources/</code>：配置结构与具体配置资产。</li>
<li><code>combat/</code>：一次战斗事件的数据协议。</li>
<li><code>presentation/</code>：镜头、音频、粒子、数字等反馈。</li>
<li><code>scenes/</code>：上述对象怎样被装配起来。</li>
</ul>
<p>AI 生成项目时，目录树是第一份架构文档。先读目录，再读事件流，最后才需要逐行读代码。</p>
<h2 id="4-snake-先理解运行循环与数据模型">4. Snake：先理解运行循环与数据模型</h2>
<h3 id="4-1-固定-tick-与逐帧表现">4.1 固定 Tick 与逐帧表现</h3>
<p>贪吃蛇不是每一帧移动一点，而是每隔固定时间移动一格：</p>
<pre><code class="language-mermaid">sequenceDiagram
    participant Input as 输入事件
    participant Model as SnakeGame
    participant Timer as MoveTimer
    participant View as main.gd / _draw

    Input-&gt;&gt;Model: queue_direction(direction)
    Timer-&gt;&gt;Model: step()
    Model--&gt;&gt;Timer: MOVED / ATE_FOOD / HIT_WALL / HIT_SELF
    Timer-&gt;&gt;View: 更新 UI、状态、VFX
    View-&gt;&gt;View: queue_redraw()
</code></pre>
<p>这里分成两种时间：</p>
<ul>
<li>Rule Tick：由 <code>Timer.timeout</code> 驱动，每次处理一格移动。</li>
<li>Render Frame：由 <code>_process(delta)</code> 驱动，用于食物呼吸和吃到食物的扩散圆环。</li>
</ul>
<p>这比“所有东西都放进 <code>_process()</code>”更容易保证规则稳定。</p>
<h3 id="4-2-蛇身不是递归-而是有序序列">4.2 蛇身不是递归，而是有序序列</h3>
<p>蛇身使用：</p>
<pre><code class="language-gdscript">Array[Vector2i]
</code></pre>
<p>数组中的第一个元素是蛇头，后面的元素依次表示身体。普通移动的核心是：</p>
<pre><code class="language-text">计算新蛇头
→ push_front(new_head)
→ 如果没吃食物，pop_back()
</code></pre>
<p>所以之前的直觉“移除最后一个，然后加第一个”基本正确。准确说是：增加新的头部，并在普通移动时移除旧尾部。吃到食物时不移除尾部，因此长度增加。</p>
<p>没有使用递归，因为身体不是“节点包含下一个节点”的链式调用；它只是一次遍历即可绘制的有序坐标数组。</p>
<h3 id="4-3-为什么没有只用-map-保存身体">4.3 为什么没有只用 Map 保存身体</h3>
<p>Map/Dictionary 或 Set 很适合回答：</p>
<pre><code class="language-text">某个格子是否已被占用？
</code></pre>
<p>但蛇还需要回答：</p>
<pre><code class="language-text">谁是头？
谁是尾？
身体顺序是什么？
下一步应该删除哪一格？
</code></pre>
<p>这些是有序序列问题，因此 Array 更自然。大型蛇可以使用混合结构：</p>
<pre><code class="language-text">Array / Deque：维护身体顺序
Set / Dictionary：O(1) 查询占用
</code></pre>
<p>当前棋盘很小，遍历成本可以忽略；为了学习清晰度，先使用单一 Array。</p>
<h3 id="4-4-输入缓冲">4.4 输入缓冲</h3>
<p>如果玩家在两个 Tick 之间快速按“上、左”，只保存最后一个按键可能丢失意图。我们使用最多两个方向的队列：</p>
<pre><code class="language-text">渲染帧输入：上 → 左
规则 Tick 1：消费“上”
规则 Tick 2：消费“左”
</code></pre>
<p>禁止反向时比较的不是当前方向，而是“最后一个已经计划的方向”。这是实时输入系统常见的 Buffered Input。</p>
<h3 id="4-5-模型与表现分离">4.5 模型与表现分离</h3>
<p><code>SnakeGame</code> 继承 <code>RefCounted</code>，不进入 SceneTree：</p>
<ul>
<li>它保存蛇身、食物、方向、分数和碰撞规则。</li>
<li>它不知道 Label、Timer、颜色或屏幕坐标。</li>
<li><code>main.gd</code> 负责输入、节点、UI、绘制和 VFX。</li>
</ul>
<p>这是今天第一次建立清晰的 Model/View 边界。</p>
<p>Web 类比：</p>
<pre><code class="language-text">SnakeGame ≈ reducer / domain model
main.gd ≈ UI controller / component
_draw() ≈ 根据 state 渲染 UI
StepResult ≈ domain event / action result
</code></pre>
<h3 id="4-6-测试学到了什么">4.6 测试学到了什么</h3>
<p>Snake 的纯规则模型可以无头运行：</p>
<pre><code class="language-bash">/Applications/Godot.app/Contents/MacOS/Godot \
  --headless \
  --path 01-snake \
  --script res://tests/test_snake_game.gd
</code></pre>
<p>无头不是唯一执行方式，只是自动化最方便的方式。还可以：</p>
<ul>
<li>把测试脚本挂到专门测试场景并从编辑器运行。</li>
<li>使用 GUT 等第三方测试插件。</li>
<li>直接运行普通游戏场景做人工交互验证。</li>
</ul>
<p>无头测试的价值是速度快、退出码明确、适合 AI 每次改动后自动验证。</p>
<h2 id="5-tetris-用候选状态驾驭复杂规则">5. Tetris：用候选状态驾驭复杂规则</h2>
<h3 id="5-1-棋盘为什么用二维数组">5.1 棋盘为什么用二维数组</h3>
<p>俄罗斯方块的核心问题是占用关系：一个确定的 <code>10 × 20</code> 空间里，哪些格子是空的，哪些已锁定。</p>
<pre><code class="language-text">cells[y][x] = -1    空格
cells[y][x] = 0..6  某种方块颜色/类型
</code></pre>
<p>这是稠密、固定大小的二维空间，二维数组比 Dictionary 更直观：</p>
<ul>
<li>容量只有 200 格。</li>
<li>消行天然按 row 操作。</li>
<li>绘制天然按 y/x 遍历。</li>
<li>不需要为稀疏存储增加复杂度。</li>
</ul>
<h3 id="5-2-局部坐标与棋盘坐标">5.2 局部坐标与棋盘坐标</h3>
<p>Tetromino 不直接保存四个绝对棋盘坐标，而是保存：</p>
<pre><code class="language-text">四个 local_cells + 一个 position
</code></pre>
<p>换算关系：</p>
<pre><code class="language-text">board_cell = position + local_cell
</code></pre>
<p>Web/图形类比：一个 SVG Group 或 DOM 容器拥有整体 transform，子元素保存相对位置。移动整个方块只需修改 <code>position</code>，不需要分别修改四个格子。</p>
<h3 id="5-3-候选-验证-提交">5.3 候选—验证—提交</h3>
<p>旋转和移动都遵守同一个重要模式：</p>
<pre><code class="language-mermaid">flowchart LR
    A[当前合法状态] --&gt; B[计算候选状态]
    B --&gt; C{can_place?}
    C -- 是 --&gt; D[提交修改]
    C -- 否 --&gt; A
</code></pre>
<p>旋转不是先改再撤销，而是：</p>
<ol>
<li>计算候选局部坐标 <code>(x, y) → (-y, x)</code>。</li>
<li>转换成棋盘坐标。</li>
<li>检查边界和固定格。</li>
<li>全部合法才 <code>apply_shape()</code>。</li>
</ol>
<p>这个模式可以迁移到很多领域：</p>
<ul>
<li>背包是否能放入物品。</li>
<li>技能是否有足够资源。</li>
<li>建筑是否能放在地图上。</li>
<li>网络服务器是否接受客户端操作。</li>
<li>数据库事务是否满足约束。</li>
</ul>
<h3 id="5-4-为什么有多个地方调用-lock-active-piece">5.4 为什么有多个地方调用 <code>_lock_active_piece()</code></h3>
<p>锁定方块有两个不同触发入口：</p>
<pre><code class="language-text">Gravity / Soft Drop 无法继续向下
                    ├──→ _lock_active_piece()
Hard Drop 到达落点 ─┘
</code></pre>
<p>它们触发原因不同，但锁定后的规则完全相同：写入棋盘、消行、计分、生成新方块、判断 Game Over。因此应该汇聚到同一个函数，避免复制两份规则。</p>
<p>这叫“多个入口，一个领域操作”，与 Web 中多个按钮最终调用同一个 service method 类似。</p>
<h3 id="5-5-7-bag-next-ghost-与-hard-drop">5.5 7-bag、Next、Ghost 与 Hard Drop</h3>
<ul>
<li>7-bag：七种方块各放一次，Fisher–Yates 洗牌，一袋用完再生成下一袋。</li>
<li>Next Piece：提前从 bag 取出一个类型作为预览。</li>
<li>Ghost Piece：逐格计算还能下降的距离，只绘制半透明候选位置。</li>
<li>Hard Drop：复用同一个下降距离，移动并立即锁定。</li>
</ul>
<p>Ghost 与 Hard Drop 共用规则非常重要：</p>
<blockquote>
<p>视觉预测和真实执行必须来自同一个计算，否则 AI 很容易生成“影子在这里，实际落在另一格”的重复逻辑 Bug。</p>
</blockquote>
<h2 id="6-action-arena-从规则脚本进入游戏架构">6. Action Arena：从规则脚本进入游戏架构</h2>
<p><img src="/file/img/2026/08/24/3ddc044d-f925-43b5-8548-37c0cebae8df.webp" alt="Action Arena 最终运行画面：玩家、绕障路径、敌人状态、生命条和命中火花" loading="lazy" decoding="async"/></p>
<p>上图来自当前 Godot 项目的真实运行截帧。橙红折线是 NavigationAgent2D 的调试路径；角色头顶文字是当前 FSM 状态；右侧敌人身上的橙色点状爆发和伤害数字来自临时 HitEffect 场景。</p>
<h3 id="6-1-最小战斗闭环">6.1 最小战斗闭环</h3>
<p>最早的闭环只有：</p>
<pre><code class="language-text">Player 移动
→ 开启 Hitbox
→ Enemy Hurtbox 收到命中
→ HealthComponent 扣血
→ 血量归零后 Enemy queue_free()
</code></pre>
<p>这里建立了三个可复用组件：</p>
<ul>
<li>Hitbox：攻击生效区域，负责发送伤害。</li>
<li>Hurtbox：可受击区域，负责接收并转发命中。</li>
<li>HealthComponent：管理生命值，发出 <code>health_changed</code>、<code>damaged</code>、<code>died</code>。</li>
</ul>
<p>Hitbox 不应该直接写：</p>
<pre><code class="language-gdscript">enemy.health -= 1
</code></pre>
<p>因为这会要求攻击者认识 Enemy 的具体结构。当前方案让 Hitbox 只寻找拥有 <code>receive_hit()</code> 的 Area，Hurtbox 再通过 Signal 转发。</p>
<h3 id="6-2-signal-是解耦-不只是回调写法">6.2 Signal 是解耦，不只是回调写法</h3>
<p>同一个 <code>Hurtbox.hit_received</code> 可以有多个监听者：</p>
<pre><code class="language-mermaid">flowchart LR
    A[Hurtbox.hit_received] --&gt; B[HealthComponent.take_hit]
    A --&gt; C[Actor 请求命中反馈]
    B --&gt; D[扣血 / damaged / died]
    C --&gt; E[音效 / 震动 / Hit Stop / 粒子 / 伤害数字]
</code></pre>
<p>Gameplay 和 Presentation 收到同一个事实，但各自处理自己的领域。这类似 Web 中一次业务事件同时更新 Store、埋点和通知 UI。</p>
<h3 id="6-3-有限状态机-fsm">6.3 有限状态机 FSM</h3>
<p>Player 同时只能处于：</p>
<pre><code class="language-mermaid">stateDiagram-v2
    [*] --&gt; Idle
    Idle --&gt; Move: 有方向输入
    Move --&gt; Idle: 方向归零
    Idle --&gt; Attack: 攻击输入且冷却完成
    Move --&gt; Attack: 攻击输入且冷却完成
    Attack --&gt; Idle: 动画结束
    Idle --&gt; Hurt: 收到攻击
    Move --&gt; Hurt: 收到攻击
    Attack --&gt; Hurt: 收到攻击，中断攻击
    Hurt --&gt; Idle: 硬直结束
</code></pre>
<p>Enemy 复用相同的 StateMachine 调度器，但使用不同策略：</p>
<pre><code class="language-text">Idle → Chase → Attack
  ↖       ↑       ↓
    Hurt 恢复后根据目标决定
</code></pre>
<p>关键职责：</p>
<ul>
<li>StateMachine：保存唯一 <code>current_state</code>，调用 <code>exit()</code>/<code>enter()</code>，转发输入和物理帧。</li>
<li>State：决定什么时候请求转换。</li>
<li>Actor：提供移动、攻击、停止、受伤等能力。</li>
<li>State 不直接替换 <code>current_state</code>，只发出 <code>transition_requested</code>。</li>
</ul>
<p>Web 类比：</p>
<pre><code class="language-text">StateMachine ≈ reducer / XState machine
State Node ≈ 某个状态下允许的 action handler
Actor 能力 ≈ service / command methods
transition_requested ≈ dispatch(action)
</code></pre>
<p>状态机解决的是“当前谁有决策权”，不是把所有函数机械地拆成文件。</p>
<h3 id="6-4-数据驱动-attackdata-与-tres">6.4 数据驱动：AttackData 与 <code>.tres</code></h3>
<p><code>AttackData</code> 定义攻击配置结构：</p>
<pre><code class="language-text">damage
knockback_force
hitstun_duration
active_duration
cooldown_duration
reach
hitbox_size
</code></pre>
<p><code>basic_slash.tres</code> 和 <code>enemy_strike.tres</code> 是两份具体数据：</p>
<pre><code class="language-text">AttackData.gd：定义 schema / 类型
basic_slash.tres：一条具体配置记录
player.tscn：把配置注入 Player
Player：消费配置，不硬编码每个数值
</code></pre>
<p>Web 类比：TypeScript interface/class 定义结构，JSON/数据库记录保存具体值，组件通过 props 或依赖注入获得配置。</p>
<p>注意：Resource 是持久配置，不等于运行时事件。</p>
<h3 id="6-5-attackdata-与-hitdata-为什么是两个对象">6.5 AttackData 与 HitData 为什么是两个对象</h3>
<table>
<thead>
<tr>
<th>对象</th>
<th>生命周期</th>
<th>表达的问题</th>
</tr>
</thead>
<tbody>
<tr>
<td>AttackData</td>
<td>长期保存、可复用、可在 Inspector 编辑</td>
<td>“这种攻击通常是什么参数？”</td>
</tr>
<tr>
<td>HitData</td>
<td>每次命中临时创建</td>
<td>“这一次是谁从哪里打中了我？”</td>
</tr>
</tbody>
</table>
<p>HitData 携带：</p>
<ul>
<li>本次伤害。</li>
<li>攻击来源位置。</li>
<li>击退力度。</li>
<li>硬直时间。</li>
</ul>
<p>这种对象也叫 Event Payload、Message、DTO。Signal 不是只能发出“发生了”，还可以携带事件上下文。</p>
<h3 id="6-6-碰撞-layer-与-mask">6.6 碰撞 Layer 与 Mask</h3>
<ul>
<li>Layer：我属于哪些类别，“我是谁”。</li>
<li>Mask：我希望检测哪些类别，“我要找谁”。</li>
</ul>
<p>本项目使用独立通道：</p>
<pre><code class="language-text">Player Hitbox  → Enemy Hurtbox
Enemy Hitbox   → Player Hurtbox
Player Body    ↔ Arena Wall
Enemy Body     ↔ Arena Wall
</code></pre>
<p>它更像一张允许通信的过滤矩阵，不是 CSS 的 <code>z-index</code>。视觉遮挡顺序和物理 Layer 是两件事。</p>
<h3 id="6-7-敌人感知与语义身份">6.7 敌人感知与语义身份</h3>
<p>Enemy 的 <code>PerceptionArea</code> 通过 <code>body_entered</code> 和 <code>body_exited</code> 维护 target。Player 通过 <code>player</code> Group 表达身份，不依赖节点名必须叫 <code>Player</code>。</p>
<pre><code class="language-text">PerceptionArea 检测 Body
→ body.is_in_group(&#34;player&#34;)
→ 保存 target 引用
→ Idle 请求 Chase
</code></pre>
<p>Group 相当于语义标签。它比检查具体脚本类型或固定路径更松耦合。</p>
<h3 id="6-8-寻路与物理碰撞不是同一件事">6.8 寻路与物理碰撞不是同一件事</h3>
<p>场景中的墙被两个系统描述：</p>
<pre><code class="language-text">NavigationPolygon 的空洞：告诉 AI 路线不能经过这里
StaticBody2D Collision：真的阻挡角色身体
</code></pre>
<p>NavigationAgent2D 的工作流程：</p>
<pre><code class="language-text">target_position = Player.global_position
→ get_next_path_position()
→ 朝下一个路径点移动
→ move_and_slide() 处理真实物理移动
</code></pre>
<p>导航回答“应该走哪条路线”，物理回答“此刻能不能穿过去”。如果只做导航没有墙体，玩家仍可能走穿；如果只有墙没有导航，敌人可能一直顶着墙追玩家。</p>
<h3 id="6-9-受击-硬直-击退与无敌时间">6.9 受击、硬直、击退与无敌时间</h3>
<p>命中后的完整流程：</p>
<pre><code class="language-mermaid">sequenceDiagram
    participant Hitbox
    participant Hurtbox
    participant Health as HealthComponent
    participant FSM as StateMachine
    participant Actor

    Hitbox-&gt;&gt;Hurtbox: receive_hit(HitData)
    Hurtbox-&gt;&gt;Health: hit_received(HitData)
    Health-&gt;&gt;Health: 扣除生命值
    Health--&gt;&gt;FSM: damaged(HitData)
    FSM-&gt;&gt;Actor: 进入 Hurt
    Actor-&gt;&gt;Actor: 中断攻击、击退、开启无敌
    Actor-&gt;&gt;FSM: HurtTimer 到期
    FSM-&gt;&gt;Actor: 恢复 Idle 或 Chase
    Actor-&gt;&gt;Actor: InvincibilityTimer 到期后重新启用 Hurtbox
</code></pre>
<p>相关术语：</p>
<ul>
<li>Knockback：命中造成的位置推移。</li>
<li>Hitstun：受击后不能行动的硬直时间。</li>
<li>Invincibility Frames / I-frames：短暂无敌窗口。</li>
<li>Interrupt：当前 Attack/Move/Chase 被 Hurt 强制打断。</li>
<li>Recovery State：受击结束后返回哪个状态。</li>
</ul>
<p>HurtTimer 与 InvincibilityTimer 分开，是因为“恢复行动”和“可以再次受击”不一定在同一时刻。</p>
<h3 id="6-10-动画驱动战斗">6.10 动画驱动战斗</h3>
<p>早期攻击由 AttackTimer 直接控制 Hitbox。后来 Player 改为 AnimationPlayer 时间线：</p>
<pre><code class="language-text">0.00s ───── 0.15s ───── 0.25s ───────── 0.42s
      前摇       有效命中帧           后摇结束
                 ↑       ↑                ↑
              open()  close()    animation_finished
</code></pre>
<p>AnimationPlayer 中包含：</p>
<ul>
<li>Value Track：改变 Weapon 的 rotation、scale。</li>
<li>Keyframe：某个时间点的属性值。</li>
<li>Call Method Track：在 0.15s/0.25s 调用 Hitbox 开关函数。</li>
<li><code>animation_finished</code> Signal：整段动画结束，Attack State 才返回 Idle。</li>
</ul>
<p><code>WeaponPivot</code> 负责角色朝向，<code>Weapon</code> 自己播放挥砍。我们没有旋转 Player 根节点，因为根节点还包含碰撞体、状态机和移动坐标系。</p>
<p>这一步建立了 Animation-driven Gameplay：动画不只是装饰，而是战斗时间线的一部分。</p>
<h3 id="6-11-命中反馈-camera-hit-stop-与-audio">6.11 命中反馈：Camera、Hit Stop 与 Audio</h3>
<p>CombatFeedback 集中处理表现：</p>
<ul>
<li>Camera2D offset：150ms 轻微随机震动。</li>
<li>Hit Stop：把 <code>Engine.time_scale</code> 暂时降到 <code>0.08</code>。</li>
<li>Hit Audio：播放撞击声并轻微随机 pitch。</li>
<li>Swing Audio：Player 开始挥砍时播放空间音效。</li>
</ul>
<p>Hit Stop 的恢复 Timer 使用 <code>ignore_time_scale=true</code>，否则负责恢复时间的 Timer 也会被自己减速。</p>
<p>连续命中还引入了异步竞争问题。通过递增 serial，只允许最后一次命中的等待任务恢复 time scale：</p>
<pre><code class="language-text">Hit #1 → serial 1 ──等待──┐ 发现已过期，不恢复
Hit #2 → serial 2 ────────┴→ 最后恢复到 1.0
</code></pre>
<p>这与 Web 中避免旧请求覆盖新请求的 request id / cancellation token 很相似。</p>
<h3 id="6-12-临时特效场景与生命周期">6.12 临时特效场景与生命周期</h3>
<p>每次命中动态创建 <code>hit_effect.tscn</code>：</p>
<pre><code class="language-text">preload PackedScene
→ instantiate()
→ setup(damage)
→ add_child()
→ GPUParticles2D 播放火花
→ Tween 上浮、淡出伤害数字
→ tween.finished
→ queue_free()
</code></pre>
<p>这个对象拥有自己的出生、播放和死亡，不要求 World 保存引用并定期清理。</p>
<p>相关概念：</p>
<ul>
<li>GPUParticles2D：批量模拟粒子。</li>
<li>ParticleProcessMaterial：速度、扩散角、重力、阻尼、缩放和颜色渐变。</li>
<li><code>one_shot</code>：只播放一次。</li>
<li><code>explosiveness</code>：粒子在开始时集中喷发。</li>
<li>Tween：用插值在一段时间内改变属性。</li>
<li>Transient Object：短生命周期对象。</li>
</ul>
<h2 id="7-今天反复使用的架构模式">7. 今天反复使用的架构模式</h2>
<h3 id="7-1-单一职责">7.1 单一职责</h3>
<p>一个对象应该有一个主要变化原因：</p>
<ul>
<li>HealthComponent 因生命规则变化而修改。</li>
<li>Hitbox 因命中规则变化而修改。</li>
<li>CombatFeedback 因表现风格变化而修改。</li>
<li>AttackData 因数值设计变化而修改。</li>
</ul>
<h3 id="7-2-组合优于巨型脚本">7.2 组合优于巨型脚本</h3>
<p>Player 不是一个包含所有系统的 1000 行脚本，而是组合：</p>
<pre><code class="language-text">CharacterBody2D
+ Hitbox
+ Hurtbox
+ HealthComponent
+ StateMachine
+ AnimationPlayer
+ Timer
+ AudioStreamPlayer2D
</code></pre>
<p>组件化不是“文件越多越好”，而是让可独立变化、可复用、可替换的职责获得边界。</p>
<h3 id="7-3-事件驱动">7.3 事件驱动</h3>
<p>Signal 表达已经发生的事实或请求：</p>
<ul>
<li><code>timeout</code></li>
<li><code>health_changed</code></li>
<li><code>damaged</code></li>
<li><code>died</code></li>
<li><code>transition_requested</code></li>
<li><code>attack_finished</code></li>
<li><code>animation_finished</code></li>
<li><code>hit_feedback_requested</code></li>
</ul>
<p>命名通常使用过去式表示事实，例如 <code>damaged</code>、<code>died</code>；使用 requested 表示请求尚需权威对象批准。</p>
<h3 id="7-4-数据驱动">7.4 数据驱动</h3>
<p>把“1 点伤害、44 像素距离”写在攻击逻辑里叫硬编码；把它们放在 AttackData Resource 中，逻辑读取数据，叫数据驱动。</p>
<p>数据驱动的价值：</p>
<ul>
<li>AI 可以帮你生成新配置，而不复制逻辑。</li>
<li>设计调参不需要改代码。</li>
<li>Player 和 Enemy 可以复用同一套组件。</li>
<li>更容易形成技能表、武器表、敌人配置表。</li>
</ul>
<h3 id="7-5-先构造候选-再验证-再提交">7.5 先构造候选，再验证，再提交</h3>
<p>这一模式从 Tetris 延伸到 Action Arena：</p>
<ul>
<li>旋转候选是否合法。</li>
<li>状态切换请求是否来自当前状态。</li>
<li>Hitbox 是否已经命中过同一个目标。</li>
<li>是否处于冷却、死亡或无敌状态。</li>
</ul>
<p>它是控制 AI 生成代码副作用的关键方式。</p>
<h3 id="7-6-规则与表现分离">7.6 规则与表现分离</h3>
<pre><code class="language-text">规则层：坐标、血量、状态、伤害、路径
表现层：颜色、动画、音效、震动、粒子、数字
</code></pre>
<p>表现可以很华丽，但不能成为扣血是否发生的唯一依据；规则可以被测试，但不需要加载所有视觉资产。</p>
<h2 id="8-我们主动跳过了什么">8. 我们主动跳过了什么</h2>
<p>跳过不是遗漏，而是控制学习范围。</p>
<h3 id="8-1-tetris-hold-piece">8.1 Tetris Hold Piece</h3>
<p>计划用 Hold Piece 学习“每个活动方块只能交换一次”的状态约束，但我们判断这一概念已经容易理解，因此没有继续实现。</p>
<p>如果以后补做，需要状态：</p>
<pre><code class="language-text">held_piece_type
can_hold_current_piece
</code></pre>
<p>新方块出生时重置权限，当前方块已经 Hold 过就拒绝再次交换。</p>
<h3 id="8-2-tetris-wall-kick-srs">8.2 Tetris Wall Kick / SRS</h3>
<p>当前旋转靠墙失败，不会尝试左右平移寻找合法位置。正式俄罗斯方块通常使用 Super Rotation System 和 Wall Kick 表。这里跳过是因为重点是候选旋转与验证，不是完整复刻竞技规则。</p>
<h3 id="8-3-后续自动化测试">8.3 后续自动化测试</h3>
<p>Snake 和 Tetris 建立了纯模型测试及无头执行方法。Action Arena 后半段以学习架构和表现为主，没有为每个状态和反馈系统继续增加永久测试。</p>
<p>这适合学习 Demo，但生产项目至少应继续测试：</p>
<ul>
<li>状态转换是否合法。</li>
<li>致命攻击与普通受伤的事件顺序。</li>
<li>同一攻击不能重复命中同一 Hurtbox。</li>
<li>Hit Stop 后 time scale 必须恢复。</li>
<li>临时特效必须销毁。</li>
</ul>
<p>今天仍然使用了短暂 smoke test 验证运行时关键链路，只是不把它们保留成正式测试套件。</p>
<h3 id="8-4-rvo-群体避让">8.4 RVO 群体避让</h3>
<p>我们研究并明确跳过了 RVO。</p>
<ul>
<li>NavigationAgent/A*：解决从 A 到 B 应该走哪条路。</li>
<li>RVO/ORCA：解决附近多个移动 Agent 怎样选择彼此不冲突的速度。</li>
<li>Physics Collision：解决物体最终能不能相互穿透。</li>
</ul>
<p>RVO 不是物理碰撞。它是一种 Local Avoidance（局部避让）。</p>
<p>没有在当前项目实现的原因：</p>
<ul>
<li>场上只有少量敌人，收益不明显。</li>
<li>动作游戏敌人过度互相礼让，可能显得犹豫、绕圈、不敢进攻。</li>
<li>近战敌人更适合使用 Attack Slot、Reservation 或简单分离力。</li>
<li>RVO 最适合专门的几十个 Agent 交叉移动实验场景。</li>
</ul>
<p>RVO 不是“没用”，而是特定群众移动问题的工具，不应该因为引擎提供就默认打开。</p>
<h3 id="8-5-attack-slot-animationtree-对象池和正式资产管线">8.5 Attack Slot、AnimationTree、对象池和正式资产管线</h3>
<p>这些都没有在今天实现：</p>
<ul>
<li>Attack Slot：控制多个近战敌人谁能进入攻击位置。</li>
<li>AnimationTree：处理更复杂的动画状态混合和 BlendSpace。</li>
<li>Object Pool：大量重复特效时复用对象，避免频繁实例化/销毁。</li>
<li>Audio Bus：统一管理 SFX/Music/UI 音量、压缩和效果。</li>
<li>Sprite/Skeletal Animation：真实美术资产的导入和动画管线。</li>
<li>Save/Load、设置菜单、输入重映射、导出发布。</li>
</ul>
<p>当前项目的目标是建立这些系统出现之前所需要的架构语言。</p>
<h2 id="9-怎样驾驭-ai-生成游戏-而不是被生成结果驾驭">9. 怎样驾驭 AI 生成游戏，而不是被生成结果驾驭</h2>
<h3 id="9-1-每一步先问五个问题">9.1 每一步先问五个问题</h3>
<ol>
<li>这一阶段只增加了哪个新能力？</li>
<li>新增了哪些 Node、Scene、Resource、Signal？</li>
<li>谁拥有数据，谁有权修改数据？</li>
<li>事件从哪里发出，经过哪里，最终由谁处理？</li>
<li>如果要替换视觉、AI 或数值，需要修改哪些文件？</li>
</ol>
<p>如果 AI 无法用一张目录树和一条事件流说明改动，通常说明边界还不清楚。</p>
<h3 id="9-2-要求-ai-先给结构-再给代码">9.2 要求 AI 先给结构，再给代码</h3>
<p>推荐顺序：</p>
<pre><code class="language-text">目标
→ 当前问题
→ 可选方案
→ 为什么选择其中一种
→ 将新增的目录/节点树
→ 事件流
→ 实现
→ 运行验证
→ 独立 commit
→ 下一步
</code></pre>
<p>这能防止 AI 一次生成大量互相耦合的脚本，而你只能“相信它”。</p>
<h3 id="9-3-用小提交保存知识增量">9.3 用小提交保存知识增量</h3>
<p>今天的提交不是按“文件”划分，而是按能力划分，例如：</p>
<pre><code class="language-text">build component-based combat loop
introduce player state machine
drive attacks with custom resources
add state-driven enemy combat
add obstacle-aware navigation
add hit reactions and invincibility
drive player attacks with animation
add combat feedback and audio
add transient hit effects
</code></pre>
<p>小提交的价值：</p>
<ul>
<li>可以比较某个概念加入前后的差异。</li>
<li>AI 改坏时容易定位和回退。</li>
<li>每个 commit 本身就是学习章节。</li>
<li>避免“重构、功能、格式化、资源替换”全部混在一起。</li>
</ul>
<h3 id="9-4-让-ai-运行真实引擎验证">9.4 让 AI 运行真实引擎验证</h3>
<p>只检查 GDScript 文本不够。至少应分层验证：</p>
<ol>
<li><code>git diff --check</code>：格式和冲突标记。</li>
<li>Godot Editor headless load：资源路径、场景语法、脚本解析。</li>
<li>运行若干帧：<code>_ready()</code> 和场景装配是否报错。</li>
<li>针对关键事件写临时 smoke test：动画关键帧、time scale 恢复、对象销毁。</li>
<li>视觉功能使用正常渲染窗口截帧检查。</li>
<li>需要手感判断时由人实际操作。</li>
</ol>
<p>AI 很适合验证“是否发生”，人仍需判断“是否好玩”。</p>
<h3 id="9-5-要求解释名词-但把名词绑定到项目中的对象">9.5 要求解释名词，但把名词绑定到项目中的对象</h3>
<p>只背定义很容易忘。更好的提问方式是：</p>
<pre><code class="language-text">不要只解释 Dependency Injection；指出当前项目中谁把什么注入给了谁。
不要只解释 Signal；画出本次命中的发送方和接收方。
不要只解释 Resource；比较 AttackData.tres 与 HitData 的生命周期。
</code></pre>
<h3 id="9-6-防止-ai-过度架构">9.6 防止 AI 过度架构</h3>
<p>常见危险信号：</p>
<ul>
<li>为只有一个调用者的简单函数创建五层抽象。</li>
<li>项目还没有第二种需求，就先建立庞大的通用框架。</li>
<li>用复杂设计模式替代清晰的数据结构。</li>
<li>因为引擎提供某功能，就自动加入 RVO、行为树、对象池等系统。</li>
<li>所有节点都通过全局 Singleton 通信。</li>
</ul>
<p>判断标准不是“专业项目是否用过”，而是：</p>
<blockquote>
<p>当前问题是否已经需要这层复杂度，它是否让下一次变化更容易？</p>
</blockquote>
<h3 id="9-7-一份可复用的-ai-协作提示词">9.7 一份可复用的 AI 协作提示词</h3>
<pre><code class="language-text">请分阶段实现这个 Godot 功能，每阶段只引入一个主要新概念。

实现前说明：
1. 当前问题和目标；
2. 至少两种可行方案；
3. 选择方案及原因；
4. 将变化的目录树和节点树；
5. 新名词及其在本项目中的对应对象；
6. 完整事件流和数据所有权。

实现时：
- Gameplay、数据、AI 和表现尽量分离；
- 每个 gd 文件开头写一句文件职责；
- 不覆盖已有未提交修改；
- 使用 Godot 实际加载并做与风险相称的运行验证；
- 一个知识增量对应一个 Git commit。

实现后说明：
1. 改了什么；
2. 我应该先看哪些文件；
3. 在 Godot 编辑器中如何观察；
4. 哪些内容有意跳过；
5. 下一阶段是什么。
</code></pre>
<h2 id="10-关键词词典">10. 关键词词典</h2>
<h3 id="godot-基础">Godot 基础</h3>
<ul>
<li>Node：运行时基本对象。</li>
<li>Scene：可保存和重复实例化的节点树。</li>
<li>SceneTree：当前运行中的整棵节点树。</li>
<li>Main Scene：项目入口场景。</li>
<li>Lifecycle Callback：由引擎在特定阶段调用的函数。</li>
<li>Signal：节点之间的一对多事件通信。</li>
<li>Connection：Signal 与接收方法之间的连接关系。</li>
<li>NodePath：在节点树中定位节点或属性的路径。</li>
<li><code>res://</code>：项目资源根路径。</li>
<li><code>preload()</code>：脚本解析时加载依赖。</li>
<li><code>load()</code>：运行时加载依赖。</li>
<li><code>@onready</code>：节点 ready 后再取得子节点引用。</li>
<li><code>@export</code>：把属性暴露给 Inspector 和场景装配。</li>
</ul>
<h3 id="数据与对象">数据与对象</h3>
<ul>
<li>Resource：可保存、复用、由 Inspector 编辑的数据对象。</li>
<li><code>.tres</code>：文本 Resource 文件。</li>
<li>RefCounted：通过引用计数管理生命周期、不必进入 SceneTree 的对象。</li>
<li>PackedScene：尚未实例化的 Scene 资源。</li>
<li>Instance：模板在运行时创建出的具体对象。</li>
<li>Dependency Injection：由外部把依赖交给对象，而不是对象内部硬编码寻找或创建。</li>
<li>Data-driven：逻辑读取数据配置，而不是把每个数值写死在流程代码中。</li>
<li>Runtime Payload：某次事件临时携带的数据，例如 HitData。</li>
</ul>
<h3 id="时间-输入与状态">时间、输入与状态</h3>
<ul>
<li>Delta：上一帧经过的秒数。</li>
<li>Fixed Tick：固定时间间隔推进规则。</li>
<li>Timer：时间到期后发出 timeout 的节点。</li>
<li>Input Action：对键盘、手柄等具体输入的语义抽象。</li>
<li>Input Buffer：暂存尚未被规则 Tick 消费的输入。</li>
<li>FSM：Finite State Machine，有限状态机。</li>
<li>State Transition：从一个状态切换到另一个状态。</li>
<li>Enter/Exit：状态取得或失去控制权时的生命周期。</li>
<li>Cooldown：动作再次允许执行前的等待时间。</li>
</ul>
<h3 id="空间-物理与-ai">空间、物理与 AI</h3>
<ul>
<li>Local Position：相对父节点的位置。</li>
<li>Global Position：相对整个世界的位置。</li>
<li>CharacterBody2D：由代码控制移动的 2D 角色物理体。</li>
<li>Area2D：检测重叠和进入/离开事件的区域。</li>
<li>Collision Layer：对象所属的物理类别。</li>
<li>Collision Mask：对象希望检测的物理类别。</li>
<li>Navigation Mesh/Polygon：描述 AI 可以行走的区域。</li>
<li>NavigationAgent2D：查询目标路径和下一个路径点。</li>
<li>Local Avoidance：避免附近移动对象的局部速度规划。</li>
<li>RVO：Reciprocal Velocity Obstacles，互惠速度障碍。</li>
<li>ORCA：基于速度约束的互惠避碰方法。</li>
<li>Attack Slot：预约玩家周围的有限攻击位置。</li>
</ul>
<h3 id="战斗与表现">战斗与表现</h3>
<ul>
<li>Hitbox：能够造成命中的区域。</li>
<li>Hurtbox：能够接收命中的区域。</li>
<li>Knockback：击退。</li>
<li>Hitstun：受击硬直。</li>
<li>I-frames：无敌帧/无敌时间。</li>
<li>Wind-up/Anticipation：攻击前摇。</li>
<li>Active Frames：攻击有效帧。</li>
<li>Recovery：攻击后摇。</li>
<li>Animation Track：动画控制某个属性或方法的轨道。</li>
<li>Keyframe：动画时间线上的关键值。</li>
<li>Call Method Track：在动画指定时间调用方法的轨道。</li>
<li>Hit Stop：命中瞬间的短暂停顿或极慢时间。</li>
<li>Camera Shake：通过 Camera offset 等方式制造冲击反馈。</li>
<li>AudioStreamPlayer2D：带世界位置的音频播放器。</li>
<li>GPUParticles2D：GPU 驱动的 2D 粒子系统。</li>
<li>Tween：随时间插值改变属性的轻量动画工具。</li>
<li>VFX：Visual Effects，视觉特效。</li>
<li>Transient Object：创建后短暂存在并自行销毁的对象。</li>
</ul>
<h3 id="算法与规则">算法与规则</h3>
<ul>
<li>Grid：离散网格。</li>
<li>Dense Array：适合固定、密集空间的数组表示。</li>
<li>Candidate State：尚未提交的候选状态。</li>
<li>Validate Before Commit：验证通过后才修改真实状态。</li>
<li>Fisher–Yates Shuffle：均匀洗牌算法。</li>
<li>7-bag：每袋包含全部七种 Tetromino 的随机系统。</li>
<li>Ghost Piece：显示方块预测落点的半透明影子。</li>
<li>Hard Drop：立即移动到最终落点并锁定。</li>
<li>Wall Kick：旋转碰壁时尝试位置修正。</li>
</ul>
<h2 id="11-从这里继续时应该掌握的判断能力">11. 从这里继续时应该掌握的判断能力</h2>
<p>读完这份总结后，不必记住每一行代码，但应该能够回答：</p>
<ol>
<li>一个 Godot 项目从哪里启动？</li>
<li>Scene、Node、Script 和 Resource 分别负责什么？</li>
<li>哪些数据必须进入 SceneTree，哪些可以只是 RefCounted 模型？</li>
<li>Signal 的发送方、接收方和 Payload 分别是谁？</li>
<li>为什么规则数据不应该只存在于画面节点？</li>
<li>为什么移动或旋转应先验证候选结果？</li>
<li>为什么 Hitbox、Hurtbox、Health 不合并成 Player/Enemy 的特例代码？</li>
<li>状态机解决了什么控制权问题？</li>
<li>导航和物理碰撞为什么要同时存在？</li>
<li>AttackData 和 HitData 为什么不能混为一谈？</li>
<li>动画如何精确控制攻击有效帧？</li>
<li>Hit Stop 为什么必须使用不受 time scale 影响的恢复计时？</li>
<li>临时特效为什么要自行销毁？</li>
<li>哪些系统当前值得实现，哪些属于过早复杂化？</li>
<li>AI 生成改动后，应该如何从结构、事件流和运行结果三层验证？</li>
</ol>
<p>如果这些问题能够用自己的话解释，就已经不再只是“让 AI 帮我写一个游戏”，而是在使用 AI 驱动一个自己理解的游戏工程。</p>
<h2 id="12-下一步">12. 下一步</h2>
<p>下一次可以先做一次 Action Arena 复盘：不看实现，从空白画出目录树、状态图和完整命中事件流，再用实际代码核对。</p>
<p>之后第四个项目应该进入一个新的领域，而不是继续堆 Action Arena 功能。可选方向：</p>
<ol>
<li>2D 平台跳跃：重力、地面检测、Coyote Time、Jump Buffer、Camera 跟随。</li>
<li>程序生成地牢：随机、图结构、连通性、TileMap 和种子复现。</li>
<li>UI/背包专项：Control 布局、Drag &amp; Drop、Resource 物品数据、存档。</li>
<li>3D 小型探索：从 Node2D/CharacterBody2D 过渡到 3D 坐标、相机和光照。</li>
</ol>
<p>选择标准仍然是：下一个项目必须带来新的核心知识，而不是只增加更多已经理解的规则。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/514</guid>
      <pubDate>Tue, 25 Aug 2026 00:00:22 +0800</pubDate>
    </item>
    <item>
      <title>千呼万唤始出来，golang1.27</title>
      <link>https://gooseforum.online/p/post/513</link>
      <description>代码语法最近可以稍微调整一下了</description>
      <content:encoded><![CDATA[<p><a href="/outbound?url=https%3A%2F%2Fgo.dev%2Fdoc%2Fdevel%2Frelease%23go1.27.0" target="_blank" rel="nofollow ugc noopener noreferrer">https://go.dev/doc/devel/release#go1.27.0</a></p>
<p>代码语法最近可以稍微调整一下了</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/513</guid>
      <pubDate>Thu, 20 Aug 2026 10:22:30 +0800</pubDate>
    </item>
    <item>
      <title>「8月反思」总结</title>
      <link>https://gooseforum.online/p/post/512</link>
      <description>关于认知门槛 AI 把“执行门槛”大幅降低了，但没有消灭“认知门槛”。 完全不懂 → AI 很强，但你驾驭不了。 懂一点 → AI 突然变得极强。 很懂 → AI 又变成一个超级执行工具。 不是你驾驭不了 AI，而是你缺少“驾驭 AI 所需要的最小知识地图”。 真正的问题往往不是提示词不够好，而是你不知道这个领域有哪些东西。 关于学习 以前学习，是为了获得执行能力。 现在学习，越来越是在获得指挥能...</description>
      <content:encoded><![CDATA[<h3 id="关于认知门槛">关于认知门槛</h3>
<blockquote>
<p>AI 把“执行门槛”大幅降低了，但没有消灭“认知门槛”。</p>
</blockquote>
<blockquote>
<p>完全不懂 → AI 很强，但你驾驭不了。<br/>
懂一点 → AI 突然变得极强。<br/>
很懂 → AI 又变成一个超级执行工具。</p>
</blockquote>
<blockquote>
<p>不是你驾驭不了 AI，而是你缺少“驾驭 AI 所需要的最小知识地图”。</p>
</blockquote>
<blockquote>
<p>真正的问题往往不是提示词不够好，而是你不知道这个领域有哪些东西。</p>
</blockquote>
<hr/>
<h3 id="关于学习">关于学习</h3>
<blockquote>
<p>以前学习，是为了获得执行能力。<br/>
现在学习，越来越是在获得指挥能力。</p>
</blockquote>
<blockquote>
<p>我不一定记得怎么写，但我要知道：有什么、什么时候用、什么方案闻起来不对。</p>
</blockquote>
<blockquote>
<p>不要一上来就学知识，先学地图。</p>
</blockquote>
<blockquote>
<p>先知道名词，再理解关系，最后才补细节。</p>
</blockquote>
<blockquote>
<p>一旦知道关键词，AI 的能力就会被释放出来。</p>
</blockquote>
<hr/>
<h3 id="关于陌生领域">关于陌生领域</h3>
<blockquote>
<p>进入一个陌生领域，先问：这个领域由哪些模块组成？</p>
</blockquote>
<blockquote>
<p>再问：每个模块分别解决什么问题？</p>
</blockquote>
<blockquote>
<p>再建立“问题 → 模块 / 方案”的映射。</p>
</blockquote>
<blockquote>
<p>比“不知道怎么做”更危险的是“不知道有这个东西”。</p>
</blockquote>
<blockquote>
<p>最致命的不是不会踩刹车，而是根本不知道前面还有岔路。</p>
</blockquote>
<hr/>
<h3 id="关于经验">关于经验</h3>
<blockquote>
<p>经验的价值，不只是让人知道怎么做，更是让人知道什么时候该踩刹车。</p>
</blockquote>
<blockquote>
<p>真正成熟的能力，是看到一种新方案时，能迅速判断它值不值得采用。</p>
</blockquote>
<blockquote>
<p>熟悉一个领域，不代表知道所有东西，而是知道哪些东西重要、哪些方向危险、哪些决策以后很难改。</p>
</blockquote>
<hr/>
<h3 id="关于方向">关于方向</h3>
<blockquote>
<p>最危险的不是 AI 写错，而是它带着你在错误方向上高速前进。</p>
</blockquote>
<blockquote>
<p>不要只问“能不能做”，还要问“如果选错了，以后改起来贵不贵”。</p>
</blockquote>
<blockquote>
<p>如果这个选择是错的，6 个月以后，我要付出什么代价？</p>
</blockquote>
<blockquote>
<p>陌生领域里，不必追求第一次就选对，但最好保证选错以后还能回来。</p>
</blockquote>
<hr/>
<h3 id="关于-ai-生成代码">关于 AI 生成代码</h3>
<blockquote>
<p>AI 每次生成几百行代码，真正的问题不是我能不能看完，而是我有没有漏掉一个根本不知道存在的关键词。</p>
</blockquote>
<blockquote>
<p><code>keep-alive</code> 被遗漏了。<br/>
<code>Shader</code> 被遗漏了。<br/>
<code>Resource</code> 被遗漏了。<br/>
最麻烦的是：你甚至不知道自己遗漏了什么。</p>
</blockquote>
<blockquote>
<p>AI 可能用了一个重要模块，却没有告诉你它叫什么。</p>
</blockquote>
<blockquote>
<p>AI 也可能根本没有想到某个模块，而你因为不知道它存在，也不会追问。</p>
</blockquote>
<blockquote>
<p>AI 默认认为：没有被问到的内容，可以不说。</p>
</blockquote>
<blockquote>
<p>对陌生领域来说，这恰恰是最危险的。</p>
</blockquote>
<hr/>
<h3 id="关于学习与生成的边界">关于学习与生成的边界</h3>
<blockquote>
<p>永远不要只拿走代码，也要拿走关键词。</p>
</blockquote>
<blockquote>
<p>不是所有 AI 生成的代码都值得学习。</p>
</blockquote>
<blockquote>
<p>真正值得留下来的，是那些会改变你以后判断方式的东西。</p>
</blockquote>
<blockquote>
<p>任何一个让我事后产生“原来还有这个东西”的概念，都值得记录下来。</p>
</blockquote>
<blockquote>
<p>它们往往不是技巧，而是整个生态里的关键节点。</p>
</blockquote>
<hr/>
<h3 id="最后几句">最后几句</h3>
<blockquote>
<p>你真正害怕的，从来不是学习本身。</p>
</blockquote>
<blockquote>
<p>你害怕的是：在错误的方向上，高效率地前进。</p>
</blockquote>
<blockquote>
<p>以前我们害怕的是不会。<br/>
现在我们还要警惕：AI 帮我们绕过了本该发生的学习过程。</p>
</blockquote>
<blockquote>
<p>功能实现了，代码运行了，不代表认知也留下来了。</p>
</blockquote>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/512</guid>
      <pubDate>Wed, 19 Aug 2026 17:06:52 +0800</pubDate>
    </item>
    <item>
      <title>「8月反思」真正危险的不是 AI 写错，而是它带着你在错误方向上跑得太快</title>
      <link>https://gooseforum.online/p/post/511</link>
      <description>我前面提到过一个问题： AI 把执行门槛打掉以后，真正暴露出来的，反而是认知门槛。 但继续往下想，我觉得还有一个更麻烦的问题。 不是 AI 不会做。 而是它太会做了。 快到什么程度呢？ 你给它一个方向，它可以很快帮你搭起来。 再给一点要求，它继续往前推。 如果方向本来就是对的，这种感觉非常爽。 但如果方向从一开始就是错的，那就会出现一种以前没那么明显的问题： 你会在错误方向上，以一种非常高的效率前...</description>
      <content:encoded><![CDATA[<p>我前面提到过一个问题：</p>
<p>AI 把执行门槛打掉以后，真正暴露出来的，反而是认知门槛。</p>
<p>但继续往下想，我觉得还有一个更麻烦的问题。</p>
<p>不是 AI 不会做。</p>
<p>而是它太会做了。</p>
<p>快到什么程度呢？</p>
<p>你给它一个方向，它可以很快帮你搭起来。</p>
<p>再给一点要求，它继续往前推。</p>
<p>如果方向本来就是对的，这种感觉非常爽。</p>
<p>但如果方向从一开始就是错的，那就会出现一种以前没那么明显的问题：</p>
<blockquote>
<p><strong>你会在错误方向上，以一种非常高的效率前进。</strong></p>
</blockquote>
<p>这其实比“代码写错了”更麻烦。</p>
<p>代码写错，通常很快就能发现。</p>
<p>报错了。</p>
<p>测试不过。</p>
<p>页面坏了。</p>
<p>接口不通。</p>
<p>这些问题都比较显性。</p>
<p>真正麻烦的是：</p>
<p><strong>代码没有错，功能也实现了，但架构方向错了。</strong></p>
<p>而且因为 AI 很快，所以这个错误方向还会不断长大。</p>
<hr/>
<p>我自己做 GooseForum 的时候，就经历过这种事情。</p>
<p>一开始我希望它：</p>
<ul>
<li>
<p>Go 打包成单文件</p>
</li>
<li>
<p>对 SEO 友好</p>
</li>
<li>
<p>前端又尽量现代化</p>
</li>
<li>
<p>管理界面不能太难用</p>
</li>
<li>
<p>最好还能兼顾 No-JS</p>
</li>
</ul>
<p>这些目标单独看都不奇怪。</p>
<p>但放在一起以后，其实天然就有冲突。</p>
<p>我一开始走过 SPA。</p>
<p>因为 SPA 很自然。</p>
<p>前后端分开，现代前端生态又成熟，管理界面也好做。</p>
<p>但很快 SEO 的问题就出来了。</p>
<p>如果我当时完全不知道 SEO 是什么，那这条路很可能就一路走下去了。</p>
<p>而且 AI 还会不断帮我把 SPA 做得越来越完整。</p>
<p>路由、状态管理、组件、接口，全都可以继续往上堆。</p>
<p>最后等我哪一天突然意识到：</p>
<p>“论坛这个东西，SEO 很重要。”</p>
<p>那就已经不是改几行代码的问题了。</p>
<hr/>
<p>后来我又走到了纯服务端渲染。</p>
<p>SEO 好了。</p>
<p>结构也简单。</p>
<p>和 Go 很搭。</p>
<p>但前端交互又开始变得难受。</p>
<p>再后来是 Alpine + 服务端渲染。</p>
<p>当时看起来也很合理。</p>
<p>轻。</p>
<p>简单。</p>
<p>不需要很重的前端框架。</p>
<p>但做着做着，又发现复杂管理界面并不适合。</p>
<p>再往后，才慢慢走到 Vue、Payload、Tailwind，再加 No-JS 兜底。</p>
<p>现在回头看，这个过程当然可以说是摸索。</p>
<p>但也可以说：</p>
<blockquote>
<p><strong>我是在不断发现之前不知道的约束。</strong></p>
</blockquote>
<p>SEO 是一个约束。</p>
<p>管理界面的复杂度是一个约束。</p>
<p>部署方式是一个约束。</p>
<p>No-JS 又是一个约束。</p>
<p>问题就在这里。</p>
<p>如果一个约束你根本不知道存在，你就不可能在一开始把它放进决策里。</p>
<p>而 AI 也不会自动替你承担这件事。</p>
<hr/>
<p>所以我后来越来越觉得，一个人在熟悉领域里的真正优势，可能根本不是“会写”。</p>
<p>而是：</p>
<blockquote>
<p><strong>他知道什么条件下，什么方案不该选。</strong></p>
</blockquote>
<p>比如我现在如果在比较熟悉的服务端领域里和 AI 协作，我通常会有一种比较明确的感觉。</p>
<p>这个规模没必要拆服务。</p>
<p>这里没必要上消息队列。</p>
<p>这个缓存做早了。</p>
<p>这个接口边界不对。</p>
<p>这个依赖以后会很麻烦。</p>
<p>很多时候甚至说不出特别完整的理论。</p>
<p>但就是会觉得：</p>
<p>“这个方向不太对。”</p>
<p>这种能力，其实就是经验。</p>
<p>你脑子里已经有了一套隐藏的约束系统。</p>
<p>AI 给出方案。</p>
<p>你会下意识拿它和这些约束比较。</p>
<p>然后决定：</p>
<p>继续。</p>
<p>修改。</p>
<p>或者直接踩刹车。</p>
<hr/>
<p>这也是为什么我觉得，在陌生领域里，最大的风险不是“我不会”。</p>
<p>不会其实很好解决。</p>
<p>AI 会写。</p>
<p>文档可以查。</p>
<p>例子可以看。</p>
<p>真正危险的是：</p>
<p><strong>你没有刹车系统。</strong></p>
<p>因为你不知道有哪些方案。</p>
<p>不知道什么时候该选哪个方案。</p>
<p>也不知道什么东西以后改起来特别痛。</p>
<p>这时候 AI 一旦开始高速生成，反而会放大问题。</p>
<hr/>
<p>所以我现在会特别在意一个东西：</p>
<blockquote>
<p><strong>这个决策如果错了，以后改起来贵不贵？</strong></p>
</blockquote>
<p>这个问题可能比“现在是不是最优”更重要。</p>
<p>比如有些东西选错了，问题不大。</p>
<p>UI 库不喜欢，换。</p>
<p>CSS 方案不喜欢，慢慢改。</p>
<p>某个动画实现不满意，也可以重做。</p>
<p>但有些东西就不一样。</p>
<p>数据模型。</p>
<p>模块边界。</p>
<p>部署方式。</p>
<p>核心资源组织。</p>
<p>这些东西一旦走得很深，再回头就非常贵。</p>
<p>所以陌生领域里，我现在越来越倾向于：</p>
<p><strong>不要追求第一次选对，而是先保证第一次选错以后还能回来。</strong></p>
<p>这和追求最优解是两回事。</p>
<p>你甚至可以先问：</p>
<blockquote>
<p>如果这个方案 6 个月以后证明是错的，我要付出什么代价？</p>
</blockquote>
<p>这其实就是一个很有价值的架构问题。</p>
<hr/>
<p>这件事放到 Godot 里也是一样的。</p>
<p>比如我以后让 AI 帮我做一个系统。</p>
<p>我现在不会只问：</p>
<p>“怎么实现？”</p>
<p>我更想先知道：</p>
<p>“有几种实现方式？”</p>
<p>“这个项目规模下，通常会选哪种？”</p>
<p>“哪些方案只是 Demo 里方便？”</p>
<p>“哪些做法以后扩展会比较痛？”</p>
<p>“有没有我不知道的模块，会改变这个问题的解法？”</p>
<p>因为这几个问题决定的是方向。</p>
<p>代码本身反而是后面的事。</p>
<hr/>
<p>以前大家总担心 AI 会不会写错代码。</p>
<p>我现在觉得，这已经不是最值得担心的问题了。</p>
<p>代码错了，通常还能发现。</p>
<p>真正麻烦的是：</p>
<blockquote>
<p><strong>它给你写了一套完全能跑的东西。</strong></p>
</blockquote>
<p>你觉得挺好。</p>
<p>AI 也觉得完成了。</p>
<p>项目继续往前推进。</p>
<p>一个月以后，你才突然发现：</p>
<p>一开始其实还有另一条路。</p>
<p>而那条路更适合你。</p>
<p>这时候真正浪费掉的，不是几百行代码。</p>
<p>而是你在错误方向上累积下来的整个结构。</p>
<hr/>
<p>所以如果说 AI 时代还有什么能力会越来越值钱，我觉得其中一个一定是：</p>
<p><strong>知道什么时候该踩刹车。</strong></p>
<p>而经验的价值，也越来越不像“我会写得比 AI 好”。</p>
<p>更像是：</p>
<blockquote>
<p><strong>我知道什么时候不应该让它继续写。</strong></p>
</blockquote>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/511</guid>
      <pubDate>Wed, 19 Aug 2026 16:51:25 +0800</pubDate>
    </item>
    <item>
      <title>「8月反思」我的想象力开始追不上 AI 的执行速度了</title>
      <link>https://gooseforum.online/p/post/510</link>
      <description>最近我突然意识到一个挺有意思的问题。 我的想象力，好像开始追不上使用 AI 之后的执行效率了。 以前不是这样。 以前更像是，我脑子里有很多想法，但是实现很慢。 想做一个东西，先查资料，再写，再调，再改。一个想法可能折腾几天，甚至更久。 所以以前真正限制我的，是执行能力。 但现在用了 AI 以后，这个关系有点反过来了。 你有一个想法，马上可以试。 试完觉得不对，再换一个。 以前积攒很久的“以后可以试...</description>
      <content:encoded><![CDATA[<p>最近我突然意识到一个挺有意思的问题。</p>
<p><strong>我的想象力，好像开始追不上使用 AI 之后的执行效率了。</strong></p>
<p>以前不是这样。</p>
<p>以前更像是，我脑子里有很多想法，但是实现很慢。</p>
<p>想做一个东西，先查资料，再写，再调，再改。一个想法可能折腾几天，甚至更久。</p>
<p>所以以前真正限制我的，是执行能力。</p>
<p>但现在用了 AI 以后，这个关系有点反过来了。</p>
<p>你有一个想法，马上可以试。</p>
<p>试完觉得不对，再换一个。</p>
<p>以前积攒很久的“以后可以试试”，现在可能很快就被消耗掉了。</p>
<p>一开始我觉得，这可能是一个很有意思的新问题：</p>
<blockquote>
<p><strong>以前是执行力追不上想象力，现在开始变成想象力追不上执行力。</strong></p>
</blockquote>
<p>但后来我又觉得，这句话不完整。</p>
<p>因为这种效率其实是有边界的。</p>
<p>只要进入一个自己不熟悉的领域，问题马上就出来了。</p>
<p>我以前在 Vue 里就遇到过一个很典型的例子。</p>
<p>我当时想实现一个效果，大概是页面返回以后，希望之前的状态还在。</p>
<p>AI 当然也能帮我实现。</p>
<p>但是实现得很糟糕。</p>
<p>后来别人提醒了我一个词：</p>
<p><code>keep-alive</code></p>
<p>然后一下就解决得很好。</p>
<p>这件事后来我一直记得。</p>
<p>因为问题其实不是我不会写 <code>keep-alive</code>。</p>
<p>如果我知道这个东西存在，剩下怎么用，我完全可以交给 AI。</p>
<p>真正的问题是：</p>
<p><strong>我根本不知道有这么个东西。</strong></p>
<p>这个差别其实很大。</p>
<p>因为如果你不知道某个概念存在，你甚至不会去问它。</p>
<p>你只能描述表面需求：</p>
<p>“我返回以后，希望状态还保留。”</p>
<p>AI 可能会顺着你的描述，给你搞状态保存、恢复、缓存，甚至自己绕一大圈。</p>
<p>最后功能也许能跑。</p>
<p>但方向可能从一开始就不是最好的。</p>
<p>所以后来我越来越觉得：</p>
<p><strong>AI 把执行门槛大幅降低了，但没有消灭认知门槛。</strong></p>
<p>其实一年前，我自己就总结过一个很类似的观点：</p>
<blockquote>
<p>完全不懂 → AI 很强，但你驾驭不了。<br/>
懂一点 → AI 突然变得极强。<br/>
很懂 → AI 又变成一个超级执行工具。</p>
</blockquote>
<p>现在重新看，我觉得中间那个“懂一点”可能比我当时想得还重要。</p>
<p>因为这个“懂一点”不一定是会写。</p>
<p>甚至不一定是深入理解。</p>
<p>更像是：</p>
<p>我知道这个领域大概有哪些东西。</p>
<p>我知道一个问题通常对应哪个模块。</p>
<p>我知道可能有几种方向。</p>
<p>我知道什么方案一看就不太对。</p>
<p>只要有这些东西，AI 的能力一下就被放出来了。</p>
<p>但如果没有，就很容易出现一种情况：</p>
<p>AI 很快。</p>
<p>你也很快。</p>
<p>但你们两个一起在错误方向上跑。</p>
<p>这也是为什么我最近接触 Godot 的时候，会特别明显地感觉到这个问题。</p>
<p>比如着色器。</p>
<p>Shader。</p>
<p>如果我不知道这个东西存在，那我想做一个水面效果、描边、像素化或者某种视觉效果的时候，我可能根本不会问：</p>
<p>“这个是不是应该用 Shader？”</p>
<p>我甚至不知道这个问题属于哪个模块。</p>
<p>这和之前的 <code>keep-alive</code> 本质上是一样的。</p>
<p>最麻烦的不是不会。</p>
<p>而是：</p>
<blockquote>
<p><strong>你不知道自己不知道。</strong></p>
</blockquote>
<p>而 AI 又不会保证主动把所有相关概念都告诉你。</p>
<p>它可能用了一个重要模块，但没有告诉你这个模块叫什么。</p>
<p>也可能根本没用某个更合适的模块。</p>
<p>而你因为不知道它存在，也不会提出质疑。</p>
<p>所以我现在觉得，AI 时代学习一个新领域，第一件事可能已经不是学怎么写了。</p>
<p>而是先搞清楚：</p>
<blockquote>
<p><strong>这个领域到底有哪些东西？</strong></p>
</blockquote>
<p>比如 Godot，不是先去记 API。</p>
<p>而是先知道：</p>
<p>Scene、Node、Signal、Resource、Shader、Animation、Navigation、Physics……</p>
<p>先知道名字。</p>
<p>知道这些东西分别大概解决什么问题。</p>
<p>这样以后遇到需求的时候，脑子里至少会出现一个反应：</p>
<p>“这个问题是不是属于某个已有模块？”</p>
<p>而不是直接让 AI 开始生成代码。</p>
<p>这可能也是 AI 出现以后，“学习”这件事情发生的一个变化。</p>
<p>以前学习很多时候是在获得执行能力：</p>
<blockquote>
<p>我要知道怎么写，因为我要自己写。</p>
</blockquote>
<p>现在越来越像是在获得指挥能力：</p>
<blockquote>
<p>我不一定要记住怎么写，但我要知道有什么、什么时候用、什么方向可能是错的。</p>
</blockquote>
<p>所以现在回头看，我最开始那句“我的想象力开始追不上 AI 的执行速度了”，其实还可以再补一句。</p>
<p>真正麻烦的地方可能不是想象力。</p>
<p>而是当 AI 跑得越来越快以后：</p>
<p><strong>我的认知地图，有时候开始追不上它的执行速度了。</strong></p>
<p>而这件事，可能比“怎么写一个更好的提示词”重要得多。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/510</guid>
      <pubDate>Wed, 19 Aug 2026 16:49:34 +0800</pubDate>
    </item>
    <item>
      <title>GooseHost静态网站托管</title>
      <link>https://gooseforum.online/p/post/508</link>
      <description>GooseHost 是一个免费的静态网站托管平台，支持 HTML、CSS、JavaScript 等静态文件的上传和部署，提供全球 CDN 加速，让您的html被全球的人看见！</description>
      <content:encoded><![CDATA[<p>GooseHost 是一个<code>免费</code>的静态网站托管平台，支持 HTML、CSS、JavaScript 等静态文件的上传和部署，提供全球 CDN 加速，让您的html被全球的人看见！</p>
<p><img src="https://host.goose.gs.cn/icons/icon-180x180.png" alt="logo" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/508</guid>
      <pubDate>Mon, 17 Aug 2026 13:01:23 +0800</pubDate>
    </item>
    <item>
      <title>估计最近大家期待的组/权限功能就要上线啦</title>
      <link>https://gooseforum.online/p/post/506</link>
      <description>目前测试结果很好，实现效果也很好。采取的方案总体不错，性能非常稳定。详细测试结果可以查看</description>
      <content:encoded><![CDATA[<p>目前测试结果很好，实现效果也很好。采取的方案总体不错，性能非常稳定。详细测试结果可以查看 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fleancodebox%2FGooseForum%2Fissues%2F12" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/leancodebox/GooseForum/issues/12</a></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/506</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:44 +0800</pubDate>
    </item>
    <item>
      <title>codex 竟然拯救了我的办公电脑的内存</title>
      <link>https://gooseforum.online/p/post/505</link>
      <description>原来可能一次性开7/8个idea项目。php/golang/java 都有，搞的内存很紧张，并且还有非常多的浏览器页面。 现如今加上封装的dogdog，公司所有流程基本也很少打开浏览器，别人发的消息，也用内部im的cli直接让codex对接。 维护好agent.md更改-cr-commit-push-部署-测试后通知前端或者测试同学。 因为开的程序少了。所以总的内存用的更少了。 当然硬盘还是那么的...</description>
      <content:encoded><![CDATA[<p>原来可能一次性开7/8个idea项目。php/golang/java 都有，搞的内存很紧张，并且还有非常多的浏览器页面。</p>
<p>现如今加上封装的dogdog，公司所有流程基本也很少打开浏览器，别人发的消息，也用内部im的cli直接让codex对接。</p>
<p>维护好agent.md更改-cr-commit-push-部署-测试后通知前端或者测试同学。</p>
<p>因为开的程序少了。所以总的内存用的更少了。</p>
<p>当然硬盘还是那么的不够用～</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/505</guid>
      <pubDate>Thu, 13 Aug 2026 17:48:58 +0800</pubDate>
    </item>
    <item>
      <title>我不想再每天告诉 Codex 下一个功能是什么</title>
      <link>https://gooseforum.online/p/post/504</link>
      <description>过去一段时间，我在做一个本地自动化工具，把办公网站里的常用能力封装成 AI Agent 可以调用的命令。 现在的合作方式已经很成熟：我告诉 Codex 一个功能点，带它看一次页面；Codex 负责分析请求、实现代码、补测试和文档。真正写代码的人不是我，单个功能的接入也已经足够高效。 但我还是开始疲惫。 问题不是实现太难，而是每天都要由我回答： 下一个应该封装什么？ 今天提一个列表，明天提一个详情，...</description>
      <content:encoded><![CDATA[<p>过去一段时间，我在做一个本地自动化工具，把办公网站里的常用能力封装成 AI Agent 可以调用的命令。</p>
<p>现在的合作方式已经很成熟：我告诉 Codex 一个功能点，带它看一次页面；Codex 负责分析请求、实现代码、补测试和文档。真正写代码的人不是我，单个功能的接入也已经足够高效。</p>
<p>但我还是开始疲惫。</p>
<p>问题不是实现太难，而是每天都要由我回答：</p>
<blockquote>
<p>下一个应该封装什么？</p>
</blockquote>
<p>今天提一个列表，明天提一个详情，后天再想起某个筛选。Codex 很能干，但它一直在等我点菜。我仍然是唯一的需求发现者、产品经理和启动按钮。</p>
<p>这不是编码疲惫，而是持续发起任务的疲惫。</p>
<h2 id="从点菜变成审核">从点菜变成审核</h2>
<p>现在的流程是：</p>
<pre><code class="language-text">我想起一个功能
→ 告诉 Codex
→ Codex 分析并实现
→ 等我想起下一个
</code></pre>
<p>下一阶段应该改成：</p>
<pre><code class="language-text">我指定一个站点或业务范围
→ Codex 主动盘点页面和现有能力
→ 找出缺失的列表、详情、筛选和关联查询
→ 生成候选清单，标注价值、风险和成本
→ 我集中审核
→ Codex 批量实现
</code></pre>
<p>交互单位不再是一个按钮，而是一个页面或一段工作流。我的职责也从“每天想需求”变成“偶尔定方向、审候选”。</p>
<h2 id="候选从哪里来">候选从哪里来</h2>
<p>Codex 可以从几个地方主动发现下一步：</p>
<ul>
<li>一次页面探索中尚未接入的筛选、分页、详情和关联入口。</li>
<li>使用频率高、但需要多次拼接才能完成的现有能力。</li>
<li>对话中反复出现的临时网页操作。</li>
<li>页面功能与已注册能力之间的缺口。</li>
</ul>
<p>候选项需要说明用途、预期收益、读写属性、实现成本，以及仍需我确认的问题。</p>
<p>主动发现不等于自由扩张。写操作仍需逐项批准；查询型 <code>POST</code> 仍需判断副作用；运行时不能开放任意 URL；凭据和敏感数据不能进入候选记录、测试或日志。</p>
<h2 id="下一步">下一步</h2>
<p>不必一开始就建设复杂平台。先做三件事：</p>
<ol>
<li>建立候选能力清单，记录来源、价值、风险和待确认问题。</li>
<li>每次探索页面时，默认盘点完整只读工作流，而不只实现当次点名的功能。</li>
<li>定期根据使用记录和重复对话生成候选项，让我一次审核一组。</li>
</ol>
<p>Codex 已经能够很好地分析和实现能力。现在真正缺少的，是一套不再依赖我逐个发起任务的演进机制。</p>
<p>我希望自己从每天点菜的人，变成偶尔确定方向和审核边界的人。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/504</guid>
      <pubDate>Thu, 13 Aug 2026 16:34:50 +0800</pubDate>
    </item>
    <item>
      <title>与 agent 共享终端</title>
      <link>https://gooseforum.online/p/post/503</link>
      <description></description>
      <content:encoded><![CDATA[<pre><code>tmux new -s session-name
tmux ls 
tmux a -t session-name
</code></pre>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/503</guid>
      <pubDate>Wed, 12 Aug 2026 14:10:32 +0800</pubDate>
    </item>
    <item>
      <title>AI时代下的追求第一性原理</title>
      <link>https://gooseforum.online/p/post/502</link>
      <description>很奇怪的两个现象，现象一是无论什么都用ai，另一个现象是严禁ai产物。 用ai/不用ai都是手段，而非目的。 如果用ai不能提高效率，反而会拖慢进度的场景应该做适当调整，比如让ai生成工具，而非ai接管全局。 相反小说/论文的目的是高质量的产出，如果质量很高，用不用ai有什么关系呢，茴香豆的四种写法重要吗？</description>
      <content:encoded><![CDATA[<p>很奇怪的两个现象，现象一是无论什么都用ai，另一个现象是严禁ai产物。</p>
<p>用ai/不用ai都是手段，而非目的。</p>
<p>如果用ai不能提高效率，反而会拖慢进度的场景应该做适当调整，比如让ai生成工具，而非ai接管全局。</p>
<p>相反小说/论文的目的是高质量的产出，如果质量很高，用不用ai有什么关系呢，茴香豆的四种写法重要吗？</p>
<p><img src="/file/img/2026/08/12/36dba733-8a2f-4b5a-9ac7-24e4127ca386.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/502</guid>
      <pubDate>Wed, 12 Aug 2026 11:13:23 +0800</pubDate>
    </item>
    <item>
      <title>暑假做什么？</title>
      <link>https://gooseforum.online/p/post/501</link>
      <description></description>
      <content:encoded><![CDATA[<p>依旧😎</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/501</guid>
      <pubDate>Sat, 08 Aug 2026 11:12:01 +0800</pubDate>
    </item>
    <item>
      <title>GooseForum的文章/分类权限快要定稿了，有兴趣的同学可以看下</title>
      <link>https://gooseforum.online/p/post/500</link>
      <description></description>
      <content:encoded><![CDATA[<p><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fleancodebox%2FGooseForum%2Fissues%2F12" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/leancodebox/GooseForum/issues/12</a></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/500</guid>
      <pubDate>Fri, 07 Aug 2026 16:35:55 +0800</pubDate>
    </item>
    <item>
      <title>我们意念合一</title>
      <link>https://gooseforum.online/p/post/495</link>
      <description></description>
      <content:encoded><![CDATA[<p><img src="/file/img/2026/07/29/076ed1b0-7311-46ee-8cd9-77ad66ec3b86.webp" alt="image" loading="lazy" decoding="async"/></p>
<p><img src="/file/img/2026/07/29/73a6f8ec-8812-43ff-917e-8e9f7ae53400.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/495</guid>
      <pubDate>Wed, 29 Jul 2026 15:19:08 +0800</pubDate>
    </item>
    <item>
      <title>codex 懒人办公</title>
      <link>https://gooseforum.online/p/post/499</link>
      <description>记录一次codex修复测试环境bug，并通知到测试同学的完整命令。</description>
      <content:encoded><![CDATA[<p>记录一次codex修复测试环境bug，并通知到测试同学的完整命令。</p>
<p><img src="/file/img/2026/08/07/51e0eb80-42e8-453d-924b-c0551ddc5985.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/499</guid>
      <pubDate>Fri, 07 Aug 2026 11:14:38 +0800</pubDate>
    </item>
    <item>
      <title>住宅IP免费送，原生独享IP只要几块钱，先试后用</title>
      <link>https://gooseforum.online/p/post/498</link>
      <description>动态住宅ip流量用不完，免费送给大家！！！ 邀请码：veexfwaif 注册即刻兑换： H6V7-NUM9-ZJSA LS6F-H4HK-WMBN PP4J-B2S9-YDJ7 8VJ9-YY34-P77Z TDUQ-7EAC-F26J 没抢到的宝子可以将注册的邮箱打在评论区 也可以https://t.me/Zooproxy7 联系这个 原生独享IP也只要几块钱，各个地区都有，官网没有的私我 号段...</description>
      <content:encoded><![CDATA[<p>动态住宅ip流量用不完，免费送给大家！！！<br/>
邀请码：veexfwaif<br/>
注册即刻兑换：<br/>
<a href="/outbound?url=https%3A%2F%2Fzooproxy.com%2F%3Fkwd%3DLQ-gooseforum" target="_blank" rel="nofollow ugc noopener noreferrer">https://zooproxy.com/?kwd=LQ-gooseforum</a><br/>
H6V7-NUM9-ZJSA</p>
<p>LS6F-H4HK-WMBN</p>
<p>PP4J-B2S9-YDJ7</p>
<p>8VJ9-YY34-P77Z</p>
<p>TDUQ-7EAC-F26J<br/>
没抢到的宝子可以将注册的邮箱打在评论区<br/>
也可以<a href="/outbound?url=https%3A%2F%2Fwww.nodeseek.com%2Fjump%3Fto%3Dhttps%253A%252F%252Ft.me%252FZooproxy7" target="_blank" rel="nofollow ugc noopener noreferrer">https://t.me/Zooproxy7</a> 联系这个</p>
<p>原生独享IP也只要几块钱，各个地区都有，官网没有的私我<br/>
号段：23.158.220.46<br/>
23.158.220.45<br/>
194.179.152.45<br/>
103.5.248.242</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/498</guid>
      <pubDate>Wed, 05 Aug 2026 12:20:24 +0800</pubDate>
    </item>
    <item>
      <title>「许愿池」后续功能讨论</title>
      <link>https://gooseforum.online/p/post/484</link>
      <description>第一阶段，大家有什么想法吗分组或者圈子以及对应权限这个功能有什么想法吗。 这边关于分组的配置可能得走 EXISTS 控制了。主要是GooseForum目前仍打算保持多分类这个能力。 一般来说，一个主题或者文章会绑定一个分类，但是实际情况是，如果一个文章，例如一个关于物理问题的数学公式，那么这个文章天然应该分别出现在物理/数学两个分类里面，就目前为止确实看到不少论坛因为限制了单类型，导致用户针对同一...</description>
      <content:encoded><![CDATA[<p>第一阶段，大家有什么想法吗分组或者圈子以及对应权限这个功能有什么想法吗。</p>
<p>这边关于分组的配置可能得走 EXISTS 控制了。主要是GooseForum目前仍打算保持多分类这个能力。</p>
<p>一般来说，一个主题或者文章会绑定一个分类，但是实际情况是，如果一个文章，例如一个关于物理问题的数学公式，那么这个文章天然应该分别出现在物理/数学两个分类里面，就目前为止确实看到不少论坛因为限制了单类型，导致用户针对同一个文章发布多次的情况。</p>
<p>赶车～晚点补充</p>
<hr/>
<h2 id="主题列表缓存">主题列表缓存</h2>
<p>修复新主题发布后，其他用户返回主题列表仍看到旧数据的问题。</p>
<p>来源：<a href="/outbound?url=https%3A%2F%2Fgooseforum.online%2Fp%2Fpost%2F574" target="_blank" rel="nofollow ugc noopener noreferrer">功能建议</a>、<a href="/outbound?url=https%3A%2F%2Fgooseforum.online%2Fp%2Fpost%2F570" target="_blank" rel="nofollow ugc noopener noreferrer">安装网站后的问题</a></p>
<h2 id="windows-安装与启动">Windows 安装与启动</h2>
<p>降低非开发者第一次运行 GooseForum 的门槛。</p>
<p>可以处理：</p>
<ul>
<li>在 Windows 发布包中提供 <code>start.bat</code>。</li>
<li>改进未传入 CLI 子命令时的提示。</li>
<li>提供最短启动流程说明。</li>
<li>明确 Intel、AMD 用户选择 x86_64。</li>
<li>明确 Windows ARM 设备选择 ARM64。</li>
<li>评估无参数运行时是否可以默认启动服务。</li>
</ul>
<p>来源：<a href="/outbound?url=https%3A%2F%2Fgooseforum.online%2Fp%2Fpost%2F563" target="_blank" rel="nofollow ugc noopener noreferrer">安装网站问题</a></p>
<h2 id="主题与权限模型">主题与权限模型</h2>
<p>设计一套可以被分类、主题、用户组和未来圈子功能共同使用的权限模型。</p>
<p>第一阶段重点考虑：</p>
<ul>
<li>分类查看权限。</li>
<li>分类发帖权限。</li>
<li>管理员和版主的权限规则。</li>
<li>多分类主题的权限合并规则。</li>
<li>首页、分类页、详情页和搜索结果统一过滤。</li>
<li>权限过滤对主题列表查询性能的影响。</li>
</ul>
<p>暂时不急于实现完整圈子系统。权限底座稳定后，再评估用户创建群组、群组管理员、置顶、加精等功能。</p>
<p>来源：<a href="/outbound?url=https%3A%2F%2Fgooseforum.online%2Fp%2Fpost%2F574" target="_blank" rel="nofollow ugc noopener noreferrer">功能建议</a>、<a href="/outbound?url=https%3A%2F%2Fgooseforum.online%2Fp%2Fpost%2F579" target="_blank" rel="nofollow ugc noopener noreferrer">下一次更新建议</a></p>
<blockquote>
<p>1 有权限的类型不可做多分类。保持干净的边界。如果一个分类设置了可见权限，那么这个分类的主题只可选择一种类型且不可修改。同时增加隐私分类id字段。<br/>
2 分类做以下处理，隐私，隐私开启入口。<br/>
3 支持邀请和申请。开启入口的可以申请。隐私状态下关闭入口的只可邀请不可申请。<br/>
4 分类管理可以增加分类详情管理页面。查看分组成员。扩大版主权限。</p>
</blockquote>
<h2 id="用户密码重置">用户密码重置</h2>
<p>为管理后台增加安全的用户密码重置入口。</p>
<p>建议采用：</p>
<ul>
<li>管理员在后台触发密码重置。</li>
<li>系统生成一次性重置链接。</li>
<li>通过邮件通知用户自行设置新密码。</li>
<li>记录管理员的重置操作。</li>
<li>后台不展示或保存明文密码。</li>
</ul>
<p>现有 CLI 重置密码能力可以继续作为部署维护手段。</p>
<p>来源：<a href="/outbound?url=https%3A%2F%2Fgooseforum.online%2Fp%2Fpost%2F574" target="_blank" rel="nofollow ugc noopener noreferrer">功能建议</a></p>
<h2 id="markdown-编辑器增强">Markdown 编辑器增强</h2>
<p>在保持 Markdown 为原始内容的前提下，降低普通用户的编辑门槛。</p>
<p>可以先支持：</p>
<ul>
<li>标题。</li>
<li>粗体和斜体。</li>
<li>引用。</li>
<li>代码和代码块。</li>
<li>链接。</li>
<li>图片。</li>
<li>有序和无序列表。</li>
</ul>
<p>后续再逐步支持：</p>
<ul>
<li>附件。</li>
<li>投票。</li>
<li>数学公式。</li>
<li>Mermaid。</li>
<li>代码高亮等客户端补充渲染。</li>
</ul>
<p>编辑器预览需要持续通过测试规约与服务端最终渲染保持一致，不急于引入完整富文本编辑器。</p>
<p>来源：<a href="/outbound?url=https%3A%2F%2Fgooseforum.online%2Fp%2Fpost%2F544" target="_blank" rel="nofollow ugc noopener noreferrer">能添加圈子或群组功能吗</a></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/484</guid>
      <pubDate>Thu, 16 Jul 2026 09:58:01 +0800</pubDate>
    </item>
    <item>
      <title>从某处评论看到，来体验下。</title>
      <link>https://gooseforum.online/p/post/496</link>
      <description>感觉还不错，速度加载也挺快\~ 上传图片出现 image.png: HTTP 400 没选分类发表按钮就一直无法点击，找了一会未什么，交互体验需要优化\~</description>
      <content:encoded><![CDATA[<p>感觉还不错，速度加载也挺快~</p>
<p>上传图片出现</p>
<p>image.png: HTTP 400</p>
<p>没选分类发表按钮就一直无法点击，找了一会未什么，交互体验需要优化~</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/496</guid>
      <pubDate>Fri, 31 Jul 2026 00:35:36 +0800</pubDate>
    </item>
    <item>
      <title>Ai下的前端/后端/Headless</title>
      <link>https://gooseforum.online/p/post/494</link>
      <description>最近好多cms其实是后端负责的，前端负责2c的内容，但是也会有很多掰扯的东西。最近看一些Headless库产生了一个想法，其实这个分工也有点像很多年前的模版引擎后期，前端切图，后端接入。只不过调整为，后端利用ai生成服务端逻辑和headless库，前端根据headless配合ui生成前端。 一句话总结： 后端/AI 负责长脑子（Headless 逻辑）。 UI 负责长颜值（轻量皮肤）。 前端 只当...</description>
      <content:encoded><![CDATA[<p>最近好多cms其实是后端负责的，前端负责2c的内容，但是也会有很多掰扯的东西。最近看一些<code>Headless</code>库产生了一个想法，其实这个分工也有点像很多年前的模版引擎后期，前端切图，后端接入。只不过调整为，后端利用ai生成服务端逻辑和headless库，前端根据headless配合ui生成前端。</p>
<pre><code>[ 后端 / AI ] ──(生成纯逻辑与契约)──&gt;  🧠 Headless 核心引擎 (状态、数据、校验)
                                              │
                                              ▼
                                    🔗 前端胶水层 (极简打通 / 神经反射)
                                              │
                                              ▼
[ 视觉 / UI ] ──(精简渲染)─────────&gt;  🎨 纯 UI 皮肤 (Tailwind / 极简组件)
</code></pre>
<p><strong>一句话总结：</strong></p>
<ul>
<li>
<p><strong>后端/AI</strong> 负责长脑子（Headless 逻辑）。</p>
</li>
<li>
<p><strong>UI</strong> 负责长颜值（轻量皮肤）。</p>
</li>
<li>
<p><strong>前端</strong> 只当最纯粹的<strong>胶水桥梁</strong>，把逻辑和皮肤丝滑缝合。</p>
</li>
</ul>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/494</guid>
      <pubDate>Fri, 24 Jul 2026 17:17:19 +0800</pubDate>
    </item>
    <item>
      <title>来都来了～</title>
      <link>https://gooseforum.online/p/post/493</link>
      <description>来都来了，大家想讨论什么就讨论什么，不要拘谨哈。如果话题多了也可以新加分类</description>
      <content:encoded><![CDATA[<p>来都来了，大家想讨论什么就讨论什么，不要拘谨哈。如果话题多了也可以新加分类</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/493</guid>
      <pubDate>Tue, 21 Jul 2026 18:39:22 +0800</pubDate>
    </item>
    <item>
      <title>功能建议</title>
      <link>https://gooseforum.online/p/post/491</link>
      <description>1.后台添加私信管理不，我安装过有个论坛后台有私信显示可以显示用户的私信这样也方便做私信审核不过这个毕竟涉及到用户的隐私也不太好，我只是建议 2.后台添加更改用户密码的按钮 3.建议后台为分类管理添加查看权限和发帖权限，比如，我创建个管理会分类但是我希望这个分类只能被网站管理人员看到和只能管理人员才能在这个分类下发帖，普通用户看不到该有该分类。</description>
      <content:encoded><![CDATA[<p>1.后台添加私信管理不，我安装过有个论坛后台有私信显示可以显示用户的私信这样也方便做私信审核不过这个毕竟涉及到用户的隐私也不太好，我只是建议
2.后台添加更改用户密码的按钮
3.建议后台为分类管理添加查看权限和发帖权限，比如，我创建个管理会分类但是我希望这个分类只能被网站管理人员看到和只能管理人员才能在这个分类下发帖，普通用户看不到该有该分类。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/491</guid>
      <pubDate>Sat, 18 Jul 2026 17:54:01 +0800</pubDate>
    </item>
    <item>
      <title>下一次更新建议</title>
      <link>https://gooseforum.online/p/post/492</link>
      <description>下一次更新能为网站添加群组功能吗，</description>
      <content:encoded><![CDATA[<p>下一次更新能为网站添加群组功能吗，</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/492</guid>
      <pubDate>Sun, 19 Jul 2026 11:27:05 +0800</pubDate>
    </item>
    <item>
      <title>安装网站后的问题</title>
      <link>https://gooseforum.online/p/post/490</link>
      <description>1.私信界面点击其他页面后是能够正常显示红点通知的但是为什么用户发布主题后帖子无法通过点击其他链接后在返回主题页面显示新的主题而是需要强制刷新后才显示 2.修改资料修改用户名当我点击了用户名但是不想修改时点击取消无反应。感觉用户名可以和其他网站一样用户无法修改或者修改需要提交申请 3.申请友情链接和发送主题是一个后台无法受到友情链接的帖子就更加不可能审核了</description>
      <content:encoded><![CDATA[<p>1.私信界面点击其他页面后是能够正常显示红点通知的但是为什么用户发布主题后帖子无法通过点击其他链接后在返回主题页面显示新的主题而是需要强制刷新后才显示
2.修改资料修改用户名当我点击了用户名但是不想修改时点击取消无反应。感觉用户名可以和其他网站一样用户无法修改或者修改需要提交申请
3.申请友情链接和发送主题是一个后台无法受到友情链接的帖子就更加不可能审核了</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/490</guid>
      <pubDate>Sat, 18 Jul 2026 15:38:13 +0800</pubDate>
    </item>
    <item>
      <title>安装网站问题</title>
      <link>https://gooseforum.online/p/post/489</link>
      <description>我点击这个exe直接等一会就自动退出了，有人知道这是怎么回事吗，这是哪里出了问题</description>
      <content:encoded><![CDATA[<p><img src="/file/img/2026/07/18/5f44f93f-e9bb-485f-88f6-652c81cc93ee.webp" alt="image" loading="lazy" decoding="async"/>我点击这个exe直接等一会就自动退出了，有人知道这是怎么回事吗，这是哪里出了问题</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/489</guid>
      <pubDate>Sat, 18 Jul 2026 13:16:58 +0800</pubDate>
    </item>
    <item>
      <title>能添加圈子或群组功能吗</title>
      <link>https://gooseforum.online/p/post/486</link>
      <description>能添加圈子或群组功能吗</description>
      <content:encoded><![CDATA[<p>能添加圈子或群组功能吗</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/486</guid>
      <pubDate>Thu, 16 Jul 2026 19:12:15 +0800</pubDate>
    </item>
    <item>
      <title>正文内容的背景和右侧卡片相连了？</title>
      <link>https://gooseforum.online/p/post/475</link>
      <description>RT RT</description>
      <content:encoded><![CDATA[<p>RT
RT</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/475</guid>
      <pubDate>Tue, 23 Jun 2026 13:39:50 +0800</pubDate>
    </item>
    <item>
      <title>有官方Q群吗</title>
      <link>https://gooseforum.online/p/post/488</link>
      <description>有官方Q群吗，方便交流</description>
      <content:encoded><![CDATA[<p>有官方Q群吗，方便交流</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/488</guid>
      <pubDate>Sat, 18 Jul 2026 03:56:34 +0800</pubDate>
    </item>
    <item>
      <title>Zooproxy实测分享｜稳定好用的代理服务使用体验与技巧</title>
      <link>https://gooseforum.online/p/post/487</link>
      <description>各位GooseForum的坛友大家好！最近一直在实测各类代理服务，对比多款工具后，想和大家详细分享一下 Zooproxy 的真实使用体验，涵盖功能特点、实测效果、实操流程以及避坑技巧，不管是日常网络访问、轻量爬虫开发还是项目测试，都有不错的参考价值。 一、简单介绍：Zooproxy核心定位 Zooproxy是一款主打高可用、低延迟、高存活率的代理服务，适配个人开发者、轻量业务场景，支持动态住宅代理...</description>
      <content:encoded><![CDATA[<p>各位GooseForum的坛友大家好！最近一直在实测各类代理服务，对比多款工具后，想和大家详细分享一下 <strong>Zooproxy</strong> 的真实使用体验，涵盖功能特点、实测效果、实操流程以及避坑技巧，不管是日常网络访问、轻量爬虫开发还是项目测试，都有不错的参考价值。</p>
<h2 id="一-简单介绍-zooproxy核心定位">一、简单介绍：Zooproxy核心定位</h2>
<p>Zooproxy是一款主打<strong>高可用、低延迟、高存活率</strong>的代理服务，适配个人开发者、轻量业务场景，支持动态住宅代理、静态代理等多种类型，覆盖节点范围广。区别于很多小众代理工具稳定性差、IP失效快、延迟波动大的问题，Zooproxy主打轻量化、易上手，无需复杂配置，新手也能快速落地使用，非常适合日常开发和轻量网络需求。</p>
<h2 id="二-核心优势实测-对比多款同类工具">二、核心优势实测（对比多款同类工具）</h2>
<p>这段时间持续压测使用，总结了几个比较亮眼的核心优势，也是我长期留存使用的关键：</p>
<p>1. <strong>IP存活率高，失效率极低</strong>：实测常规时段IP可用率能稳定在95%以上，不像部分代理工具批量获取后大半失效，大幅减少无效重试的时间成本。同时支持自动剔除无效IP，留存可用优质节点，使用体验更流畅。</p>
<p>2. <strong>延迟稳定，波动小</strong>：无论是国内访问还是跨境轻量请求，延迟表现均衡，无突发高延迟、丢包等问题，适合需要稳定网络链路的爬虫测试、接口调试、数据采集等场景。</p>
<p>3. <strong>配置简单，兼容性强</strong>：支持主流请求方式，适配Python、Go、Java等各类开发语言，同时兼容Proxifier等代理工具，全局代理、局部接口代理均可灵活配置，适配绝大多数个人开发场景。</p>
<p>4. <strong>节点资源充足</strong>：拥有海量运营商原生IP资源，IP池更新频率高，重复率低，能够有效规避IP封禁、频次限制问题，爬虫、批量请求场景适配性极佳。</p>
<h2 id="三-完整使用流程-新手零基础可上手">三、完整使用流程（新手零基础可上手）</h2>
<p>给大家整理了一套最简单的实操步骤，全程无复杂操作，新手直接照搬即可：</p>
<p>1. 登录<a href="/outbound?url=https%3A%2F%2Fzooproxy.com%2F%3Fkwd%3DLQ-gooseforum" target="_blank" rel="nofollow ugc noopener noreferrer">Zooproxy官方平台</a>，根据自身业务场景选择对应代理类型（日常使用选动态代理、长期固定访问选静态代理）；</p>
<p>2. 批量获取代理IP列表，建议优先进行本地有效性检测，筛选低延迟、高可用节点；</p>
<p>3. 对接项目或工具，支持随机调用节点，单次请求自动匹配优质IP；</p>
<p>4. 依托平台自动容错机制，请求失败自动剔除失效IP，无需手动筛选维护节点。</p>
<h2 id="四-实用使用技巧-避坑指南">四、实用使用技巧&amp;避坑指南</h2>
<p>结合实测踩坑经验，分享几个能大幅提升使用体验的小技巧，帮大家规避问题、提升效率：</p>
<p>1. <strong>必做前置检测</strong>：批量获取IP后，不要直接投入使用，优先做一轮有效性+延迟检测，剔除超时、无效节点，避免影响业务稳定性。</p>
<p>2. <strong>控制请求频次</strong>：轻量请求无需高频切换IP，固定优质节点短时使用即可；批量高频请求建议开启随机轮换，降低IP封禁概率。</p>
<p>3. <strong>区分场景选代理类型</strong>：短期临时访问、爬虫采集选动态住宅代理，性价比更高；需要固定IP访问、账号常驻场景，优先静态代理，避免频繁换IP导致风控。</p>
<p>4. <strong>规避高频并发滥用</strong>：个人轻量使用完全足够，切勿超大流量、超高并发暴力请求，容易触发风控限制，影响节点可用性。</p>
<h2 id="五-整体总结">五、整体总结</h2>
<p>综合来看，Zooproxy是一款<strong>轻量化、高稳定、低门槛</strong>的优质代理工具，没有复杂的部署和配置流程，IP质量、延迟稳定性远超多数同价位小众代理服务，完美适配个人开发者、学生党日常开发、接口测试、轻量爬虫、网络访问等场景。</p>
<p>对于追求稳定、不想折腾节点维护、需要低成本解决网络代理需求的朋友，非常值得尝试。</p>
<p>最后欢迎各位坛友交流讨论！大家平时都用哪些代理工具？有没有更好的使用技巧？评论区一起交流避坑～</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/487</guid>
      <pubDate>Fri, 17 Jul 2026 15:05:57 +0800</pubDate>
    </item>
    <item>
      <title>眼前一亮的Codex-gpt5.6关于我对话的意图识别</title>
      <link>https://gooseforum.online/p/post/485</link>
      <description>出于好奇发生了以下对话（我知道项目情况，本来想着先问一下引导他关于后续升级事情讨论，最后突然灵光一闪想问一下他，能不能识别我的意图） 项目中使用ts了吗，用的谁家什么版本库 Codex:(前面几个不重要的回复省略) 间接还是直接。 Codex:(前面几个不重要的回复省略) 两个版本？不会有影响么。 Codex:(前面几个不重要的回复省略) 亮点来了 正中眉心～</description>
      <content:encoded><![CDATA[<p>出于好奇发生了以下对话（我知道项目情况，本来想着先问一下引导他关于后续升级事情讨论，最后突然灵光一闪想问一下他，能不能识别我的意图）</p>
<blockquote>
<p>项目中使用ts了吗，用的谁家什么版本库</p>
</blockquote>
<p>Codex:…(前面几个不重要的回复省略)</p>
<blockquote>
<p>间接还是直接。</p>
</blockquote>
<p>Codex:…(前面几个不重要的回复省略)</p>
<blockquote>
<p>两个版本？不会有影响么。</p>
</blockquote>
<p>Codex:…(前面几个不重要的回复省略)</p>
<p><code>亮点来了</code></p>
<p><img src="/file/img/2026/07/16/41b8fc4c-da8d-4d04-b094-e1db484782de.webp" alt="image" loading="lazy" decoding="async"/></p>
<p>正中眉心～</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/485</guid>
      <pubDate>Thu, 16 Jul 2026 17:11:28 +0800</pubDate>
    </item>
    <item>
      <title>Lunch Note for Kids: 50+ Sweet Ideas to Brighten Every School Day</title>
      <link>https://gooseforum.online/p/post/483</link>
      <description>Packing a healthy lunch is one way to show your child you care, but adding a lunch note for kids can make lunchtime even more special. A few encouraging words, a funny joke, or a simple reminder that ...</description>
      <content:encoded><![CDATA[<p>Packing a healthy lunch is one way to show your child you care, but adding a <strong>lunch note for kids</strong> can make lunchtime even more special. A few encouraging words, a funny joke, or a simple reminder that you’re thinking of them can boost their confidence and put a smile on their face during the school day.</p>
<p>Whether your child is starting preschool or heading off to elementary school, lunch notes are a simple tradition that can create lasting memories.</p>
<h2 id="why-add-a-lunch-note-for-kids">Why Add a Lunch Note for Kids?</h2>
<p>Children often look forward to discovering a surprise inside their lunchbox. A thoughtful lunch note can:</p>
<ul>
<li>
<p>Make your child feel loved and supported.</p>
</li>
<li>
<p>Encourage positive thinking throughout the day.</p>
</li>
<li>
<p>Ease first-day or back-to-school anxiety.</p>
</li>
<li>
<p>Build confidence before a test or presentation.</p>
</li>
<li>
<p>Strengthen your daily connection, even when you’re apart.</p>
</li>
</ul>
<p>A handwritten message only takes a few seconds but can have a lasting impact.</p>
<h2 id="what-to-write-on-a-lunch-note">What to Write on a Lunch Note</h2>
<p>You don’t need to write a long letter. Short, cheerful messages work best. Here are a few ideas:</p>
<ul>
<li>
<p>Have an amazing day!</p>
</li>
<li>
<p>I believe in you.</p>
</li>
<li>
<p>You make me proud every day.</p>
</li>
<li>
<p>Smile—you’ve got this!</p>
</li>
<li>
<p>Can’t wait to hear about your day!</p>
</li>
<li>
<p>You’re kind, smart, and brave.</p>
</li>
<li>
<p>Remember to be yourself.</p>
</li>
<li>
<p>Have fun with your friends!</p>
</li>
<li>
<p>Good luck on your spelling test!</p>
</li>
<li>
<p>I love you to the moon and back.</p>
</li>
</ul>
<p>Adding a small drawing, heart, or smiley face makes the note even more personal.</p>
<h2 id="funny-lunch-note-ideas">Funny Lunch Note Ideas</h2>
<p>Kids love to laugh! Try including a joke in their lunchbox.</p>
<ul>
<li>
<p>What do you call cheese that isn’t yours? Nacho cheese!</p>
</li>
<li>
<p>Why did the banana go to school? Because it wanted to be a little smarter!</p>
</li>
<li>
<p>What kind of tree fits in your hand? A palm tree.</p>
</li>
<li>
<p>Why was the math book sad? It had too many problems.</p>
</li>
<li>
<p>What do bees use to brush their hair? A honeycomb.</p>
</li>
</ul>
<p>A simple joke can turn lunchtime into the best part of the day.</p>
<h2 id="inspirational-lunch-notes">Inspirational Lunch Notes</h2>
<p>If your child needs extra encouragement, motivational messages can help.</p>
<ul>
<li>
<p>Every day is a new adventure.</p>
</li>
<li>
<p>Mistakes help us learn.</p>
</li>
<li>
<p>Believe in yourself because I believe in you.</p>
</li>
<li>
<p>Be kind whenever you can.</p>
</li>
<li>
<p>Today is full of possibilities.</p>
</li>
<li>
<p>Your best is always enough.</p>
</li>
<li>
<p>Keep trying—you can do hard things.</p>
</li>
<li>
<p>Be curious and keep learning.</p>
</li>
</ul>
<h2 id="lunch-notes-for-different-ages">Lunch Notes for Different Ages</h2>
<h3 id="preschool">Preschool</h3>
<p>Young children enjoy simple messages with colorful drawings.</p>
<ul>
<li>
<p>Have fun today!</p>
</li>
<li>
<p>Big hugs!</p>
</li>
<li>
<p>You’re my sunshine.</p>
</li>
<li>
<p>I love you!</p>
</li>
</ul>
<h3 id="elementary-school">Elementary School</h3>
<p>School-age children appreciate encouraging words and jokes.</p>
<ul>
<li>
<p>You’re doing an awesome job.</p>
</li>
<li>
<p>Make someone smile today.</p>
</li>
<li>
<p>Have fun learning something new.</p>
</li>
<li>
<p>You’re amazing!</p>
</li>
</ul>
<h3 id="older-kids">Older Kids</h3>
<p>As children grow, they often enjoy more mature and supportive messages.</p>
<ul>
<li>
<p>Good luck today—you’ve prepared well.</p>
</li>
<li>
<p>Believe in your abilities.</p>
</li>
<li>
<p>Keep being kind and confident.</p>
</li>
<li>
<p>I’m proud of the person you’re becoming.</p>
</li>
</ul>
<h2 id="make-lunch-notes-more-fun">Make Lunch Notes More Fun</h2>
<p>Here are a few creative ideas:</p>
<ul>
<li>
<p>Use colorful pens or markers.</p>
</li>
<li>
<p>Add stickers or stamps.</p>
</li>
<li>
<p>Include a small puzzle or riddle.</p>
</li>
<li>
<p>Draw a simple cartoon.</p>
</li>
<li>
<p>Add seasonal or holiday themes.</p>
</li>
<li>
<p>Write messages on reusable lunch cards.</p>
</li>
</ul>
<p>Reusable lunch note cards are especially convenient because they can be used throughout the school year.</p>
<h2 id="benefits-beyond-lunchtime">Benefits Beyond Lunchtime</h2>
<p>A <strong>lunch note for kids</strong> does more than brighten lunch. It helps create positive family routines and reminds children they are supported wherever they go.</p>
<p>Many parents say their children save these little notes for years, making them treasured keepsakes long after the school year ends.</p>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>Including a <strong><a href="/outbound?url=https%3A%2F%2Fwww.bento-boxes.com%2Flunch-notes-for-kids" target="_blank" rel="nofollow ugc noopener noreferrer">lunch note for kids</a></strong> is one of the easiest ways to make school lunches more meaningful. Whether you write a heartfelt message, share a funny joke, or offer words of encouragement, your child will appreciate knowing you’re thinking about them.</p>
<p>If you’re looking for creative ways to make lunchtime more enjoyable, explore our collection of lunch accessories, lunchbox ideas, and printable lunch notes to make every school day a little brighter.</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/483</guid>
      <pubDate>Thu, 09 Jul 2026 17:16:36 +0800</pubDate>
    </item>
    <item>
      <title>搞了一个非常激进的改动，应该得过几天才能加新功能了</title>
      <link>https://gooseforum.online/p/post/482</link>
      <description>RT 文章/评论 模式 调整为 主题/回复 模式。 页面上可能改完之后看不出区别，不过后续加功能会更好维护。</description>
      <content:encoded><![CDATA[<p>RT 文章/评论 模式 调整为 主题/回复 模式。
页面上可能改完之后看不出区别，不过后续加功能会更好维护。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/482</guid>
      <pubDate>Tue, 07 Jul 2026 23:37:41 +0800</pubDate>
    </item>
    <item>
      <title>[已回迁]服务器迁移</title>
      <link>https://gooseforum.online/p/post/479</link>
      <description>RT 基本迁移完毕。看看效果先</description>
      <content:encoded><![CDATA[<p>RT 基本迁移完毕。看看效果先</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/479</guid>
      <pubDate>Tue, 30 Jun 2026 11:41:11 +0800</pubDate>
    </item>
    <item>
      <title>markdown编辑器添加vditor和wangeditor怎么样</title>
      <link>https://gooseforum.online/p/post/480</link>
      <description>所见即所得模式下，在编辑器加入排版 颜色 表格等等更多功能会更好，重要的是都适配vue</description>
      <content:encoded><![CDATA[<p>所见即所得模式下，在编辑器加入排版 颜色 表格等等更多功能会更好，重要的是都适配vue</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/480</guid>
      <pubDate>Wed, 01 Jul 2026 11:18:55 +0800</pubDate>
    </item>
    <item>
      <title>可以讨论下其他的，比如‘梦幻西游’这个排队怎么这么久</title>
      <link>https://gooseforum.online/p/post/476</link>
      <description>RTRTRTRT</description>
      <content:encoded><![CDATA[<p>RTRTRTRT</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/476</guid>
      <pubDate>Tue, 23 Jun 2026 19:29:54 +0800</pubDate>
    </item>
    <item>
      <title>relaxed~</title>
      <link>https://gooseforum.online/p/post/478</link>
      <description></description>
      <content:encoded><![CDATA[<p><img src="/file/img/2026/06/25/d3a1454e-4226-4ca8-9144-87245346bb31.webp" alt="MVIMG_20260625_222456" loading="lazy" decoding="async"/></p>
<p>如图</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/478</guid>
      <pubDate>Thu, 25 Jun 2026 22:26:45 +0800</pubDate>
    </item>
    <item>
      <title>[GooseForum]v0.2.40-HTTP通知(beta版)</title>
      <link>https://gooseforum.online/p/post/477</link>
      <description>本版本开始除了一些编辑和ui优化，增加了Http事件通知支持，搭建GooseForum第三方通知频道提供一个切入点 HTTP 通知使用说明 HTTP 通知会在选中的站内事件发生后，异步向回调地址发送 POST 请求。这个功能是尽力通知，失败不会影响用户发帖、回复或注册。 支持的事件 article.published article.updated comment.created user.sig...</description>
      <content:encoded><![CDATA[<blockquote>
<p>本版本开始除了一些编辑和ui优化，增加了Http事件通知支持，搭建GooseForum第三方通知频道提供一个切入点</p>
</blockquote>
<p><img src="/file/img/2026/06/23/57f7a36d-c480-490c-9738-f2c6ab6c3943.webp" alt="image" loading="lazy" decoding="async"/></p>
<h2 id="http-通知使用说明">HTTP 通知使用说明</h2>
<p>HTTP 通知会在选中的站内事件发生后，异步向回调地址发送 POST 请求。这个功能是尽力通知，失败不会影响用户发帖、回复或注册。</p>
<h3 id="支持的事件">支持的事件</h3>
<ul>
<li><code>article.published</code></li>
<li><code>article.updated</code></li>
<li><code>comment.created</code></li>
<li><code>user.signup</code></li>
<li><code>moderation.report.created</code></li>
</ul>
<h3 id="请求格式">请求格式</h3>
<p>请求体固定为 JSON，Header 会带上事件名、投递 ID、时间戳和签名。</p>
<pre><code class="language-http">POST /your-webhook HTTP/1.1
Content-Type: application/json
X-Goose-Event: article.published
X-Goose-Delivery: 7c9f0b0fd4e2a111
X-Goose-Timestamp: 1710000000
X-Goose-Signature: sha256=...
</code></pre>
<pre><code class="language-json">{
  &#34;event&#34;: &#34;article.published&#34;,
  &#34;timestamp&#34;: 1710000000,
  &#34;data&#34;: {
    &#34;articleId&#34;: 123,
    &#34;title&#34;: &#34;Hello GooseForum&#34;,
    &#34;userId&#34;: 1
  }
}
</code></pre>
<h3 id="签名校验">签名校验</h3>
<p><code>X-Goose-Signature</code> 由 Secret、时间戳和原始请求体计算得出。</p>
<pre><code class="language-text">sha256 = HMAC_SHA256(secret, timestamp + &#34;.&#34; + rawBody)
</code></pre>
<p>验签时请使用原始 body，不要先解析再重新序列化。</p>
<h3 id="node-js">Node.js</h3>
<pre><code class="language-js">import crypto from &#39;node:crypto&#39;

function verify(secret, timestamp, rawBody, signature) {
  const digest = crypto
    .createHmac(&#39;sha256&#39;, secret)
    .update(timestamp + &#39;.&#39; + rawBody)
    .digest(&#39;hex&#39;)

  return signature === &#39;sha256=&#39; + digest
}
</code></pre>
<h3 id="go">Go</h3>
<pre><code class="language-go">func verify(secret string, timestamp string, rawBody []byte, signature string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(timestamp))
    mac.Write([]byte(&#34;.&#34;))
    mac.Write(rawBody)
    want := &#34;sha256=&#34; + hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(signature), []byte(want))
}
</code></pre>
<h3 id="失败保护">失败保护</h3>
<p>同一个回调地址连续 3 次通知失败后，系统会自动关闭该地址，并标记为异常终止。重新启用并保存后会清空失败状态。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/477</guid>
      <pubDate>Tue, 23 Jun 2026 19:55:50 +0800</pubDate>
    </item>
    <item>
      <title>想着加一个时间通知服务</title>
      <link>https://gooseforum.online/p/post/474</link>
      <description>除了最近大家提的 level / 文件/编辑 以外我又想了一个事件event服务。 可以配置回调地址。然后相关事件发出来，方便大家开发一些接入服务。</description>
      <content:encoded><![CDATA[<p>除了最近大家提的 level / 文件/编辑 以外我又想了一个事件event服务。<br/>
可以配置回调地址。然后相关事件发出来，方便大家开发一些接入服务。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/474</guid>
      <pubDate>Tue, 23 Jun 2026 11:16:21 +0800</pubDate>
    </item>
    <item>
      <title>感觉强大的小黑屋要先行提到日程了</title>
      <link>https://gooseforum.online/p/post/473</link>
      <description>本站不能乱发黄赌毒，以及偏激的内容哈。</description>
      <content:encoded><![CDATA[<p>本站不能乱发黄赌毒，以及偏激的内容哈。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/473</guid>
      <pubDate>Sun, 21 Jun 2026 21:01:54 +0800</pubDate>
    </item>
    <item>
      <title>越来越好，期待附件功能</title>
      <link>https://gooseforum.online/p/post/470</link>
      <description>越来越好，期待附件功能 后面把附件功能做好，就太棒了</description>
      <content:encoded><![CDATA[<p><code>越来越好，期待附件功能</code></p>
<p>后面把附件功能做好，就太棒了</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/470</guid>
      <pubDate>Sun, 21 Jun 2026 10:10:34 +0800</pubDate>
    </item>
    <item>
      <title>今年70了，还可以学go吗</title>
      <link>https://gooseforum.online/p/post/471</link>
      <description>小伙子们，我今年70了，我还有机会学习golang吗</description>
      <content:encoded><![CDATA[<p>小伙子们，我今年70了，我还有机会学习golang吗</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/471</guid>
      <pubDate>Sun, 21 Jun 2026 10:52:28 +0800</pubDate>
    </item>
    <item>
      <title>哎呀 Godot 4.7 发布了</title>
      <link>https://gooseforum.online/p/post/469</link>
      <description>有没有感兴趣一起研究学习的小伙伴。</description>
      <content:encoded><![CDATA[<p>有没有感兴趣一起研究学习的小伙伴。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/469</guid>
      <pubDate>Sat, 20 Jun 2026 14:23:14 +0800</pubDate>
    </item>
    <item>
      <title>震惊！！点进标题帖子，返回键会回到顶部？？</title>
      <link>https://gooseforum.online/p/post/467</link>
      <description>顶部往下刷到底点进标题帖子，返回键会回到顶部，没有返回到刚刚点进标题帖子的停留！每次返回还得往下刷找找刚刚点进的帖子😅</description>
      <content:encoded><![CDATA[<p>顶部往下刷到底点进标题帖子，返回键会回到顶部，没有返回到刚刚点进标题帖子的停留！每次返回还得往下刷找找刚刚点进的帖子😅</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/467</guid>
      <pubDate>Wed, 17 Jun 2026 11:34:28 +0800</pubDate>
    </item>
    <item>
      <title>感觉今天浪费了一吨的token</title>
      <link>https://gooseforum.online/p/post/468</link>
      <description>后面4个commit改来改去的，效果不理想。</description>
      <content:encoded><![CDATA[<p>后面4个commit改来改去的，效果不理想。
<img src="/file/img/2026/06/17/0d5a2379-fd94-4846-b073-50deb648c3eb.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/468</guid>
      <pubDate>Wed, 17 Jun 2026 23:36:46 +0800</pubDate>
    </item>
    <item>
      <title>GooseForum 做了一个head的淡显效果，大家觉得如何</title>
      <link>https://gooseforum.online/p/post/466</link>
      <description>RT 对于这个效果如果觉得不好，或者有其他显示建议可以在本文下面发。可以调整</description>
      <content:encoded><![CDATA[<p>RT
对于这个效果如果觉得不好，或者有其他显示建议可以在本文下面发。可以调整</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/466</guid>
      <pubDate>Tue, 16 Jun 2026 22:01:07 +0800</pubDate>
    </item>
    <item>
      <title>版主功能初支持&amp;管理页面组件风格统一风格处理</title>
      <link>https://gooseforum.online/p/post/465</link>
      <description>GooseForum 0.2.36 第一版支持版主功能的版本。版主当前可以参与封禁和解封主题。 优化了回复组件，支持用户在回复中上传图片。 admin 组件风格统一化，优化之前部分有细节风格不同的问题。</description>
      <content:encoded><![CDATA[<h1 id="gooseforum-0-2-36">GooseForum 0.2.36</h1>
<ul>
<li>第一版支持版主功能的版本。版主当前可以参与封禁和解封主题。</li>
<li>优化了回复组件，支持用户在回复中上传图片。</li>
<li>admin 组件风格统一化，优化之前部分有细节风格不同的问题。</li>
</ul>
<p><img src="/file/img/2026/06/16/6ddad04e-2d4a-42dd-8b03-3b47fa31cf3d.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/465</guid>
      <pubDate>Tue, 16 Jun 2026 21:27:12 +0800</pubDate>
    </item>
    <item>
      <title>你的传家宝</title>
      <link>https://gooseforum.online/p/post/464</link>
      <description>&#34; hello world ！</description>
      <content:encoded><![CDATA[<p>&#34; hello world ！&#34;</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/464</guid>
      <pubDate>Mon, 15 Jun 2026 23:21:05 +0800</pubDate>
    </item>
    <item>
      <title>这么好的论坛大家应该积极用起来，哈哈哈哈</title>
      <link>https://gooseforum.online/p/post/459</link>
      <description>常态50MB的内存占用。 2C2G都可以上几百QPS（目前还暂不支持cdn，只是页面的返回的qps）。 默认备份以及超轻量的空间占用</description>
      <content:encoded><![CDATA[<p>常态50MB的内存占用。
<img src="/file/img/2026/06/10/7bf29209-8d24-47b6-b421-d5b6e4acf959.webp" alt="image" loading="lazy" decoding="async"/></p>
<p>2C2G都可以上几百QPS（目前还暂不支持cdn，只是页面的返回的qps）。
<img src="/file/img/2026/06/10/1bbeb3f2-4957-4468-a368-45a8d83ce4ef.webp" alt="image" loading="lazy" decoding="async"/></p>
<p>默认备份以及超轻量的空间占用
<img src="/file/img/2026/06/10/18a125a6-12a6-4755-9646-ccaab6543e7b.webp" alt="QQ_1781106835818" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/459</guid>
      <pubDate>Wed, 10 Jun 2026 23:54:24 +0800</pubDate>
    </item>
    <item>
      <title>新增预设头像</title>
      <link>https://gooseforum.online/p/post/463</link>
      <description>预设头像更新，从8变成12，并且重新生成了一批。具体如下</description>
      <content:encoded><![CDATA[<p>预设头像更新，从8变成12，并且重新生成了一批。具体如下</p>
<p><img src="/static/pic/1.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/2.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/3.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/4.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/5.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/6.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/7.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/8.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/9.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/10.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/11.webp" alt="" loading="lazy" decoding="async"/><br/>
<img src="/static/pic/12.webp" alt="" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/463</guid>
      <pubDate>Sun, 14 Jun 2026 21:59:01 +0800</pubDate>
    </item>
    <item>
      <title>普大喜奔，GooseForum 被 Awesome Go 收录啦！</title>
      <link>https://gooseforum.online/p/post/462</link>
      <description>普大喜奔，GooseForum 被 Awesome Go 收录啦！ 虽然只是列表里小小的一行，但对我这种个人为爱发电项目来说，还是挺开心的。一路边写边改，边踩坑边修，终于也算在 Go 生态的小角落里露了个脸。 GooseForum 是一个基于 Go、Vue 和 Tailwind CSS 的自托管论坛系统。目标也很简单：做一个部署起来不折腾、用起来清爽、后续还能慢慢折腾主题和社区玩法的论坛。 项目地...</description>
      <content:encoded><![CDATA[<p>普大喜奔，GooseForum 被 Awesome Go 收录啦！</p>
<p>虽然只是列表里小小的一行，但对我这种个人为爱发电项目来说，还是挺开心的。一路边写边改，边踩坑边修，终于也算在 Go 生态的小角落里露了个脸。</p>
<p>GooseForum 是一个基于 Go、Vue 和 Tailwind CSS 的自托管论坛系统。目标也很简单：做一个部署起来不折腾、用起来清爽、后续还能慢慢折腾主题和社区玩法的论坛。</p>
<p>项目地址： <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fleancodebox%2FGooseForum" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/leancodebox/GooseForum</a> <br/>
Awesome Go： <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Favelino%2Fawesome-go" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/avelino/awesome-go</a></p>
<p>继续加油，继续慢慢打磨。</p>
<p><img src="/file/img/2026/06/14/dcec14e2-904b-4377-9b20-1ab83121590c.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/462</guid>
      <pubDate>Sun, 14 Jun 2026 13:13:52 +0800</pubDate>
    </item>
    <item>
      <title>「千呼万唤始出来」可定制的主题初版本GooseForum</title>
      <link>https://gooseforum.online/p/post/458</link>
      <description>主题定制GooseForum初版本尝鲜。在 v0.2.23 版本中，GooseForum 不仅支持了双色主题。更是支持第一版主题自定义面板。未来将会在这个页面上继续发扬光大。让GooseForum的配置更上一层楼 并且预设了4种配置，欢迎大家使用～</description>
      <content:encoded><![CDATA[<p>主题定制GooseForum初版本尝鲜。在 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fleancodebox%2FGooseForum%2Freleases%2Ftag%2Fv0.2.23" target="_blank" rel="nofollow ugc noopener noreferrer">v0.2.23</a> 版本中，GooseForum 不仅支持了双色主题。更是支持第一版主题自定义面板。未来将会在这个页面上继续发扬光大。让GooseForum的配置更上一层楼</p>
<p><img src="/file/img/2026/06/10/a7932701-819a-4a77-b6a5-cc932892383a.webp" alt="image" loading="lazy" decoding="async"/></p>
<p>并且预设了4种配置，欢迎大家使用～
<img src="/file/img/2026/06/11/551ee881-e585-418e-913e-56c2a7d5fd36.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/458</guid>
      <pubDate>Wed, 10 Jun 2026 22:02:52 +0800</pubDate>
    </item>
    <item>
      <title>我再乱更新umami我就是🐷</title>
      <link>https://gooseforum.online/p/post/461</link>
      <description>可能是因为 umami 所在服务器是国内的缘故吧，每次更新 umami 死慢死慢的。上次更新是因为next的漏洞吧，机器搞挂了。昨天一时兴起想更新一下。结果旧的恢复不过来，新的磨磨叽叽一直也安装不上来。</description>
      <content:encoded><![CDATA[<p>可能是因为 umami 所在服务器是国内的缘故吧，每次更新 umami 死慢死慢的。上次更新是因为next的漏洞吧，机器搞挂了。昨天一时兴起想更新一下。结果旧的恢复不过来，新的磨磨叽叽一直也安装不上来。</p>
<p><img src="/file/img/2026/06/11/31fb2286-8939-4589-aea0-41618beb506b.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/461</guid>
      <pubDate>Thu, 11 Jun 2026 23:48:32 +0800</pubDate>
    </item>
    <item>
      <title>是不是每天发的内容太正经了，大家都不来灌水</title>
      <link>https://gooseforum.online/p/post/460</link>
      <description>其实高数并不难，只要你把它放下，你的生活就会瞬间变得轻松很多。</description>
      <content:encoded><![CDATA[<blockquote>
<p>其实高数并不难，只要你把它放下，你的生活就会瞬间变得轻松很多。</p>
</blockquote>
<p><img src="/file/img/2026/06/11/98a64b23-feef-4f1e-b4a8-18997ecb4d22.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/460</guid>
      <pubDate>Thu, 11 Jun 2026 21:16:27 +0800</pubDate>
    </item>
    <item>
      <title>面向tailwindcss的定制主题规划</title>
      <link>https://gooseforum.online/p/post/457</link>
      <description>daisyui-主题制作页面 因为项目是基于 tailwind 的。之前也有小伙伴说过字体小（我觉得刚刚好）。另外深色和浅色主题。所以规划一下走类似daisyui 的调色板配置这一套，但是还不能出现影响admin的情况，应该可以做到。先标记一下。后面打算走这个方向。老版本使用 daisyui 的时候能调整的从字体/颜色到圆角，还是很全面的。是个比较可行的方向。</description>
      <content:encoded><![CDATA[<p><a href="/outbound?url=https%3A%2F%2Fdaisyui.com%2Ftheme-generator%2F%23theme%3DeJx1lOtu4yAQhV8FWaq0lRoEw33fhti4seqYCBxtd1d992IcOaYkP5n55pyZAfG_mezZNb-bcXg_zc1b0_rRh0NsTy6HOxs-UvRwWONHG92BEpIy_mNsT79AviCCiTKISQzCvP6EYQdzssAUGGIaUwUVzPawyrBQiCnMCK_g1k-zm-atwIjcCtNICUxlUXAJw9mGvxsr-MKCpggMw4SYB3BtsM5KZS5SQu6Lokt4t_eQOg8gYelHM_6Qrk1yFQGJKAEMtFiSbds9KyE7GI4oN4nlNftMn2pERWoLiiEmd52DHe9rEquBWC6ME3jAPjWQSDEsddHTMPV-A9X6GqRAIDiWUJGVNKzSJt2aVNgwUaz0mgaO8S5_ez-AqKbYlIu8wbVDLiI8bd8AFmVPf2yYhul9g_W6fm2Q5piDecA-M1AKcYFlOYELwYd7_3S7XJbUdUU-0aZEIAppS7feg-2Ga0wvbnTtnPUJFsGd98l-cGO3ZH7Ej_6z5OPwz5VSUOY2pV3i6EPnFppePnOgc5f5tJzzafJDdLdT53p7HdNIvR2je2suwfUuxPwLrbGvb294Uxo" target="_blank" rel="nofollow ugc noopener noreferrer">daisyui-主题制作页面</a></p>
<p>因为项目是基于 tailwind 的。之前也有小伙伴说过字体小（我觉得刚刚好）。另外深色和浅色主题。所以规划一下走类似daisyui 的调色板配置这一套，但是还不能出现影响admin的情况，应该可以做到。先标记一下。后面打算走这个方向。老版本使用 daisyui 的时候能调整的从字体/颜色到圆角，还是很全面的。是个比较可行的方向。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/457</guid>
      <pubDate>Tue, 09 Jun 2026 23:29:02 +0800</pubDate>
    </item>
    <item>
      <title>GitHub App 做 OAuth 登录时，新用户为什么会直接 404？</title>
      <link>https://gooseforum.online/p/post/455</link>
      <description>最近在排查 GooseForum 的 GitHub 登录问题时，遇到一个挺隐蔽的坑。 现象是：已经授权过的老用户可以正常登录，但新用户点击 GitHub 登录后，会跳到 GitHub 的 404 页面。URL 看起来又很正常： 一开始我以为是回调地址、client_ id、OAuth 库版本或者 state 校验出了问题。但检查下来发现都不是。 真正的原因是：这个应用创建的是 GitHub App...</description>
      <content:encoded><![CDATA[<p>最近在排查 GooseForum 的 GitHub 登录问题时，遇到一个挺隐蔽的坑。</p>
<p>现象是：已经授权过的老用户可以正常登录，但新用户点击 GitHub 登录后，会跳到 GitHub 的 404 页面。URL 看起来又很正常：</p>
<pre><code class="language-text">https://github.com/login/oauth/authorize?client_id=...&amp;redirect_uri=...
</code></pre>
<p>一开始我以为是回调地址、client_id、OAuth 库版本或者 state 校验出了问题。但检查下来发现都不是。</p>
<p>真正的原因是：这个应用创建的是 <strong>GitHub App</strong>，而不是传统的 OAuth App，并且这个 GitHub App 默认还是 <strong>Private</strong> 状态。</p>
<p>Private 状态下，已有授权关系的账号可能还能继续用，但新的外部用户访问授权页面时，就会直接看到 GitHub 404。这个 404 很迷惑，因为它不像普通配置错误那样给出明确提示。</p>
<p>解决方式是在 GitHub App 设置里打开：</p>
<pre><code class="language-text">Settings -&gt; Developer settings -&gt; GitHub Apps -&gt; 你的 App -&gt; Advanced -&gt; Danger zone -&gt; Make public
</code></pre>
<p>也就是把 GitHub App 从 private 改成 public。</p>
<p>这里的说明是：</p>
<pre><code class="language-text">Make this GitHub App public
Allow this GitHub App to be installed on other accounts.
</code></pre>
<p>改完之后，新用户才能正常进入 GitHub 授权流程。</p>
<p>顺便也确认了一下，GitHub App 和 OAuth App 现在确实是两套东西。GitHub App 也可以用于用户授权登录，但如果是面向公开用户登录，就要注意它的公开状态、callback URL、权限配置这些地方。</p>
<p>这次问题最坑的地方在于：链接看起来完全没问题，代码也没明显错误，GitHub 只给了一个 404。以后如果遇到“老用户能登录，新用户 OAuth 直接 404”，可以优先检查应用是不是还处在 private 状态。</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/455</guid>
      <pubDate>Sun, 07 Jun 2026 16:24:47 +0800</pubDate>
    </item>
    <item>
      <title>把内网办公网站变成本机只读工具：一个 CLI / MCP / Skill 多合一项目实践</title>
      <link>https://gooseforum.online/p/post/451</link>
      <description>脱敏说明：本文已隐去真实公司域名、系统名称、仓库地址、表名、集群名、人员账号和业务数据。文中出现的“数据库平台”“日志平台”“发布平台”“工程平台”等均为抽象称呼，示例字段也经过泛化处理。 背景：浏览器不是所有办公查询的最佳入口 公司内部通常会有很多办公网站：数据库管理平台、日志平台、发布平台、工程管理平台、审批系统、工单系统、监控系统。它们承担了很多关键流程，但日常使用时常常有一个共同问题：用户...</description>
      <content:encoded><![CDATA[<blockquote>
<p>脱敏说明：本文已隐去真实公司域名、系统名称、仓库地址、表名、集群名、人员账号和业务数据。文中出现的“数据库平台”“日志平台”“发布平台”“工程平台”等均为抽象称呼，示例字段也经过泛化处理。</p>
</blockquote>
<h2 id="背景-浏览器不是所有办公查询的最佳入口">背景：浏览器不是所有办公查询的最佳入口</h2>
<p>公司内部通常会有很多办公网站：数据库管理平台、日志平台、发布平台、工程管理平台、审批系统、工单系统、监控系统。它们承担了很多关键流程，但日常使用时常常有一个共同问题：用户只是想查一个结果，却不得不打开页面、等待前端加载、切换菜单、输入筛选条件、翻页、再复制几段信息。</p>
<p>这些操作本身并不复杂，很多时候背后只是几个 HTTP 请求。真正复杂的是：</p>
<ul>
<li>登录态在浏览器里。</li>
<li>权限必须跟随用户本人。</li>
<li>每个系统的接口风格都不一样。</li>
<li>页面更新后，封装能力要能持续维护。</li>
<li>不能为了效率绕过安全边界。</li>
</ul>
<p>于是我们开始做一个本机工具：把内网办公网站中高频、只读、低风险的查询动作封装成 CLI、MCP 和 Codex Skill。</p>
<p>它的目标不是替代原系统，也不是做一个大而全的内部网关，而是把“每天反复点页面查信息”的动作变成结构化、可复用、可被 AI 工具调用的本机能力。</p>
<h2 id="核心原则-只读-本机-本人权限">核心原则：只读、本机、本人权限</h2>
<p>这个项目一开始就定了三个边界。</p>
<p>第一，只做只读能力。</p>
<p>查询列表、查看详情、查表结构、看少量样例数据、搜索日志、查工程和集群映射，这些可以封装。审批、删除、发布、修改配置、创建分支等会改变服务端状态的动作，不做。</p>
<p>第二，在用户本机运行。</p>
<p>工具不部署成集中服务，也不使用共享账号。每个人在自己的机器上运行，访问范围由自己的账号权限决定。</p>
<p>第三，复用浏览器登录态。</p>
<p>用户已经在 Chrome 或 Edge 里登录了内部系统，工具就从本机浏览器读取目标域名的 Cookie，并用同样的 Cookie 发起只读 HTTP 请求。这样既避免重复登录，也避免在项目里保存密码或长期 token。</p>
<p>换句话说，这个工具不是“绕过浏览器”，而是“把浏览器已经拥有的本人登录态用于更快的只读查询”。</p>
<h2 id="形态-cli-mcp-skill-放在同一个仓库">形态：CLI、MCP、Skill 放在同一个仓库</h2>
<p>这个项目最终有三个入口，但核心实现只有一份。</p>
<pre><code class="language-text">-------------------+        +-------------------+
| CLI               |        | MCP Server         |
| dogdog action ... |        | tools/call         |
+---------+---------+        +---------+---------+
          |                            |
          +-------------+--------------+
                        |
              +---------v----------+
              | Action Registry    |
              | shared capability  |
              +---------+----------+
                        |
              +---------v----------+
              | Site Adapters      |
              | database/log/etc.  |
              +---------+----------+
                        |
              +---------v----------+
              | Intranet Websites  |
              +--------------------+

Codex Skill:
- 项目说明
- 接入流程
- 安全边界
- 站点文档索引
</code></pre>
<p>CLI 适合人直接调试和日常使用。比如：</p>
<pre><code class="language-bash">dogdog capabilities
dogdog action database.find_table --json-input &#39;{&#34;table&#34;:&#34;example_table&#34;}&#39; --json
dogdog action logs.query --json-input &#39;{&#34;keyword&#34;:&#34;exampleKeyword&#34;,&#34;startAt&#34;:&#34;2026-01-01 10:00:00&#34;,&#34;endAt&#34;:&#34;2026-01-01 10:30:00&#34;}&#39; --json
</code></pre>
<p>MCP 适合接入 AI 客户端，让模型在用户授权的本机环境里调用这些只读能力。</p>
<p>Skill 则不是运行时逻辑。它更像一本给 Codex 看的项目手册：什么时候应该使用这个项目、怎么和用户一起浏览页面、怎么提取接口、哪些能力不能封装、文档写在哪里。</p>
<p>一个关键设计是：业务能力只实现一次，放在共享 action registry 里。CLI 和 MCP 都只是薄入口，Skill 只保存工作流和规范，不复制业务逻辑。</p>
<h2 id="最关键的一步-打通浏览器登录态">最关键的一步：打通浏览器登录态</h2>
<p>内网工具最容易卡住的地方不是发 HTTP 请求，而是登录态。</p>
<p>如果让每个用户手动复制 Cookie，体验很差，也不安全。如果要求用户配置账号密码，更不合适。更自然的方式是读取本机浏览器已经保存的 Cookie。</p>
<p>以 Chromium 系浏览器为例，Cookie 存在本机 profile 目录里，但敏感值会被系统加密。macOS 上通常需要通过 Keychain 获取浏览器的 Safe Storage 密钥，再解密 Cookie；Windows 和 Linux 则分别有自己的系统密钥机制。</p>
<p>这个项目里的运行时策略大致是：</p>
<ol>
<li>根据站点配置确认允许读取的目标域名。</li>
<li>在 Chrome / Edge 的常见 profile 中查找 Cookie 数据库。</li>
<li>复制一份 Cookie 数据库到临时目录，避免直接锁住浏览器文件。</li>
<li>只查询目标域名相关 Cookie。</li>
<li>解密后拼成请求头。</li>
<li>请求结束后不保存 Cookie，不打印 Cookie。</li>
</ol>
<p>这里有一个很重要的小原则：工具不扫描所有 Cookie，不把 Cookie 当配置持久化，也不在日志里输出原始登录态。它只是按站点白名单临时读取、临时使用。</p>
<h2 id="如何新增一个能力-和用户一起操作浏览器">如何新增一个能力：和用户一起操作浏览器</h2>
<p>这个项目的迭代方式也挺有意思。它不是靠猜接口，也不是先写一个抽象框架再慢慢填空，而是从真实页面出发。</p>
<p>一次能力接入通常这样走：</p>
<ol>
<li>用户说清楚目标：想查什么，页面在哪里，最后希望得到什么。</li>
<li>用户和 Codex 一起打开浏览器，按日常方式操作一遍。</li>
<li>观察页面展示和 Network 请求。</li>
<li>区分核心接口、静态资源、埋点、菜单配置、噪音请求。</li>
<li>找到最小稳定的只读 HTTP 请求。</li>
<li>记录页面流程、请求参数、响应结构、只读判断。</li>
<li>在站点 adapter 中封装成 action。</li>
<li>同时验证 CLI 和 MCP 能看到这个 action。</li>
<li>更新 Skill 和站点文档，方便下一次继续维护。</li>
</ol>
<p>这个流程的价值在于：用户懂业务，Codex 擅长从页面和代码中抽象接口。两者一起走一遍真实操作，通常能很快把“网页里的按钮”提炼成“可复用的读能力”。</p>
<h2 id="一个能力应该长什么样">一个能力应该长什么样</h2>
<p>一个好的 action 不应该暴露任意 URL，也不应该让调用方拼业务系统的内部参数。它应该接收业务语义明确的输入，返回结构化输出。</p>
<p>比如“搜索工程和集群映射”可以抽象成：</p>
<pre><code class="language-json">{
  &#34;keyword&#34;: &#34;example-service&#34;,
  &#34;groupName&#34;: &#34;&#34;,
  &#34;includeUnavailable&#34;: true
}
</code></pre>
<p>输出则整理成：</p>
<pre><code class="language-json">{
  &#34;total&#34;: 1,
  &#34;items&#34;: [
    {
      &#34;repository&#34;: &#34;example-group/example-service&#34;,
      &#34;moduleName&#34;: &#34;example-service&#34;,
      &#34;clusterName&#34;: &#34;example_cluster&#34;,
      &#34;moduleType&#34;: &#34;service&#34;,
      &#34;gitProjectId&#34;: 12345,
      &#34;gitSshUrl&#34;: &#34;git@example.internal:example-group/example-service.git&#34;,
      &#34;searchStatusName&#34;: &#34;available&#34;
    }
  ]
}
</code></pre>
<p>调用者不需要知道底层页面是哪个弹窗，也不需要关心底层请求叫 <code>moduleName</code> 还是 <code>keyword</code>。这些都由 adapter 消化。</p>
<h2 id="目前接入过的几类能力">目前接入过的几类能力</h2>
<p>为了验证这套方式，我们陆续封装了几类典型只读场景。</p>
<p>数据库平台：</p>
<ul>
<li>查询当前用户可见的数据库实例。</li>
<li>按表名定位表在哪个库。</li>
<li>查询表结构。</li>
<li>执行受限的只读 <code>SELECT</code>。</li>
<li>预览少量数据。</li>
</ul>
<p>日志平台：</p>
<ul>
<li>查询业务域和集群枚举。</li>
<li>按关键词、时间范围、集群搜索日志。</li>
<li>对容易超时的大范围查询做分片限制。</li>
</ul>
<p>发布 / 云平台：</p>
<ul>
<li>查询集群列表。</li>
<li>查询集群分组。</li>
<li>查询实例信息。</li>
<li>查询集群总览。</li>
</ul>
<p>工程平台：</p>
<ul>
<li>搜索工程、仓库和集群之间的映射。</li>
<li>识别当前用户对工程的可用状态。</li>
</ul>
<p>这些能力有一个共同点：它们都能显著减少打开浏览器、等待页面、复制信息的时间；同时它们又都是读取信息，不改变服务端状态。</p>
<h2 id="安全边界比功能更重要">安全边界比功能更重要</h2>
<p>这个项目越好用，越需要克制。</p>
<p>我们给它设了几条硬规则：</p>
<ul>
<li>不做写操作。</li>
<li>不暴露任意 URL fetch。</li>
<li>查询型 POST 必须逐个记录为只读接口。</li>
<li>SQL 只允许单条 SELECT，拒绝多语句、DDL、DML 和危险关键字。</li>
<li>不保存密码、Cookie、token。</li>
<li>不在文档、日志、fixture 里留下真实敏感数据。</li>
<li>能力输出尽量结构化，必要字段脱敏。</li>
<li>MCP tool schema 必须明确，不能让模型自由拼接内部接口。</li>
</ul>
<p>尤其是 MCP 场景，工具越容易被模型调用，schema 和边界越要清晰。模型应该调用“查某张表结构”这样的业务能力，而不是拿到一个“请求任意内部 URL”的万能工具。</p>
<h2 id="项目局部上下文-让工具越用越顺">项目局部上下文：让工具越用越顺</h2>
<p>实际使用中还有一个小发现：很多查询不是孤立的。</p>
<p>比如某个业务项目经常要查同一批数据库表、同一个日志集群、同一组服务和工程映射。如果每次都重新找这些关系，效率还是不够高。</p>
<p>所以项目里引入了“用户项目本地上下文”的概念：在用户自己的业务工程目录里维护一个轻量说明文件，记录稳定的、非敏感的关联信息，例如：</p>
<ul>
<li>常查表名和数据库位置。</li>
<li>常用日志业务域、集群和关键词。</li>
<li>服务名、工程名、仓库名、集群名的映射。</li>
<li>排查问题时积累下来的路径提示。</li>
</ul>
<p>这个文件不属于工具安装目录，也不存任何凭据。它更像一张本地索引，让 AI 和用户下次在同一个业务项目里工作时少走弯路。</p>
<h2 id="为什么要把-skill-放进同一个仓库">为什么要把 Skill 放进同一个仓库</h2>
<p>这个项目不只是一个 CLI，也不只是一个 MCP server。它还有一个很重要的维护问题：能力会越来越多，接入方式需要一致。</p>
<p>把 Codex Skill 放在仓库根目录，有几个好处：</p>
<ul>
<li>Codex 能直接知道项目规范。</li>
<li>新增能力时能自动找到文档、源码、测试入口。</li>
<li>运行时和开发期边界写得清楚。</li>
<li>项目分发时，CLI、MCP、Skill、文档一起走。</li>
</ul>
<p>Skill 的职责不是实现功能，而是告诉 Codex：</p>
<ul>
<li>这是一个只读内网工具项目。</li>
<li>每个能力要放进共享 action registry。</li>
<li>CLI 和 MCP 不重复业务逻辑。</li>
<li>浏览器控制只用于开发期发现接口。</li>
<li>运行时必须自己读取默认浏览器登录态。</li>
<li>哪些东西不能提交、不能打印、不能封装。</li>
</ul>
<p>这让项目在持续增长时不容易散。</p>
<h2 id="一点工程取舍">一点工程取舍</h2>
<p>为了启动快、维护轻，项目一开始没有引入复杂框架。Node 直接运行 TypeScript 源码，CLI 和 MCP 共享同一套 registry。站点 adapter 只是普通模块，按需注册 action。</p>
<p>这种选择有几个现实收益：</p>
<ul>
<li>启动快。</li>
<li>调试简单。</li>
<li>新增站点成本低。</li>
<li>不需要先理解一个很重的插件体系。</li>
<li>后续如果要加测试、缓存、TUI 或本地 Web UI，也可以在核心 registry 上扩展。</li>
</ul>
<p>当然，轻量不等于随意。真正要守住的是能力定义、认证读取、安全策略、文档记录这几条主线。</p>
<h2 id="总结">总结</h2>
<p>这个项目的核心不是“把网页接口扒出来”这么简单，而是建立一套可持续的本机只读能力生产方式：</p>
<ul>
<li>用户在浏览器里完成真实操作。</li>
<li>Codex 协助观察页面和请求。</li>
<li>把最小稳定的读接口封装成 action。</li>
<li>CLI 和 MCP 共享能力。</li>
<li>Skill 记录流程和边界。</li>
<li>运行时复用用户自己的浏览器登录态。</li>
<li>权限始终跟随用户本人。</li>
</ul>
<p>它解决的是一个很日常、但很有价值的问题：让内部工具从“只能在浏览器里慢慢点”变成“可以被命令行、AI 和自动化上下文可靠调用”的结构化能力。</p>
<p>更重要的是，这条路没有要求重建所有系统，也没有要求目标系统立刻提供完美开放 API。它只是从高频只读场景开始，一点点把已经存在的页面能力沉淀成更快、更稳、更适合协作的本机工具。</p>
<p>这可能是内部效率工具最舒服的一种形态：小、快、克制，但能不断长出新的爪子。</p>
<p><img src="/file/img/2026/07/28/795a8552-cb60-40f4-b405-176db325d419.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/451</guid>
      <pubDate>Wed, 03 Jun 2026 18:33:15 +0800</pubDate>
    </item>
    <item>
      <title>纪念一下第一次王者上百星</title>
      <link>https://gooseforum.online/p/post/453</link>
      <description></description>
      <content:encoded><![CDATA[<p>rt
<img src="/file/img/2026/06/04/664129e0-2015-4d58-bb01-b9abd5def8ea.webp" alt="Screenshot_2026-06-04-22-25-15-497_com.ss.android.ugc.aweme-edit" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/453</guid>
      <pubDate>Thu, 04 Jun 2026 22:31:28 +0800</pubDate>
    </item>
    <item>
      <title>深夜战神</title>
      <link>https://gooseforum.online/p/post/454</link>
      <description>纪念一下。如果i18n彻底处理好了之后。我也去外语站宣传一下。</description>
      <content:encoded><![CDATA[<p>纪念一下。如果i18n彻底处理好了之后。我也去外语站宣传一下。</p>
<p><img src="/file/img/2026/06/06/864aaad3-442c-4d76-8218-ac0f25d3c4c8.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/454</guid>
      <pubDate>Sat, 06 Jun 2026 00:25:04 +0800</pubDate>
    </item>
    <item>
      <title>OpenClaw 2026.6.1 发布：更强的韧性、更稳的渠道与全新的 Skill Workshop</title>
      <link>https://gooseforum.online/p/post/452</link>
      <description>原文 ：https://github.com/openclaw/openclaw/releases/tag/v2026.6 发布时间 ：2026 年 6 OpenClaw 最新版本 2026.6.1 已经上线。这一次更新没有 headline-grabbing 的「新功能」，但 每一个改进都精准地打在运行时的痛点上 ——从代理恢复、渠道稳定性，到 Skill Workshop 的完整工作流，再到数...</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>原文</strong>：https://github.com/openclaw/openclaw/releases/tag/v2026.6.1<br/>
<strong>发布时间</strong>：2026 年 6 月</p>
</blockquote>
<p>OpenClaw 最新版本 <strong>2026.6.1</strong> 已经上线。这一次更新没有 headline-grabbing 的「新功能」，但<strong>每一个改进都精准地打在运行时的痛点上</strong>——从代理恢复、渠道稳定性，到 Skill Workshop 的完整工作流，再到数十项边界情况的安全加固。对于把 OpenClaw 当作日常基础设施的用户来说，这是一次值得认真升级的版本。</p>
<hr/>
<h2 id="一-核心改进-运行时更-抗揍">一、核心改进：运行时更「抗揍」</h2>
<h3 id="1-代理与-cli-运行时的故障恢复">1. 代理与 CLI 运行时的故障恢复</h3>
<ul>
<li>
<p>被打断的工具调用、过期的会话绑定、压缩交接（compaction handoff）以及媒体重试，现在都能<strong>更干净地恢复</strong>而不会留下脏状态。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88129" target="_blank" rel="nofollow ugc noopener noreferrer">#88129</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88136" target="_blank" rel="nofollow ugc noopener noreferrer">#88136</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88141" target="_blank" rel="nofollow ugc noopener noreferrer">#88141</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88162" target="_blank" rel="nofollow ugc noopener noreferrer">#88162</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88182" target="_blank" rel="nofollow ugc noopener noreferrer">#88182</a></p>
</li>
<li>
<p>Codex 运行时修复了包括：直播会话锁、CLI 工具转录恢复、ACP 元数据持久化、真实工具结果优先于合成修复输出、以及被中止的 app-server 句柄清理。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fissues%2F88405" target="_blank" rel="nofollow ugc noopener noreferrer">#88405</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88724" target="_blank" rel="nofollow ugc noopener noreferrer">#88724</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88730" target="_blank" rel="nofollow ugc noopener noreferrer">#88730</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fvincentkoc" target="_blank" rel="nofollow ugc noopener noreferrer">@vincentkoc</a></p>
</li>
</ul>
<h3 id="2-渠道与移动推送的稳定性">2. 渠道与移动推送的稳定性</h3>
<ul>
<li>
<p>Telegram、WhatsApp、iMessage、Slack、Discord、Microsoft Teams、Google Chat、Google Meet 和 iOS 实时 Talk 的<strong>请求/重试计时器全面加帽</strong>，减少因超时无限挂起导致的「消息发不出去」或「会话假死」。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88096" target="_blank" rel="nofollow ugc noopener noreferrer">#88096</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88105" target="_blank" rel="nofollow ugc noopener noreferrer">#88105</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88183" target="_blank" rel="nofollow ugc noopener noreferrer">#88183</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88231" target="_blank" rel="nofollow ugc noopener noreferrer">#88231</a></p>
</li>
<li>
<p>WhatsApp QR 登录的 <code>408</code> 超时现在会自动重试。</p>
</li>
<li>
<p>iOS 支持了原生 iPad 布局，并新增托管推送中继（hosted push relay）和更可靠的 WebSocket ping 路径。</p>
</li>
</ul>
<h3 id="3-请求与下载的边界防护">3. 请求与下载的边界防护</h3>
<ul>
<li>对 provider 和 plugin 的<strong>计时器、重试、OAuth/设备码生命周期、媒体下载、本地服务探测、生成内容轮询</strong>等路径，全面增加了上限保护，防止单个任务「hang 住」整个运行。</li>
<li>覆盖范围包括 OpenAI、Runway、xAI、MiniMax、BytePlus、DashScope、FAL、OpenRouter、Google、Vydra、Comfy 等 provider 的生成媒体下载。</li>
</ul>
<hr/>
<h2 id="二-新功能-skill-workshop-正式可用">二、新功能：Skill Workshop 正式可用</h2>
<p>Skill Workshop 不再只是概念，现在拥有<strong>完整的 Control UI 工作流</strong>：</p>
<ul>
<li><strong>提案列表</strong>：查看待审核的 Skill 提案，支持今日视图和看板视图切换。</li>
<li><strong>可修订</strong>：在审批前可以就地修订提案，带有版本化的日期 frontmatter。</li>
<li><strong>支持文件</strong>：提案可以携带经扫描、哈希校验和回滚保护的支持文件。</li>
<li><strong>审核操作</strong>：通过 CLI 或 Gateway 对提案执行 <strong>apply、reject、quarantine</strong>。</li>
<li><strong>文件预览</strong>：可搜索的文件预览模态框，配合会话交接功能。</li>
<li><strong>多语言</strong>：完整的 locale 覆盖。</li>
</ul>
<p>相关文档与实现：</p>
<ul>
<li><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88734" target="_blank" rel="nofollow ugc noopener noreferrer">Skill Workshop 官方指南</a> —— 涵盖治理式 Skill 创建、可审核提案、CLI/Gateway 操作、审批策略与恢复。
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fshakkernerd" target="_blank" rel="nofollow ugc noopener noreferrer">@shakkernerd</a> 和 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fvyctorbrzezowski" target="_blank" rel="nofollow ugc noopener noreferrer">@vyctorbrzezowski</a></li>
<li>核心 Skill 索引与运行时加载统一：Skill 的加载、状态、过滤和 prompt 格式化现在集中管理。</li>
<li>Codex app-server 的 prompt 中现在会注入 Skill Workshop 指引，当 <code>skill_workshop</code> 可用时自动生效。</li>
</ul>
<hr/>
<h2 id="三-workboard-与编排能力">三、Workboard 与编排能力</h2>
<ul>
<li><strong>Workboard</strong>：新增多代理规划与运行跟踪的编排原语（orchestration primitives）和代理协调工具。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F87469" target="_blank" rel="nofollow ugc noopener noreferrer">#87469</a></li>
<li>任务驱动的看板运行（task-backed board runs）和任务评论在编辑模态框中展示。</li>
<li><strong>SecretRef 插件清单</strong>：提供 provider 集成清单契约，并提取共享的 LLM 核心包供 provider/plugin 复用。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F82326" target="_blank" rel="nofollow ugc noopener noreferrer">#82326</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88117" target="_blank" rel="nofollow ugc noopener noreferrer">#88117</a></li>
</ul>
<hr/>
<h2 id="四-插件与-provider-生态更新">四、插件与 Provider 生态更新</h2>
<h3 id="官方插件独立发布">官方插件独立发布</h3>
<ul>
<li><strong>Tokenjuice</strong> 作为官方 <code>@openclaw/tokenjuice</code> 插件独立发布，支持 npm 和 ClawHub 安装。</li>
<li><strong>GitHub Copilot</strong> 作为官方 <code>@openclaw/copilot</code> 插件独立发布，同样支持 npm 和 ClawHub。</li>
</ul>
<h3 id="provider-支持扩展">Provider 支持扩展</h3>
<ul>
<li><strong>MiniMax M3</strong> 模型正式支持。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88860" target="_blank" rel="nofollow ugc noopener noreferrer">#88860</a></li>
<li>Google 默认解析到 <code>google-generative-ai</code>，Vertex 静态目录行修复。</li>
<li>OpenRouter 增加 SQLite 模型缓存。</li>
<li>Copilot Claude 1M 上下文能力保留。</li>
<li>Foundry 推理元数据对齐，DeepSeek V4 thinking 参数在 Foundry fallback 时跳过。</li>
<li>OpenAI 响应回放（replay）防护，避免 disabled Responses store 时仍携带 replay id。</li>
</ul>
<hr/>
<h2 id="五-性能与状态持久化">五、性能与状态持久化</h2>
<ul>
<li><strong>SQLite 迁移</strong>：iMessage 监控状态、入站队列、插件安装索引全面迁移到 SQLite，重启和本地监控恢复时减少重复文件扫描。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88794" target="_blank" rel="nofollow ugc noopener noreferrer">#88794</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88797" target="_blank" rel="nofollow ugc noopener noreferrer">#88797</a></li>
<li><strong>内存优化</strong>：QMD 更新/嵌入写入按 store 串行化、Linux 文件监听 fan-out 减少、临时文件读取重试、元数据清理、Linux 原生 watcher 在目录重建后自动重连。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F89185" target="_blank" rel="nofollow ugc noopener noreferrer">#89185</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F89188" target="_blank" rel="nofollow ugc noopener noreferrer">#89188</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F85351" target="_blank" rel="nofollow ugc noopener noreferrer">#85351</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2FRomneyDa" target="_blank" rel="nofollow ugc noopener noreferrer">@RomneyDa</a> 和 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2FNianJiuZst" target="_blank" rel="nofollow ugc noopener noreferrer">@NianJiuZst</a></li>
</ul>
<hr/>
<h2 id="六-control-ui-与聊天体验">六、Control UI 与聊天体验</h2>
<ul>
<li><strong>Dreaming 标签</strong>：新增代理选择器，支持在 Dreaming 状态、日记和日记动作中传播所选代理。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F78748" target="_blank" rel="nofollow ugc noopener noreferrer">#78748</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fstevenepalmer" target="_blank" rel="nofollow ugc noopener noreferrer">@stevenepalmer</a></li>
<li><strong>Composer 体验</strong>：聊天 composer 控件更克制（calmer），本地草稿在输入时保持本地状态，发送后自动清空。流式增量渲染跳过 markdown 工作，首输出延迟（first-output latency）可追踪。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88772" target="_blank" rel="nofollow ugc noopener noreferrer">#88772</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88825" target="_blank" rel="nofollow ugc noopener noreferrer">#88825</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88998" target="_blank" rel="nofollow ugc noopener noreferrer">#88998</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F89030" target="_blank" rel="nofollow ugc noopener noreferrer">#89030</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F89106" target="_blank" rel="nofollow ugc noopener noreferrer">#89106</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fvincentkoc" target="_blank" rel="nofollow ugc noopener noreferrer">@vincentkoc</a> 和 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fsallyom" target="_blank" rel="nofollow ugc noopener noreferrer">@sallyom</a></li>
<li><strong>错误可见</strong>：Gateway 聊天失败现在在 Control UI 中显示为可见的助理消息，而非不可见的错误状态。</li>
<li><strong>工具卡片</strong>：折叠的工具卡片现在显示工具名称和动作，而非通用的输出文本。
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fshakkernerd" target="_blank" rel="nofollow ugc noopener noreferrer">@shakkernerd</a></li>
</ul>
<hr/>
<h2 id="七-ci-发布与诊断">七、CI、发布与诊断</h2>
<ul>
<li>发布候选读取、Beta smoke REST 调用、插件 npm 验证、变更日志恢复、跨 OS 进程组、Kitchen Sink 就绪探测、Telegram 凭证超时、Control UI i18n 生成、Vitest 路由等<strong>全面加帽</strong>。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88127" target="_blank" rel="nofollow ugc noopener noreferrer">#88127</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88137" target="_blank" rel="nofollow ugc noopener noreferrer">#88137</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88155" target="_blank" rel="nofollow ugc noopener noreferrer">#88155</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88160" target="_blank" rel="nofollow ugc noopener noreferrer">#88160</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88966" target="_blank" rel="nofollow ugc noopener noreferrer">#88966</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2FRomneyDa" target="_blank" rel="nofollow ugc noopener noreferrer">@RomneyDa</a></li>
<li>磁盘空间健康检查加入 Doctor 工具。</li>
<li>更新流程：当缺失的外部插件修复下载卡住时，核心更新保持非阻塞；但已安装活跃插件的 payload smoke 失败仍会阻塞。</li>
<li>插件安装失败时提供<strong>更清晰的修复路径指引</strong>。</li>
</ul>
<hr/>
<h2 id="八-值得关注的修复">八、值得关注的修复</h2>
<ul>
<li><strong>CLI</strong>：<code>openclaw agents add</code> 不再强制实时验证 provider 目录，添加辅助代理不再依赖目录可用性。
相关 Issue/PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fissues%2F76284" target="_blank" rel="nofollow ugc noopener noreferrer">#76284</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88314" target="_blank" rel="nofollow ugc noopener noreferrer">#88314</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fzhangguiping-xydt" target="_blank" rel="nofollow ugc noopener noreferrer">@zhangguiping-xydt</a></li>
<li><strong>WSL 剪贴板</strong>：通过 shell 桥接 WSL 剪贴板操作。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88764" target="_blank" rel="nofollow ugc noopener noreferrer">#88764</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88689" target="_blank" rel="nofollow ugc noopener noreferrer">#88689</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Falexzhu0" target="_blank" rel="nofollow ugc noopener noreferrer">@alexzhu0</a></li>
<li><strong>Cron</strong>：SQLite cron 迁移兼容旧版运行日志表、归档作业存储、诊断 cron 名称和旧版一次性 delete-after-run 行为。
相关 PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F88285" target="_blank" rel="nofollow ugc noopener noreferrer">#88285</a></li>
<li><strong>Skills</strong>：跳过来自过时持久化快照的禁用 Skill 环境覆盖，防止禁用 Skill 的 <code>apiKey</code> SecretRefs 中止嵌入或渠道回合。
相关 Issue/PR：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fissues%2F79072" target="_blank" rel="nofollow ugc noopener noreferrer">#79072</a>、<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F79173" target="_blank" rel="nofollow ugc noopener noreferrer">#79173</a>
感谢 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fzeus1959" target="_blank" rel="nofollow ugc noopener noreferrer">@zeus1959</a></li>
</ul>
<hr/>
<h2 id="总结">总结</h2>
<p>OpenClaw 2026.6.1 的改进关键词是 <strong>「韧性」</strong> 和 <strong>「治理」</strong>：</p>
<ul>
<li><strong>韧性</strong>：代理恢复、渠道超时、媒体下载、生成内容轮询等边界情况全面加固，系统更难被「一个异常任务」拖垮。</li>
<li><strong>治理</strong>：Skill Workshop 从概念变为完整可用的审核工作流，配合 SecretRef 清单和插件独立发布，生态治理更加规范。</li>
<li><strong>体验</strong>：Control UI 的聊天 composer、Dreaming 标签、错误可见性等改进，让日常交互更顺畅。</li>
</ul>
<p>如果你正在运行 OpenClaw 作为基础设施，这个版本值得优先升级。</p>
<blockquote>
<p>完整变更列表与 PR 链接：
<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Ftag%2Fv2026.6.1" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/openclaw/releases/tag/v2026.6.1</a></p>
</blockquote>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/452</guid>
      <pubDate>Thu, 04 Jun 2026 09:38:10 +0800</pubDate>
    </item>
    <item>
      <title>大佬前后端都是自己写的么</title>
      <link>https://gooseforum.online/p/post/450</link>
      <description>感觉好厉害啊</description>
      <content:encoded><![CDATA[<p>感觉好厉害啊</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/450</guid>
      <pubDate>Wed, 03 Jun 2026 10:10:54 +0800</pubDate>
    </item>
    <item>
      <title>浪费大家硬盘了～后面会打包体积更加小的版本发布</title>
      <link>https://gooseforum.online/p/post/434</link>
      <description>优化后 优化前</description>
      <content:encoded><![CDATA[<p>优化后
<img src="/file/img/2026/05/21/5bdf4f1b-d1d4-4ce5-bc1e-1e311fad1719.webp" alt="image" loading="lazy" decoding="async"/>
优化前
<img src="/file/img/2026/05/21/5cfe028a-1a3d-43d4-bbdf-fe412acd6e7d.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/434</guid>
      <pubDate>Thu, 21 May 2026 11:23:48 +0800</pubDate>
    </item>
    <item>
      <title>今天又来视察，看有没有偷懒</title>
      <link>https://gooseforum.online/p/post/449</link>
      <description>今天来视察，看看大佬有没有偷懒，结果很失望今天没有更新，来人大刑伺候</description>
      <content:encoded><![CDATA[<p>今天来视察，看看大佬有没有偷懒，结果很失望今天没有更新，来人大刑伺候</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/449</guid>
      <pubDate>Tue, 02 Jun 2026 12:46:00 +0800</pubDate>
    </item>
    <item>
      <title>关于 Mobile 显示效果优化建议征询</title>
      <link>https://gooseforum.online/p/post/448</link>
      <description>当前移动端相关展示区域类似卡片的展示形式，会导致空间利用率有限就是图一，现在寻求一下大家判断，1好一点还是2好一点 减少四周留白</description>
      <content:encoded><![CDATA[<p>当前移动端相关展示区域类似卡片的展示形式，会导致空间利用率有限就是图一，现在寻求一下大家判断，1好一点还是2好一点</p>
<p><img src="/file/img/2026/06/01/972d29b0-3148-4803-8b52-cf4d76f7c1d4.webp" alt="image" loading="lazy" decoding="async"/></p>
<p>减少四周留白
<img src="/file/img/2026/06/01/826e8f77-b1bb-4d09-82ab-829495563011.webp" alt="image" loading="lazy" decoding="async"/></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/448</guid>
      <pubDate>Mon, 01 Jun 2026 18:20:08 +0800</pubDate>
    </item>
    <item>
      <title>每天来看下</title>
      <link>https://gooseforum.online/p/post/447</link>
      <description>哈哈哈，每天来看一下大佬更新了什么，好像没有更新日志呀，不专业，一点都不专业，偷偷更新，都不知道更新啥了</description>
      <content:encoded><![CDATA[<p>哈哈哈，每天来看一下大佬更新了什么，好像没有更新日志呀，不专业，一点都不专业，偷偷更新，都不知道更新啥了</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/447</guid>
      <pubDate>Sun, 31 May 2026 12:50:16 +0800</pubDate>
    </item>
    <item>
      <title>OpenClaw v2026.5.28 发布：Agent 更稳定、交付更安全、移动端全面刷新</title>
      <link>https://gooseforum.online/p/post/446</link>
      <description>发布日期： 2026-05 标签： v2026.5.28 核心亮点 🧠 Agent 运行时更稳定 子代理保持 cwd/工作空间隔离 钩子上下文保持 prompt -local 超时中止时释放会话锁，避免过时的重启续传 Codex 应用服务器/辅助器故障不再摧毁共享运行时状态 🔐 渠道交付和会话身份更安全 覆盖出站插件钩子、Matrix 房间 iMessage 反应/批准、Slack 最终回复、Di...</description>
      <content:encoded><![CDATA[<p><strong>发布日期：</strong> 2026-05-30<br/>
<strong>标签：</strong> <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Ftag%2Fv2026.5.28" target="_blank" rel="nofollow ugc noopener noreferrer">v2026.5.28</a></p>
<hr/>
<h2 id="核心亮点">核心亮点</h2>
<h3 id="agent-运行时更稳定">🧠 Agent 运行时更稳定</h3>
<ul>
<li>子代理保持 cwd/工作空间隔离</li>
<li>钩子上下文保持 prompt-local</li>
<li>超时中止时释放会话锁，避免过时的重启续传</li>
<li>Codex 应用服务器/辅助器故障不再摧毁共享运行时状态</li>
</ul>
<h3 id="渠道交付和会话身份更安全">🔐 渠道交付和会话身份更安全</h3>
<ul>
<li>覆盖出站插件钩子、Matrix 房间 ID</li>
<li>iMessage 反应/批准、Slack 最终回复、Discord 恢复工具警告</li>
<li>运行时配置消息操作、WhatsApp 个人资料认证根</li>
<li>Telegram 轮询、Microsoft Teams 服务 URL 信任检查</li>
</ul>
<h3 id="移动端和聊天界面刷新">📱 移动端和聊天界面刷新</h3>
<ul>
<li>iOS Pro UI 全面刷新</li>
<li>托管推送中继默认设置</li>
<li>实时 Talk 标签播放</li>
<li>Gateway 聊天传输、引导、Talk 权限</li>
<li>WebChat 重新连接交付、会话选择器行为优化</li>
</ul>
<h3 id="输入验证更严格">🛡️ 输入验证更严格</h3>
<ul>
<li>浏览器工具超时、视口/标签索引、Gateway 端口</li>
<li>cron 重试处理、Discord 组件 ID</li>
<li>模式数组引用、Telegram 回调页面、渠道进度回调等现在更早拒绝畸形值</li>
</ul>
<h3 id="模型和媒体覆盖扩展">🤖 模型和媒体覆盖扩展</h3>
<ul>
<li>Claude Opus 4.8、Fal Krea 图像模型</li>
<li>NVIDIA 精选模型、MiniMax 流媒体音乐响应</li>
<li>加密 PDF 提取、语音模型目录</li>
<li>GitHub Copilot 代理运行时、Codex Supervisor 插件</li>
</ul>
<h3 id="cli-认证-诊断更可靠">🔧 CLI / 认证 / 诊断更可靠</h3>
<ul>
<li>畸形数字/版本选项被拒绝</li>
<li>工作区 dotenv 提供商凭据被忽略</li>
<li>OAuth/令牌生命周期和本地服务启动请求被限制</li>
<li>代理认证健康标签更清晰</li>
<li>旧版 <code>api_key</code> 认证配置文件迁移到规范形式</li>
</ul>
<hr/>
<h2 id="主要变更">主要变更</h2>
<h3 id="状态与子代理">状态与子代理</h3>
<ul>
<li>在状态输出中显示活动子代理详情</li>
</ul>
<h3 id="diffs-与语言包">Diffs 与语言包</h3>
<ul>
<li>拆分默认语言包并扩展默认 Diffs 语言覆盖</li>
</ul>
<h3 id="clawhub-插件市场">ClawHub 插件市场</h3>
<ul>
<li>添加插件显示名称</li>
<li>技能验证和信任界面</li>
</ul>
<h3 id="ios-移动端">iOS 移动端</h3>
<ul>
<li>刷新开发应用</li>
<li>支持 Pro Command、Chat、Agents、Settings</li>
<li>托管推送中继默认设置</li>
<li>实时 Talk 播放</li>
</ul>
<h3 id="文档更新">文档更新</h3>
<ul>
<li>澄清 Codex 计算机使用设置</li>
<li>粘贴令牌 stdin 认证设置</li>
<li>macOS Gateway 睡眠故障排除</li>
<li>原生 Codex 钩子中继恢复</li>
<li>容器模型认证等</li>
</ul>
<h3 id="pdf-与工具链">PDF 与工具链</h3>
<ul>
<li>使用 ClawPDF 进行 PDF 提取</li>
<li>支持加密 PDF 提取</li>
<li>在代理工具结果中显示 MCP 结构化内容</li>
</ul>
<h3 id="新模型与提供商支持">新模型与提供商支持</h3>
<ul>
<li>Claude Opus 4.8</li>
<li>Fal Krea 图像模型</li>
<li>NVIDIA 精选模型目录</li>
<li>MiniMax 流媒体音乐</li>
<li>提供商支持的语音模型目录</li>
</ul>
<h3 id="github-copilot-与-codex">GitHub Copilot 与 Codex</h3>
<ul>
<li>添加 GitHub Copilot 代理运行时</li>
<li>Codex Supervisor 插件包</li>
</ul>
<h3 id="插件架构">插件架构</h3>
<ul>
<li>将 GitHub Copilot 和 Tokenjuice 外部化为官方按需安装插件</li>
</ul>
<h3 id="workboard-代理协调">Workboard 代理协调</h3>
<ul>
<li>添加代理协调工具，用于跟踪和移交活动代理工作</li>
</ul>
<h3 id="discord-集成">Discord 集成</h3>
<ul>
<li>在进度草稿中显示评论，以便实时 Discord 运行展示有用的进行中上下文</li>
</ul>
<h3 id="插件-sdk">插件 SDK</h3>
<ul>
<li>添加回复负载发送钩子</li>
<li>SDK 声明扁平化包类型</li>
</ul>
<h3 id="策略与合规">策略与合规</h3>
<ul>
<li>添加策略比较</li>
<li>入站渠道合规性检查</li>
<li>沙箱姿态合规性检查</li>
</ul>
<hr/>
<h2 id="下载与验证">下载与验证</h2>
<h3 id="macos">macOS</h3>
<table>
<thead>
<tr>
<th>文件</th>
<th>大小</th>
<th>下载</th>
</tr>
</thead>
<tbody>
<tr>
<td>OpenClaw-2026.5.28.dmg</td>
<td>40.6 MB</td>
<td><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.28%2FOpenClaw-2026.5.28.dmg" target="_blank" rel="nofollow ugc noopener noreferrer">下载</a></td>
</tr>
<tr>
<td>OpenClaw-2026.5.28.zip</td>
<td>54.8 MB</td>
<td><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.28%2FOpenClaw-2026.5.28.zip" target="_blank" rel="nofollow ugc noopener noreferrer">下载</a></td>
</tr>
<tr>
<td>OpenClaw-2026.5.28.dSYM.zip</td>
<td>38.5 MB</td>
<td><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.28%2FOpenClaw-2026.5.28.dSYM.zip" target="_blank" rel="nofollow ugc noopener noreferrer">下载</a></td>
</tr>
</tbody>
</table>
<h3 id="npm">npm</h3>
<pre><code class="language-bash">npm install -g openclaw@2026.5.28
</code></pre>
<ul>
<li>npm 包页面：<a href="/outbound?url=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fopenclaw%2Fv%2F2026.5.28" target="_blank" rel="nofollow ugc noopener noreferrer">https://www.npmjs.com/package/openclaw/v/2026.5.28</a></li>
<li>registry tarball：<a href="/outbound?url=https%3A%2F%2Fregistry.npmjs.org%2Fopenclaw%2F-%2Fopenclaw-2026.5.28.tgz" target="_blank" rel="nofollow ugc noopener noreferrer">https://registry.npmjs.org/openclaw/-/openclaw-2026.5.28.tgz</a></li>
<li>完整性：<code>sha512-p7jGN9wzCrqEvHNI6Y7+eh6DWoYDzJ1iQGKTm8xqQ2uQ9/2mY1CCf87WoZeb0+m3eHKSGchlI3tN33fE1lMtEA==</code></li>
</ul>
<h3 id="依赖证据">依赖证据</h3>
<ul>
<li><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.28%2Fopenclaw-2026.5.28-dependency-evidence.zip" target="_blank" rel="nofollow ugc noopener noreferrer">openclaw-2026.5.28-dependency-evidence.zip</a> (60.4 KB)</li>
</ul>
<hr/>
<h2 id="发布验证">发布验证</h2>
<ul>
<li>npm preflight：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Factions%2Fruns%2F26692293231" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/openclaw/actions/runs/26692293231</a></li>
<li>完整发布验证：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Factions%2Fruns%2F26692292739" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/openclaw/actions/runs/26692292739</a></li>
<li>发布检查：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Factions%2Fruns%2F26692419552" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/openclaw/actions/runs/26692419552</a></li>
<li>npm Telegram 包 E2E：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Factions%2Fruns%2F26692496669" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/openclaw/actions/runs/26692496669</a></li>
<li>macOS 预检/签名/公证：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Freleases%2Factions%2Fruns%2F26694473893" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/releases/actions/runs/26694473893</a></li>
<li>macOS 验证：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Freleases%2Factions%2Fruns%2F26695381614" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/releases/actions/runs/26695381614</a></li>
<li>macOS 发布/appcast：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Freleases%2Factions%2Fruns%2F26695523506" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/releases/actions/runs/26695523506</a></li>
</ul>
<p>appcast 订阅：<a href="/outbound?url=https%3A%2F%2Fraw.githubusercontent.com%2Fopenclaw%2Fopenclaw%2Fmain%2Fappcast.xml" target="_blank" rel="nofollow ugc noopener noreferrer">https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</a></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/446</guid>
      <pubDate>Sun, 31 May 2026 11:40:06 +0800</pubDate>
    </item>
    <item>
      <title>部署有没有内存限制</title>
      <link>https://gooseforum.online/p/post/443</link>
      <description>1h1g可以呀玩不，有没有限制，大佬用的什么配置服务器说说呗</description>
      <content:encoded><![CDATA[<p>1h1g可以呀玩不，有没有限制，大佬用的什么配置服务器说说呗</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/443</guid>
      <pubDate>Thu, 28 May 2026 14:05:49 +0800</pubDate>
    </item>
    <item>
      <title>不错不错 越来越好了</title>
      <link>https://gooseforum.online/p/post/445</link>
      <description>喜欢这种极简风 加油干</description>
      <content:encoded><![CDATA[<p>喜欢这种极简风 加油干</p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/445</guid>
      <pubDate>Fri, 29 May 2026 20:39:01 +0800</pubDate>
    </item>
    <item>
      <title>OpenClaw 2026.5.27 Release 报告</title>
      <link>https://gooseforum.online/p/post/444</link>
      <description>发布时间： 2026-05-28 19:41 (CST) 标签： v2026.5.27 | 正式版本 | 非预发布 核心亮点 安全性升级 — 群组提示文本从系统提示中隔离、重复点主机名规范化、阻止有副作用的命令包装器、拒绝不安全的 Node 运行时环境覆盖、禁止无认证 Tailscale 暴露，节点/设备角色审批现需管理员权限。（#87144, #87305, #87292, #87308, #8...</description>
      <content:encoded><![CDATA[<p><strong>发布时间：</strong> 2026-05-28 19:41 (CST)</p>
<p><strong>标签：</strong> <code>v2026.5.27</code> | 正式版本 | 非预发布</p>
<hr/>
<h3 id="核心亮点">核心亮点</h3>
<ul>
<li>
<p><strong>安全性升级</strong> — 群组提示文本从系统提示中隔离、重复点主机名规范化、阻止有副作用的命令包装器、拒绝不安全的 Node 运行时环境覆盖、禁止无认证 Tailscale 暴露，节点/设备角色审批现需管理员权限。（#87144, #87305, #87292, #87308, #87146）</p>
</li>
<li>
<p><strong>Codex 运行时更稳</strong> — 运行时模型优先解析、工作区内存通过工具路由、共享应用服务器客户端在启动和辅助进程故障后存活、原生 Hook 中继生成在重启和回退时保持、避免错误的运行时实时切换。（#87383, #87403, #87375, #72574, #87428）</p>
</li>
<li>
<p><strong>网关和回复路径加速</strong> — 会话读取、插件元数据指纹、认证环境快照、自动启用插件配置、工具搜索目录等减少热路径重新发现，可见回复不再继承隐藏清理超时。（#86439, #87044）</p>
</li>
<li>
<p><strong>更多提供商和模型支持</strong> — OpenAI 兼容嵌入提供商成为核心、DeepInfra 目录浏览加载完整凭证感知模型集、Pixverse 新增视频生成和 API 区域选择、VLLM 思考参数接入、Claude CLI OAuth 覆盖层支持 PI 认证配置文件、裸 Anthropic 模型 ID 直接可用。（#85269, #84549, #87167）</p>
</li>
<li>
<p><strong>通道投递更稳</strong> — Telegram <code>sendMessage</code> 使用持久出站投递、iMessage 抑制重复原生执行审批提示和发送、Slack 在延迟清理期间保留最终回复、Matrix 提及预览/终稿更严格、QQBot 回退审批按钮遵循斜杠命令认证、Discord 公会请求检查更紧、Google Chat 在 DM 中停止线程发送。（#87261, #87154）</p>
</li>
</ul>
<hr/>
<h3 id="主要变更">主要变更</h3>
<ul>
<li><strong>内存：</strong> 新增核心 OpenAI 兼容嵌入提供商，支持本地和托管的 OpenAI 风格端点，含配置、诊断和文档支持。（#85269）</li>
<li><strong>插件 SDK：</strong> 标记内存专用嵌入提供商注册为已弃用兼容性，并在插件兼容性诊断中显示非捆绑使用。（#85072）</li>
<li><strong>提供商：</strong> 新增 Pixverse 视频生成提供商、API 区域选择、文档和外部插件打包支持。</li>
<li><strong>DeepInfra：</strong> 用户在引导期间浏览模型时加载完整模型目录，保留配置的 API 密钥目录，刷新媒体/视频默认值，保持价格/默认模型元数据对齐。（#84549）</li>
<li><strong>插件 SDK：</strong> 公开插件审批操作元数据，停止从公共 SDK 表面导出 Vitest 测试助手。（#87120）</li>
<li><strong>通道 SDK：</strong> 将通道消息兼容性移入核心，移除旧通道回合运行时别名，保留插件的运行时目录 Markdown 元数据。</li>
<li><strong>ClawHub：</strong> 添加插件显示元数据，使目录/包列表使用更简洁的名称。（#87354）</li>
<li><strong>代理：</strong> 将心跳运行时模板从文档资源中拆分，并为旧版心跳模板内容添加兼容性修复。（#85416）</li>
</ul>
<hr/>
<h3 id="修复汇总">修复汇总</h3>
<ul>
<li><strong>安全/内容边界</strong>（9 项）— 系统提示外路由不信任群组提示、规范化重复尾部主机名点、阻止有副作用的命令包装器、拒绝不安全 Node 运行时环境覆盖、拒绝无认证 Tailscale 暴露、阻止不信任 Microsoft Teams 服务 URL、强制 <code>/allowlist configWrites</code> 来源策略、门控 QQBot 回退审批按钮、要求管理员进行节点/设备角色审批。</li>
<li><strong>Codex</strong>（9 项）— 运行时模型优先解析、工作区内存通过工具路由、保留共享应用服务器客户端、保留原生 Hook 中继生成、保持原始推理/源回复保护完整、报告隔离动态工具、保持尝试看门狗在排队终端回合时启用、Codex OAuth 压缩通过 OpenAI-Codex 路由。</li>
<li><strong>代理/运行时</strong>（12 项）— 避免会话事件队列自等待、限制压缩唤醒和引导重试、保留待处理错误诊断的优雅、避免错误的 Codex 运行时实时切换、避免陈旧的重启继续重用、保留会话回退错误、抑制重复的 Claude CLI 技能提示、保持活动用户回合前的运行时上下文、剥离陈旧的 Anthropic 思考、隔离不受支持的工具模式、安全恢复已完成的写入超时、超时中止时释放保留的会话写入锁。</li>
<li><strong>回复/会话投递</strong>（5 项）— 保持可见回合准入无界、在最新目标上保留可见回退投递、保留桥接 Hook 上下文、按通道语法分类直接回退目标、在桥接模式下报告审批决议。</li>
<li><strong>通道</strong>（7 项）— Telegram <code>sendMessage</code> 操作回复持久化、抑制 iMessage 重复原生执行审批提示和发送、保持 iMessage 审批轮询在拒绝反应后存活、Slack 保留延迟清理期间的最终回复、Matrix 提及预览/终稿不提及且正常投递、忽略嵌入文件名的 Matrix ID、抑制成功回复中恢复的 Discord 工具警告伪影、抑制 Google Chat DM 中的线程发送。</li>
<li><strong>内存</strong>（2 项）— 在非常退出后恢复 QMD 搜索 JSON，尽可能通过 Codex 工具路径保持工作区内存路由。</li>
<li><strong>提供商/模型</strong>（9 项）— 在 OpenAI 兼容聊天完成中转发缓存令牌使用、为 PI 认证配置文件加载 Claude CLI OAuth 覆盖层、发送裸直接 Anthropic 模型 ID、连接配置的 VLLM 思考参数、尊重 OpenAI 兼容缓存保留、规范化 OpenAI 响应重放工具 ID、在没有缓存目录的情况下解析 OpenAI <code>gpt-5.5</code>、保留 <code>retry-after</code> 回退处理、限制 GitHub Copilot 认证请求。</li>
<li><strong>网关/性能</strong>（8 项）— 借用只读会话元数据和活动会话工作区存储、缓存当前/稳定插件元数据指纹、缓存自动启用插件配置、精简元数据身份缓存、信任当前元数据生命周期缓存、稳定隔离 cron 提示缓存亲和性、持久化模型认证配置文件后缀、排空探测客户端关闭。</li>
<li><strong>CLI/帮助/配置</strong>（5 项）— 拒绝松散或畸形的数字选项（网关超时、模型限制、目录限制、消息选项、Webhook、部分值）、尊重子命令版本选项、正确路由生成/根/插件帮助目标、保持技能 JSON 输出自然刷新、在根帮助中保持插件描述符加载安静。</li>
<li><strong>插件状态/工具搜索</strong>（4 项）— 插件行达到上限时驱逐当前命名空间、重用未更改的工具搜索目录、对齐发布目录重用包装器、保持回退工具警告不提及。</li>
<li><strong>安装/包/发布</strong>（8 项）— 匹配 npm globstar 排除、在清单中尊重 dist 包排除、省略解包的测试助手、跳过 Homebrew 直到 macOS 包需要它、打包 Docker 运行时工作区模板、在完整验证期间对 Docker 运行时模板进行冒烟测试、合并嵌套 shrinkwrap 覆盖引脚、保留分支 shrinkwrap 引脚。</li>
<li><strong>E2E/QA/Crabbox</strong>（10 项）— 限制 Telegram、Open WebUI、ClawHub、Matrix、工具搜索、MCP、网关网络、捆绑运行时、厨房水槽、Codex 媒体、配置重载和代理回合断言等待；Windows 目标优先选择 Azure；重新初始化无效更改门 git 目录；完整同步稀疏容器运行；空显式测试请求失败。</li>
</ul>
<hr/>
<h3 id="下载资源">下载资源</h3>
<table>
<thead>
<tr>
<th>资源</th>
<th>大小</th>
<th>下载</th>
</tr>
</thead>
<tbody>
<tr>
<td>macOS DMG</td>
<td>37.9 MB</td>
<td><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.27%2FOpenClaw-2026.5.27.dmg" target="_blank" rel="nofollow ugc noopener noreferrer">OpenClaw-2026.5.27.dmg</a></td>
</tr>
<tr>
<td>macOS ZIP</td>
<td>52.0 MB</td>
<td><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.27%2FOpenClaw-2026.5.27.zip" target="_blank" rel="nofollow ugc noopener noreferrer">OpenClaw-2026.5.27.zip</a></td>
</tr>
<tr>
<td>macOS dSYM</td>
<td>36.6 MB</td>
<td><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.27%2FOpenClaw-2026.5.27.dSYM.zip" target="_blank" rel="nofollow ugc noopener noreferrer">OpenClaw-2026.5.27.dSYM.zip</a></td>
</tr>
<tr>
<td>依赖证据</td>
<td>58.2 KB</td>
<td><a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Fdownload%2Fv2026.5.27%2Fopenclaw-2026.5.27-dependency-evidence.zip" target="_blank" rel="nofollow ugc noopener noreferrer">dependency-evidence.zip</a></td>
</tr>
</tbody>
</table>
<ul>
<li>npm 包：<code>openclaw@2026.5.27</code> — <a href="/outbound?url=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fopenclaw%2Fv%2F2026.5.27" target="_blank" rel="nofollow ugc noopener noreferrer">registry</a></li>
<li>完整发布 CI 报告：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Freleases%2Fblob%2Fmain%2Fevidence%2F2026.5.27%2Frelease-evidence.md" target="_blank" rel="nofollow ugc noopener noreferrer">evidence/2026.5.27/release-evidence.md</a></li>
<li>appcast：<a href="/outbound?url=https%3A%2F%2Fraw.githubusercontent.com%2Fopenclaw%2Fopenclaw%2Fmain%2Fappcast.xml" target="_blank" rel="nofollow ugc noopener noreferrer">appcast.xml</a></li>
</ul>
<hr/>
<p><strong>GitHub Release：</strong> <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Ftag%2Fv2026.5.27" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/openclaw/releases/tag/v2026.5.27</a></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/444</guid>
      <pubDate>Fri, 29 May 2026 13:38:28 +0800</pubDate>
    </item>
    <item>
      <title>OpenClaw 2026.5.26 更新速览：更快、更稳、更安全</title>
      <link>https://gooseforum.online/p/post/442</link>
      <description>发布日期： 2026-05 标签： v2026.5.26 状态： 正式版 (Latest) + 预发布版 TL;DR 这次更新没有花哨的新功能，但 每一个细节都在让 OpenClaw 变得更好用 ——启动更快、响应更及时、语音更靠谱、审批更方便，而且安全边界更严格。如果你之前觉得 Gateway 启动慢、移动端审批麻烦、或者语音对话容易被打断，这次更新值得认真看看。 一、性能：Gateway 和回...</description>
      <content:encoded><![CDATA[<p><strong>发布日期：</strong> 2026-05-27
<strong>标签：</strong> <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Ftag%2Fv2026.5.26" target="_blank" rel="nofollow ugc noopener noreferrer">v2026.5.26</a>
<strong>状态：</strong> 正式版 (Latest) + 预发布版</p>
<hr/>
<h2 id="tl-dr">TL;DR</h2>
<p>这次更新没有花哨的新功能，但<strong>每一个细节都在让 OpenClaw 变得更好用</strong>——启动更快、响应更及时、语音更靠谱、审批更方便，而且安全边界更严格。如果你之前觉得 Gateway 启动慢、移动端审批麻烦、或者语音对话容易被打断，这次更新值得认真看看。</p>
<hr/>
<h2 id="一-性能-gateway-和回复终于不再-热身-了">一、性能：Gateway 和回复终于不再&#34;热身&#34;了</h2>
<p>过去的 Gateway 启动有点像老式汽车：点火之后要预热一圈，反复扫描插件、频道、会话、成本索引……现在这些元数据被<strong>缓存起来</strong>，启动时直接复用，不再重复发现。</p>
<p>更妙的是，<strong>可见回复和后续工作被拆开了</strong>。你看到的回复先出去，慢一点的收尾工作在后台继续。主观感受就是：<strong>字出来得更快了</strong>。</p>
<blockquote>
<p>相关 PR: <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F84649" target="_blank" rel="nofollow ugc noopener noreferrer">#84649</a>, <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F85843" target="_blank" rel="nofollow ugc noopener noreferrer">#85843</a>, <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F86517" target="_blank" rel="nofollow ugc noopener noreferrer">#86517</a>, <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F86678" target="_blank" rel="nofollow ugc noopener noreferrer">#86678</a></p>
</blockquote>
<hr/>
<h2 id="二-transcripts-所有对话都有了-记忆">二、Transcripts：所有对话都有了&#34;记忆&#34;</h2>
<p>这次把<strong>转录 (Transcripts)</strong> 做成了核心基础设施：</p>
<ul>
<li>会议摘要可以直接回溯原始转录</li>
<li>CLI、WebChat、媒体输入、Codex 镜像……所有用户输入统一走一条更可靠的持久化路径</li>
<li>附带来源元数据、媒体溯源、清理后的文本</li>
</ul>
<p>简单说，以后复盘对话、做总结、或者排查问题，都有据可查，不再依赖零散的日志拼凑。</p>
<hr/>
<h2 id="三-频道-移动端审批终于不用打字了">三、频道：移动端审批终于不用打字了</h2>
<p><strong>Signal / iMessage / WhatsApp</strong> 现在支持<strong>反应式审批</strong>——直接在消息上点 👍 就能批准敏感操作，不用输入 <code>/approve</code> 命令。这在手机上用起来舒服太多了。</p>
<p>其他频道也有实质性改进：</p>
<table>
<thead>
<tr>
<th>频道</th>
<th>改进</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Telegram</strong></td>
<td>保留 typing 状态、支持论坛主题</td>
</tr>
<tr>
<td><strong>iMessage</strong></td>
<td>正确处理附件根路径、远程媒体暂存</td>
</tr>
<tr>
<td><strong>WhatsApp</strong></td>
<td>恢复群组和媒体行为</td>
</tr>
<tr>
<td><strong>Discord</strong></td>
<td>语音播放改善、模型选择更友好</td>
</tr>
</tbody>
</table>
<blockquote>
<p>相关 PR: <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F85894" target="_blank" rel="nofollow ugc noopener noreferrer">#85894</a>, <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F85952" target="_blank" rel="nofollow ugc noopener noreferrer">#85952</a>, <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Fpull%2F85477" target="_blank" rel="nofollow ugc noopener noreferrer">#85477</a></p>
</blockquote>
<hr/>
<h2 id="四-语音-talk-模式真正可用了">四、语音：Talk 模式真正可用了</h2>
<p>实时语音 (Talk) 这次做了大量底层重构，核心收益：</p>
<ul>
<li><strong>Web UI 和 Discord 语音</strong>里可以实时查看、引导、取消 Talk 运行</li>
<li><strong>唤醒词识别</strong>更宽容，但不会让环境语音随便触发代理</li>
<li><strong>barge-in（打断）检测</strong>更聪明，知道什么时候该听你的</li>
<li><strong>发言者归因</strong>在 Discord 语音中更准确</li>
</ul>
<p>如果你在用 OpenClaw 做语音助手，这次更新会让体验从&#34;能跑&#34;变成&#34;好用&#34;。</p>
<hr/>
<h2 id="五-安全-把能堵的漏洞都堵了一遍">五、安全：把能堵的漏洞都堵了一遍</h2>
<p>虽然枯燥，但很重要：</p>
<ul>
<li><strong>SSRF 防护</strong>：浏览器快照读取前先过策略检查</li>
<li><strong>提示注入防护</strong>：系统事件文本无法伪造嵌套 <code>&lt;&lt;&lt;</code> 标记</li>
<li><strong>外部内容隔离</strong>：<code>web_fetch</code> 获取的文本默认包装为不可信外部内容</li>
<li><strong>ClickClack 白名单</strong>：入站消息先过发送者允许列表，再进代理</li>
<li><strong>设备令牌轮换</strong>：过期/失效的令牌直接拒绝 RPC</li>
<li><strong>工具调用文本清洗</strong>：序列化的工具调用内容不会泄露到最终回复</li>
</ul>
<blockquote>
<p>贡献者：<a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fzsxsoft" target="_blank" rel="nofollow ugc noopener noreferrer">@zsxsoft</a>, <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fttzero25" target="_blank" rel="nofollow ugc noopener noreferrer">@ttzero25</a>, <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fmmaps" target="_blank" rel="nofollow ugc noopener noreferrer">@mmaps</a></p>
</blockquote>
<hr/>
<h2 id="六-codex-与提供商-少一些-provider-specific-的坑">六、Codex 与提供商：少一些 provider-specific 的坑</h2>
<ul>
<li><strong>Codex CLI</strong> 升级到 0.134.0</li>
<li><strong>OpenAI 采样参数</strong>（temperature、top_p 等）现在能正确透传到 Gateway</li>
<li><strong>xAI</strong> 使用限制错误现在会明确暴露给用户</li>
<li><strong>Ollama</strong> 的 top_p 做了归一化，避免贪婪采样异常</li>
<li><strong>动态工具模式</strong>加了保护，防止不受支持的配置把代理带崩</li>
</ul>
<hr/>
<h2 id="七-其他值得注意的改动">七、其他值得注意的改动</h2>
<table>
<thead>
<tr>
<th>功能</th>
<th>变化</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Discord 模型选择器</strong></td>
<td>超过 25 个模型时显示字母桶分组 (A–G · H–N · O–Z)</td>
</tr>
<tr>
<td><strong>Control UI</strong></td>
<td>新增临时 Activity 标签页，实时看工具调用</td>
</tr>
<tr>
<td><strong>TUI</strong></td>
<td>代理忙的时候提示会被排队，不再静默丢弃</td>
</tr>
<tr>
<td><strong>Cron</strong></td>
<td>默认并发从 1 提到 8，计划任务不再排队</td>
</tr>
<tr>
<td><strong>媒体处理</strong></td>
<td>Sharp 替换为 Rastermill，更轻量，保留 PNG alpha</td>
</tr>
<tr>
<td><strong>iOS/Android</strong></td>
<td>Talk 模式界面改进、离线恢复、网关配对</td>
</tr>
<tr>
<td><strong>构建</strong></td>
<td><code>pnpm build</code> 自动包含 UI 构建，不再遗漏 dist</td>
</tr>
</tbody>
</table>
<hr/>
<h2 id="结语">结语</h2>
<p>这次更新的关键词是**“打磨”**——没有惊天动地的新功能，但启动速度、响应体感、语音稳定性、移动端体验、安全边界，全都有实质性的进步。对于日常高频使用 OpenClaw 的人来说，这是最舒服的一类更新。</p>
<p>完整变更列表请见 GitHub Releases：
🔗 <a href="/outbound?url=https%3A%2F%2Fgithub.com%2Fopenclaw%2Fopenclaw%2Freleases%2Ftag%2Fv2026.5.26" target="_blank" rel="nofollow ugc noopener noreferrer">https://github.com/openclaw/openclaw/releases/tag/v2026.5.26</a></p>
<hr/>
<p><em>发布于 2026-05-27 · OpenClaw Team</em></p>
]]></content:encoded>
      <guid>https://gooseforum.online/p/post/442</guid>
      <pubDate>Thu, 28 May 2026 09:46:17 +0800</pubDate>
    </item>
  </channel>
</rss>