Skip to content

Releases: AAAAAnson/mbeditor

v5.6.1 — 交互效果点击修复 + 微信自触发改造

Choose a tag to compare

@AAAAAnson AAAAAnson released this 13 Jun 08:53

真机真值表驱动的交互修复 patch:让交互效果在编辑器里点得动、在微信真机上(id 被剥后)也点得动。

后端测试 648 passed / 15 skipped,前端 369 passed

🐛 修复:tab-panel 点击展开无反应

标签 <text> 盖在按钮 <rect> 上且为兄弟节点,点击文字时事件不经过触发元素 → begin="tabNbtn.click" 收不到(真实浏览器复现)。改为 <g id> 包裹 rect+label,对齐其余效果结构。预览面新增提示:检测到可交互 SVG 且在「公众号效果」预览时,引导切到「交互预览」点击测试(不影响编辑内容)。

🔧 交互效果改造为微信自触发(消除跨元素 id 依赖)

真机真值表确认:微信剥光所有 id=,却保留 begin="id.click" 引用 → 跨元素触发在公众号真机悬空失效。改为同元素 begin="click"/"touchstart" 自触发 + 覆盖揭示。全部 6 个交互效果经「微信实际存储 HTML + 真实 Chromium 点击」验证,剥 id 后交互均存活:

效果 改造 语义
smil-carousel / mask-reveal 直接改自触发 完整保留
flip-card 覆盖揭示(背面常驻、正面淡出) 降级单向翻面
longpress-ring 充环+延时盖板淡出自触发;圆心可命中 长按近似
tab-panel 覆盖揭示手风琴 受限:各板块独立展开、不互斥
multi-choice 选项自高亮、解析常驻 受限:不按选项切换
scroll-carousel / pano-slide 纯 CSS scroll-snap 不受影响

tab-panel / multi-choice 的「点 A 控制独立 B」本质需跨元素、微信无 id 做不到,已诚实判定受限并降级(不保留悬空 id.click 假装能用),description 与模板注释均标注。

✅ 测试

新增参数化断言:渲染通过 / begin·end 无跨元素 id 引用 / 模拟剥 id 后存活 / 不触发 id-stripped-dangling-ref 告警。

完整条目见 CHANGELOG.md

🤖 Generated with Claude Code

v5.6.0 — 微信 SVG 交互能力路线图(P1+P2)+ 真机真值表

Choose a tag to compare

@AAAAAnson AAAAAnson released this 13 Jun 07:48

本次发布完成微信公众号 SVG 能力路线图的全部 P0 → P1 → P2:从"自家管线先把 SVG 打坏",到"AI 填槽即产出过校验的合法交互 SVG",并首次用 31 探针真机真值表校准了规则边界。

后端测试 250 → 619 passed,前端 282 → 369 passed

✨ 新增

  • 交互效果引擎(P1-1):8 个 opensvg 派生插槽化配方,覆盖六类交互(展开/轮播/滑动/长按/答题/翻卡),文本/图片/颜色槽 + 时序参数,填槽渲染强制过校验;支持区块级插入(不再整篇覆盖)。新端点 GET/POST /api/v1/agent/effects
  • 真后端 LLM 生成(P1-4):接入 Claude API(claude-opus-4-8)。LLM 只产结构化 DSL、绝不直接写 SVG,经 effect registry 确定性渲染——注入面与校验面全部收敛。无 API key 时优雅降级。
  • 编辑器内交互预览(P1-3):「公众号效果」(sanitize 后) ↔「交互预览」(原始 SVG,sandboxed iframe,SMIL 点击可真实验证) 模式切换。
  • 反向导入 + 多平台 profile(P2-4):微信文章/通用 HTML 反向解析为 mbdoc(SVG 子树逐字保真),POST /api/v1/publish/import-htmlwechat(行为字节等价) + generic(更宽松) 渲染 profile。
  • 编辑体验(P2-1/2/3):SVG 可视化面板(颜色/热区/SMIL 时序)替代纯 textarea;模板缩略图 + 参数化配色文案;StructurePanel 解析 SVG 内部交互结构并可点击定位。

