深度拆解PenEcho核心架构:20000×20000无限画布靠稀疏瓦片保持流畅的秘诀
深度拆解PenEcho核心架构20000×20000无限画布靠稀疏瓦片保持流畅的秘诀【免费下载链接】penechoThink with AI beyond the chat box. A shared canvas for handwriting, equations, diagrams, and spatial reasoning.项目地址: https://gitcode.com/gh_mirrors/pe/penechoPenEcho 是一款超越聊天框的 AI 协作画布集手写笔迹、数学公式、专业图表与空间推理于一体。它最大的技术亮点是把一块 20000×20000 逻辑坐标的无限画布拆成稀疏的 512×512 小瓦片sparse tiles按需分配——整块画布永远不是一张真实位图因此无论你怎么放大缩小、平移涂写浏览器都始终流畅。下面带你用最通俗的方式看懂这套稀疏瓦片架构的运作原理。为什么无限画布不能整张画先算一笔账一块 20000×20000 的画布如果按常见的 4 通道 RGBA 位图计算就是约1.6GB 内存的像素数据——这还没算撤销栈、快照和高分屏放大。真实使用中画布 99% 的面积是空白纸面。为空白像素白白分配内存既浪费又拖慢渲染。所以 PenEcho 做了一个根本性的决定不整块分配。核心定义就在画布运行时的开头const SIZE 20000, TILE 512,来源public/app.js也就是说逻辑坐标空间是 20000×20000但内存里实际存在的只是被内容碰过的 512×512 小格子。官方架构文档把这句话说得很直白英文原文The full logical canvas is never allocated as one bitmap. Rendering composites only visible sparse tiles into the viewport canvas.完整逻辑画布从不被分配为单张位图渲染时只把可见的稀疏瓦片合成到视口画布上。网格切分瓦片坐标系是画布的地基把 20000×20000 按 512 一格切分整个画布最多有 39×39 ≈1521 个潜在瓦片槽位。每个槽位有一个整数坐标(tx, ty)对应的逻辑区域是[tx*512, ty*512]起的 512×512 方块。任何一次笔触、擦除、AI 生成的图形都会被落进它覆盖的瓦片里。跨瓦片的长线条会切成若干片段分别写进各自瓦片的局部坐标。这样一块瓦片坏了只需要重绘它一张画布脏了也只需要重绘脏的那几格——这是后面局部渲染和局部存储的基础。按需分配空着的格子一格内存都不占这是稀疏二字的真正含义。瓦片不是启动时预先创建好的而是谁被写到、谁才被诞生function tile(tx, ty, create true) { const k key(tx, ty); if (!tiles.has(k) create) { const c document.createElement(canvas); c.width c.height TILE; // 512×512 c.getContext(2d, { willReadFrequently: true }); tiles.set(k, c); state.inkBounds.set(k, null); } return tiles.get(k); }来源public/app.js全画布用一个字典tilesMap键是瓦片坐标管理没有内容的坐标在字典里根本不存在——这就是稀疏每个瓦片是一个独立的 512×512canvas带透明背景铺在纸面之上。画上一幅小图可能只产生几块瓦片整个画布的内存占用 ≈实际内容量而不是 1.6GB。只渲染视口forTiles 与分层合成滚动或缩放时浏览器需要知道当前屏幕露出哪些瓦片。PenEcho 用一个统一的遍历函数forTiles完成这件事function forTiles(x, y, w, h, fn, create true) { const x0 Math.max(0, Math.floor(x / TILE)), y0 Math.max(0, Math.floor(y / TILE)), x1 Math.min(Math.ceil(SIZE / TILE) - 1, Math.ceil((x w) / TILE) - 1), y1 Math.min(Math.ceil(SIZE / TILE) - 1, Math.ceil((y h) / TILE) - 1); if (x1 x0 || y1 y0) return; for (let ty y0; ty y1; ty) for (let tx x0; tx x1; tx) { const c tile(tx, ty, create); if (c) fn(c, tx, ty); } }来源public/app.js传入视口矩形它把坐标换算成瓦片索引范围只遍历落在视口内的瓦片。渲染笔迹层时只有一行核心逻辑forTiles(visible.x, visible.y, visible.w, visible.h, (canvas, tx, ty) inkCtx.drawImage(canvas, tx * TILE, ty * TILE), false);来源public/app.js配合几个细节流畅度就被锁死了分层画布背景、已放置内容、墨迹、动画、交互预览各在一层互不牵连动画不进位图动画场景活在独立的持久对象层上只按脏矩形局部重绘与瓦片位图完全解耦渲染队列requestRender()用state.renderQueued去重同一帧内的多次脏标记只触发一次合成。瓦片是存储的最小单元稀疏瓦片的好处不止在内存里还贯穿到本地持久化。浏览器使用 IndexedDB 数据库penecho-canvas-history其中snapshot-tiles库每块有内容的瓦片存一个独立 PNG Blob以快照 ID 索引。这带来两个直接收益画布列表只加载轻量的预览缩略图不碰任何瓦片数据点开某个画布时才按需分批解码瓦片解码批次大小为 8加载体验平滑。画布导出/分享时同样按瓦片打包成自包含的penecho-raster-tiles格式每个瓦片是独立资产可无损迁移到云端或别人的设备。完整规则见架构总览docs/architecture.md画布存储格式 v2spec/canvas-storage-v2.mdAI 如何看懂这么大的画布如果画布真有一张完整位图喂给 AI 的截图会大到离谱。稀疏瓦片让另一件事成为可能按需裁剪。AI 自动请求的流程是你的新笔迹更新了一个脏区域dirty bounds和热点轨迹延迟结束后客户端以最新墨迹为中心裁剪出一张白底小图atlas而不是整幅画布请求中附带全局几何参数、权威的最近输入矩形、8×8 热点网格和局部放大细节模型据此判断用户在画哪、想补全什么模型返回的结构化命令公式、图表、统一绘图指令等经校验后作为未确认草稿展示确认后写回稀疏瓦片或进入动画对象层。整条链路详见架构文档的 AI Request Flow 小节docs/architecture.md。稀疏瓦片架构小结环节做法收益内存512×512 瓦片按需创建空白不分配占用 ≈ 内容量与 1.6GB 大图无缘渲染forTiles只遍历视口内瓦片分层合成缩放/平移始终只画看得见的格子更新每块瓦片独立脏区跟踪局部重绘一笔只动几格帧率稳定存储每块瓦片一个 PNG Blob 存 IndexedDB列表秒开、按需加载、可迁移AI围绕脏区域裁剪 atlas 而非整幅截图请求小而准模型看得清上下文一句话总结20000×20000 只是坐标系不是内存。稀疏瓦片让无限画布从一句营销词变成了浏览器里可以随手平移涂写的日常体验——这就是 PenEcho 流畅感的底层答案。延伸阅读想深入了解完整架构含 AI 请求链路、模型执行器、统一绘图协议docs/architecture.md想弄清画布数据在本地与云端之间的持久化格式spec/canvas-storage-v2.md画布运行时源码入口public/app.js【免费下载链接】penechoThink with AI beyond the chat box. A shared canvas for handwriting, equations, diagrams, and spatial reasoning.项目地址: https://gitcode.com/gh_mirrors/pe/penecho创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考