🔬 真机真值表(关键发现)

31 探针经 add_draft 真推草稿箱 + 回读,产出 docs/research/wechat-svg-truth-table.md

微信剥除 id= 定义,却保留 url(#id) / href=#id / begin=id.click 引用 → 一切依赖 id 的渐变/滤镜/clipPath/mask/use/跨元素 SMIL 在真机悬空失效,仅 begin=click 同元素自触发可用。

该结论已转化为校验器 id-stripped-dangling-ref 告警,从生成阶段拦截。

🛠 校准与安全

  • 白名单按 T/CASME 1609—2024 + 真值表校准:stroke/rx/ry 放行、静态 stroke-dasharray 不再误杀;新增 <style>/SVG <a>/外链 <image> 三类告警;事件处理器拦截改为通配 on[a-z]+=
  • LLM 输出、反向导入 HTML、模板槽值全部视为不可信,双重门禁;对抗式审查修复跨类槽位二次替换、url(javascript:) 样式注入、<image> 危险 scheme 等多条注入路径。安全底线未回退。

完整条目见 CHANGELOG.md

🤖 Generated with Claude Code

v5.5.0 — 页面背景修复 + 复制管线加固 + MBDoc API

Choose a tag to compare

@AAAAAnson AAAAAnson released this 12 Jun 13:22

🎨 重点修复:页面背景粘到公众号后台不再消失

根因终于找到了:微信粘贴处理器会"解包" HTML5 语义标签(<article> <main> <header> <footer> 等)——子内容保留,但标签连同它的 style 属性一起被丢弃。把页面渐变/底色写在 <article style> 上的推文,粘贴后整页变白。

  • ✅ Sanitizer 把语义包裹标签统一改名为 <section>(微信完整保留),背景随之存活
  • ✅ 校验器新增 semantic-wrapper-tag 警告,复制前就提示
  • ✅ 新增全文档管线回归测试,以真实推文结构断言背景存活

🛠 复制管线全面加固

完整 HTML 文档支持:AI 直接产出的带 <!DOCTYPE> / <head> / <body bgcolor> 的完整文档,现在能正确走完复制管线——

  • <!DOCTYPE> 不再让 premailer 抛异常跳过 CSS 内联
  • <title>/<meta>/<link> 不再泄漏进正文
  • <body> 的 style/bgcolor 自动搬到根 <section> 上,针对 body 的 CSS 规则同步重定向
  • 嵌套 @media 整块剥除(旧版会让移动端 display:none 泄漏成全局规则,所有端隐藏内容)
  • a, a:hover {...} 这类混合选择器只删伪类部分,普通选择器保留
  • 单引号 style 内含双引号(font-family:"PingFang SC")不再被截断

校验与图片

  • 正文里出现 "mask" 等英文单词不再误触发禁用 CSS 拦截
  • 图片 data-URI 内联锚定到 <img> 标签,教程正文/<video>/<iframe> 不再被误改写;失败 URL 负缓存免重试

前端剪贴板

  • 长文分段复制不再静默丢失裸文本节点
  • swiss 主题不再误剥作者写的黑色/深灰背景(深色 hero、代码块幸存)
  • 纯文本兜底按块级边界换行,不再全文挤成一行

📦 新增:MBDoc 后端 API

  • MBDoc CRUD + 发布端点(/api/v1/mbdocs),前端 store 接后端并保留本地缓存层
  • Article → MBDoc 转换器与一键迁移脚本
  • EditorSurface / publish_adapter 重构为 hook + service 分层
  • 后端 API 测试基础设施 + publish 集成测试;文章列表 JSON 导出/导入备份

✅ 质量

后端 250 个测试通过,前端 282 个测试通过,Vite 构建干净。

Full Changelog: v5.4.0...v5.5.0

v5.4.0 — Chunked Copy + Title URLs + Sanitizer Table Fix

Choose a tag to compare

@AAAAAnson AAAAAnson released this 17 May 07:26

Added — 长文一键复制

  • "复制富文本"对话框新增长文模式:HTML > 400KB 时弹"分段复制 / 改用草稿箱"选择面板。分段路径按 body 顶层 block 边界递归切到 ~250KB 一段,每段都是自洽的富文本片段,引导用户逐段粘到公众号后台末尾。
  • 切分算法 splitHtmlIntoChunks 递归下钻:遇到超预算的元素就钻到它的子级,每一层切完都用本层的开/闭标签把内容重新包起来,保证嵌套结构里的标题/卡片/章节等外层样式在每段粘贴时都还在。
  • 草稿箱兜底:未绑定公众号 appid+appsecret 时按钮灰掉并提示,绑了就一键跳 /wechat/draft 完全跳过剪贴板。

Added — 文章 URL 与标题对应

  • 路由从"/ 一招走天下"换成 /a/<encodeURIComponent(title)>-<4位ID> 的标题型 URL。浏览器地址栏现在能看出打开的是哪篇文章,可收藏可分享。
  • 标题改名时通过 replaceParams 原地同步 URL,不污染后退栈。
  • nginx 已有 try_files \$uri \$uri/ /index.html,刷新 /a/<slug> 直接命中 SPA fallback,无需服务端配置改动。

Fixed — 微信粘贴布局

  • Sanitizer 注入 table-layout:fixed:当 <table> 里至少一个直接子 <td> 写了 width:Xpx,就给该表加 table-layout:fixed,让作者的列宽真正生效。默认 table-layout:auto 会让浏览器把窄列压到 single-character min-content,正是"01""02"等数字徽章被分裂到两行的根因。
  • 同步规则:表本身没设 width/max-width/min-width 也没 width= HTML 属性的,自动补 width:100%——HTML5 规范里 fixed-layout 在无宽度表上等于 auto,必须给一个宽度才能生效。
  • table-layout 加进 sanitizer allowlist,值限定 {fixed, auto}

Backend 202/202 tests passing · Frontend 232/232 tests passing

v5.3.0

Choose a tag to compare

@AAAAAnson AAAAAnson released this 25 Apr 12:46

v5.3.0

v5.0.0

Choose a tag to compare

@AAAAAnson AAAAAnson released this 20 Apr 10:06

Added — 编辑器所见即所得

  • 预览区现在是可编辑的 contentEditable 画布:直接在预览里改文字,500ms 去抖后自动回写到 HTML/Markdown 源码。形状一致时只拷贝文本节点,保留源码结构;形状漂移走 sanitizer 兜底。
  • HTML→Markdown 序列化器覆盖标题/段落/嵌套列表/引用/代码块/分隔线/图片/inline 强调/链接,Markdown 模式的预览编辑能无损回写。
  • 预览框支持拖拽调整宽/高/右下角,以及 40%–200% 独立缩放滑杆;尺寸和缩放分别持久化到 uiStore

Added — 五套示例模板 + 一键复制富文本

  • 内置 极简商务 / 科技霓虹 / 活力撞色 / 文艺手札 / 杂志专栏 五种风格示例文章,全部 100% 微信 sanitizer 白名单内联样式。
  • 恢复并增强了一键复制富文本按钮,复制结果与预览完全一致,粘贴到公众号后台 0 样式损失。

Added — 编辑器导航与结构面板

  • 左侧 StructurePanel 列出标题/图片大纲,点击节点自动跳到对应位置并在预览和编辑器中同步高亮。
  • 编辑器头部新增「返回上一页 / 返回稿库」回退按钮,保留未保存草稿。

Changed — UI 与体验大改

  • 前端重做:walnut / paper / swiss 三主题 + 三种布局(focus / split / triptych)。
  • 去掉了产品里暴露的 Agent Console(保留为 marketing 素材,不进打包)。
  • 非关键英文 UI 文案改成中文(导航、按钮、状态芯片)。
  • 关闭自动保存时保留草稿,切换文章不清空未保存内容。

Changed — 后端

  • 数据目录自动探测:检测到 docker-compose.yml 走仓库根 data/,否则落 backend/data/,写死的 /app/data 去掉。
  • 启动时统一 ensure_data_directories() 创建 images / articles / mbdocs / config.json 父目录。
  • PUT /articles/{id}mode=markdown 且只收到 Markdown 时自动用 markdown renderer 同步 HTML,便于 CLI/API 调用方只传 Markdown。

Added — 文章列表删除按钮

  • 列表每行末尾新增 🗑 按钮,点击触发 window.confirmDELETE /articles/{id};同步清理 currentArticleId,删当前编辑中的文章不会留下悬挂引用。

Added — 首次启动自动 seed 五篇模板

  • backend 启动若检测到 ARTICLES_DIR 为空,从 backend/app/seeds/tpl_*.json 把五套示例模板种进去;已有内容绝不覆盖。模板同时保留在仓库根 docs/cli/examples/templates/,便于 dev 模式和 CLI 复用。

Security — 预览粘贴的 XSS 护栏

  • cleanPreviewFallback 从「只剥 style/class/contenteditable」升级为完整黑名单:<script>/<iframe>/<object>/<embed>/<link>/<meta>/<style>/<base>/<frame>/<frameset> 直接移除;on* 内联事件处理器一律 strip;href/src/xlink:href 中的 javascript: / vbscript: / data:text/html 协议一律清除。保留父元素文本和安全属性。
  • render_markdown_source 关闭 markdown-it 的 html: true,Markdown 里内嵌的 <script> / <img onerror> 一律被当作文本转义输出,不会以活 HTML 写入 article.html。publish 管道仍会做一遍 sanitize,但现在存储态本身也是安全的。

Changed — 版本号

  • backend pyproject.tomlAPP_VERSION、frontend package.json、BrandLogo、README 徽章、Settings 页面全部统一到 5.0.0;测试用例改用 APP_VERSION 常量而非硬编码字符串。

v4.1 — agent-first CLI + WeChat-safe 白名单 sanitizer

Choose a tag to compare

@AAAAAnson AAAAAnson released this 17 Apr 12:20

亮点

🖥️ Agent-first mbeditor CLI(对齐 CLI-Anything 理念)

  • pip install -e ./backend 得到可执行的 mbeditor
  • 默认 direct 模式:直接读写本地 data/ 文件 + 调用服务函数,不需要跑 FastAPI
  • HTTP 模式--mode http/api/v1 后端代理,共享 token / 缓存
  • 命令组:article / doc / image / render / publish / config / skill / info
  • 稳定输出 envelope:{ok, action, message, data}--json --compact 出 JSONL
  • 退出码约定:0 成功 / 1 执行错误 / 2 用法错误
  • 随包 SKILL.mdmbeditor skill 直接打印给 agent 吞
  • 33 条 CLI 测试 + 1 条 CLI 驱动的端到端视觉零变形测试

🧼 WeChat-safe 白名单 sanitizer

针对"复制到公众号后台 vs /draft/add"渲染漂移的根因修复:

  • 正向属性白名单(~60 项,基于真实公众号稳定文档校准)
  • display 值约束:仅 block / inline / inline-block / none / table-*flex / grid 全部剥除
  • position 值约束:仅 relative / staticabsolute / fixed 触发 display:none
  • 去掉 !important / flex 族 / grid 族 / float/clear / cursor/user-select/pointer-events/will-change
  • 保留 linear-gradient / box-shadow / letter-spacing / opacity / vertical-align 等所有公众号真支持的视觉属性
  • 按钮 <a> 自动转 <table><tr><td> 结构

📖 附带示范文章 docs/cli/examples/demo_article.json —— 用新格式重写的 7-block 推文,25 个属性全部在白名单内,零漂样板。

🎨 真 Playwright raster 工作器

  • RasterRenderer 发布时无 uploader 直接抛错,杜绝 data: URL 进草稿
  • SvgRenderer 发布时拒绝 <image> 的远程 href(含 xlink:href
  • 缓存 / 失败恢复 / 本地图片内联边界测试齐全

🧱 MBDoc stage 完成

  • heading / paragraph / markdown / html / image / svg / raster 七种 block 全部有真渲染器
  • publish.py 剥离成路由层,transform 下沉到 publish_adapter / legacy_render_pipeline / media_uploader / wechat_publisher 等服务
  • 新增 document_projector:legacy Article ↔ MBDoc 桥接
  • /api/v1/mbdoc 新增 /project/article/{id} / /render / /publish 端点

🧪 前端 block-native bridge 编辑器

  • 新增 features/editor/ 模块,projected-block 编辑 + session 状态
  • Lazy-loaded Monaco / Markdown 编辑器壳
  • Vite chunk 切分:monaco / markdown-vendor / tiptap / react-vendor / lucide
  • Editor chunk 降到约 62 KB

测试

  • backend: 210 passed / 1 pre-existing xfail
  • CLI: 33 passed
  • WeChat-safe sanitizer: 26 passed
  • 示范文章白名单守护: 7 passed
  • 端到端 CLI-driven 视觉零漂移: 1 passed(diff = 0 px)

升级提示

  • 如果你曾经在文章里依赖 display:flex / display:grid / position:absolute / animation / transform 等做版式,它们现在会被 sanitizer 剥除。请用 display:inline-block + vertical-align:middle 做横排布局(参考 docs/cli/examples/demo_article.json
  • WeChat 凭据配置仍在 data/config.json,向后兼容
  • 老的 /articles + /publish API 保留不变

v4.0 — 复杂 HTML 还原度 99.6%(WeChat publish pipeline 硬化)

Choose a tag to compare

@AAAAAnson AAAAAnson released this 12 Apr 00:49

🎯 一句话总结

结构 100%、几何 99.6% 地把一篇 600 行带 grid / SVG / scroll-reveal / CTA 按钮的复杂动画 HTML 推到公众号草稿——在 MB 科技测试公众号端到端验证通过。

背景

v3.1 之前 publish 流水线只能稳定处理简单图文排版。遇到复杂外部 HTML(例如 落地页导出的产品页)会出现:

  • 内容大段空白(scroll-reveal 默认 opacity:0 依赖 JS 显示)
  • Hero 高度暴涨 2-3 倍(装饰性 position:absolute 失效变 block)
  • 下载按钮消失(<a> 标签被微信后端 strip)
  • grid 布局退化成单列堆叠(旧逻辑没保留)

v4.0 对 publish 流水线做了四项"硬化"修复 + 一整套视觉一致性校准基础设施。

✨ 主要改动

Publish 流水线硬化(backend/app/api/v1/publish.py

输入 新流水线处理 结果
opacity:0 opacity:1 修复 scroll-reveal 隐藏
transform:translate*(...) transform:none 修复 slide-up 偏移
transition* / animation* strip 避免 sub-pixel 漂移
position:absolute|fixed display:none 微信删 position,失效的装饰直接隐藏
<a href="外部"> <section> 保留样式 微信删 a,视觉按钮留下
首个外部 <a href> 自动抽 → content_source_url 公众号"阅读原文"链接

视觉一致性基线 20.96% → 1.47%

在 H1-H6 + 段落基线 doc 上把 pixel diff 从 20.96% 校准到 1.47%:

  • _BODY_STYLE_FLUSH 完整镜像微信 .rich_media_content 容器(letter-spacing:0.578pxpadding:0 4pxdisplay:flow-root BFC、contenteditable 启用 line-break:after-white-space
  • 标题/段落 line-height 改用整数 px(h1=36..h6=21、p=29)取代 1.4 / 1.8 倍率,避免分数 line-box 的累积 round 分歧
  • 渲染器把文本包在 <span leaf=""></span> 镜像微信 ProseMirror ingest 行为

新增校准基础设施

  • backend/tests/visual/dump_wechat_computed_styles.py — dump WeChat 容器 computed style 到 JSON(校准 ground truth)
  • scripts/test_publish_html.py/publish/preview + /publish/draft + 截图一条龙
  • scripts/test_publish_direct.py — 绕过 API 直接 import,对付 uvicorn 旧字节码
  • scripts/compare_source_vs_draft.py — source ↔ draft 四象限 side-by-side

📊 验证结果(printmaster_wechat_animated.html 600 行测试)

阶段 Draft 高度 vs source 4564
v3.1(旧流水线) 7496 px +64.24% ❌
v4.0 修复 reveal 5212 px +14.20%
v4.0 修复 absolute 4519 px -0.99%
v4.0 最终 4547 px -0.37%

结构还原度 100%(文字、图片、SVG、grid、flex、按钮文字全保留)。

📖 文档

  • 踩坑全记录docs/research/RESEARCH_CORRECTIONS.md — 完整校准过程 + 2026-04-12 publish 陷阱 writeup
  • Agent 使用指南skill/mbeditor.skill.md 新增 "Publish Pipeline 已知陷阱" 章节,六个陷阱 + 预防建议
  • ChangelogCHANGELOG.md [4.0.0]

🧪 部署验证

已本地 docker compose 验证:

docker compose build        # ✅ 镜像构建成功
docker compose up -d        # ✅ backend healthy
curl http://localhost:7072/api/v1/version
# {"version":"4.0.0","repo":"AAAAAnson/mbeditor"}

全流水线 smoke test(grid=4、display:none=7、position:absolute=0、<a>=0、opacity:0=0、cta-btn 保留)全部 assertion 通过

⚠️ 已知问题

  • Host-port shadowing:如果有 stale Python 进程绑定相同端口(如 7072),docker 部署会被僵尸 listener shadow。排查:Get-NetTCPConnection -LocalPort 7072 -State Listen 看谁占着
  • 本地开发 uvicorn:必须加 --reload 否则改 publish.py 后不生效
  • 1.47% 剩余 sub-pixel 差异:WeChat 容器 letter-spacing 0.578px 的字符漂移,无法消除(也不影响视觉)
  • 外部链接:每篇文章最多一个外部可点击 URL(通过"阅读原文"),写多个 <a href> 只有第一个有效

🙏 感谢

感谢 Claude Opus 4.6 (1M context) 全程陪同校准 + 六次 WeChat 草稿 push 迭代的耐心 debug。

v3.1 — 预览所见即所得

Choose a tag to compare

@AAAAAnson AAAAAnson released this 09 Apr 08:09

What's Changed

Fixed

  • 预览所见即所得 — 预览框改为显示后端处理后的内联化 HTML,复制到微信后台的效果与预览完全一致
  • 移除 base CSS 中 section 全局 margin/padding 重置,防止覆盖文章自定义样式
  • 复制时直接使用预处理好的 HTML,避免重复 API 调用

Full Changelog: v3.0...v3.1

V3.0 — 纯 HTML 排版组件 + 所见即所得发布

Choose a tag to compare

@AAAAAnson AAAAAnson released this 09 Apr 04:14

What's New in V3.0

核心变更

  • 下架 SVG 交互模板:SVG+foreignObject 方案在部分微信客户端表现不稳定,暂时下架。相关代码保留,待方案成熟后重启
  • 全新 HTML 排版组件:6 种纯 inline style 排版组件,复制到公众号后完美还原
    • 标签徽章 / 渐变卡片 / 数据看板 / 时间线 / 引用样式 / 对比表格
  • 所见即所得修复:后端自动注入 base styles(字体、字号、行高、颜色),预览效果 = 发布效果

改进

  • 🐳 Docker 启动自动创建 data 目录,无需手动 mkdir -p data/images data/articles
  • ⚙️ 首页 Header 新增设置页面入口(齿轮图标)
  • 📝 示例文章重新设计,展示纯 HTML 排版效果
  • 📖 README 同步更新

快速开始

git clone https://github.com/AAAAAnson/mbeditor.git
cd mbeditor
docker compose up -d
# 访问 http://localhost:7073

升级指南

已部署用户直接拉取最新代码重建即可:

git pull
docker compose up --build -d

Full Changelog: v2.0...v3.0