结论

纯网页端能手写,不用 WKWebView 桥。 iPad Safari 从 iOS 13 起就支持 Apple Pencil 的 Pointer Events(pointerType === 'pen',带 pressure 压力 / tiltX/tiltY 倾斜)。在 canvas 上画线即可。WKWebView 桥或原生 app 只有要"原生级"体验时才需要。

相关项目:浏览器内 Agent 服务 (InPage Agent) 的手写画布需求。
完整研发演进史与算法路径详见:数字墨迹与笔刷引擎演进史 (Digital Ink & Brush Engine Evolution)。
手笔手势冲突与平移引擎踩坑详见:批注模式触控笔书写触发页面滚动导致笔画拉丝偏移 (Stylus Annotation Triggers Viewport Pan Causing Stroke Drift)。

实现要点

  1. canvas 元素设 touch-action: none —— 否则滚动会吃掉笔画;但在可滚动文档(如 PDF)中叠加批注时,需配合内置虚拟平移引擎由手指接管平移。
  2. 监听 pointerdown / pointermove / pointerup;移动事件用 getCoalescedEvents() 拿细颗粒度坐标序列。
  3. 每笔记为 points 数组(pressure 字段),喂给 perfect-freehand 渲染平滑压力线条。
  4. 落盘:存为 SVG 或点列(JSON),放 IndexedDB。

掌误抑制与手笔分离: 在画布监听事件中严格区分 pointerType =<mark> 'pen'(落墨、preventDefault 锁定视口)与 pointerType </mark>= 'touch'(严禁落墨,手指驱动虚拟平移滚动容器)。

开源选型(2026-09 GitHub CLI 实查)

层项目星说明
笔画渲染(核心)steveruizok/perfect-freehand5730MIT;压力感应平滑线条,tldraw 同款
完整画布tldraw/tldraw50kMIT 类;React 无限画布
完整画布excalidraw/excalidraw132kMIT;手绘风白板
整体参考(最接近)penecho/penecho2368JS;手写画布 + 内置 agent + MCP;AGPL-3.0,抄代码要谨慎
iPad 原生参考brianharms/penpal—Swift;iPad 手写连 Claude API,回复也手写在同一画布
手写识别(墨迹→文字)huggingface/transformers.js16k本地 WASM 跑 TrOCR,开源不上传;偏重,可后置

什么时候才真的需要原生/WKWebView 桥

  • 想要 Apple Scribble 系统手写键盘(系统能力,不暴露给 web JS)。
  • 更强的掌误抑制 / 原生墨迹识别(Ink)体验。
  • 否则:画线、手写笔记、agent 画布,纯浏览器完全够。

"GoodNotes 级" = 三个硬指标(2026-09 调研)

指标纯 web 能做到吗怎么做 / 参考
逼真墨迹质感能,自写或调和算法1. SignaturePad 算法 (Square 三次贝塞尔 + 速度插值):连笔书写极流畅,自带笔锋自然收窄,最接近钢笔质感。
2. GoodNotes 模拟引擎 (向心样条 + Hermite S 曲线压感 + 速度阻尼):双层增量渲染,支持钢笔/圆珠笔/秀丽笔/荧光笔。
3. Rnote 笔刷模型 (向心 Catmull-Rom + 低通滤波 + 拐角曲率抑制):解决笔画拐折处的突变与膨胀。
4. perfect-freehand:多边形 Ribbons,开启真实硬件压感时质感偏马克笔/白板笔。
极低延迟(~16ms)逼近,需特定优化组合1. canvas.getContext('2d', { desynchronized: true }) 绕过合成器双缓冲。
2. 双层画布 (Backing + Active):当前笔划只在顶层局部画增量段,零全量重绘开销。
3. e.getCoalescedEvents():iPad Pro 120Hz/240Hz 采样全保留,消除折线段感。
掌误抑制 + 系统识别纯 Web 可做到笔/手分离1. Web 层开启 Pen-Only 模式:e.pointerType === 'pen' 触发绘制,touch 忽略画线,有效解决手掌贴屏误画。
2. Apple Scribble 原生系统文字识别需原生层;Web 端文字识别可用 TrOCR / 云 OCR。

实测对比实验室 (Web Handwriting Lab)

已在平台部署五种引擎并排体验实验室:https://6767.chat/write

  • 涵盖:GoodNotes Ink 引擎、SignaturePad 算法、Rnote 笔刷模型、Perfect-Freehand、原生折线基准。
  • 包含实时 HUD:采样率(ProMotion 120Hz 状态)、原生压感值、渲染耗时、米字练习格底纹。

GoodNotes 核心 4 维手感参数数学建模 (实测基准: 75 / 50 / 33 / 0)

  1. 笔尖锐度 (Tip Sharpness, 75%):

    • 作用:控制落笔初始接触与提笔出锋时的收细锥度。
    • 算法:在笔画抬起或末段加速时引入出锋锥形衰减 $w_{\text{tip}} = w \cdot (1 - 0.75 \times 0.75)$,消除圆头钝感,使中文的“撇、捺、勾、悬针竖”自然显现尖锐笔锋。
  2. 压力敏感度 (Pressure Sensitivity, 50%):

    • 作用:映射 Apple Pencil 硬件压感 $p \in [0, 1]$ 到线条粗细。
    • 算法:通过非线性 Hermite / 幂次曲线调和 $w_p = \text{base} \cdot [(1 - 0.8S) + 1.6S \cdot p^{0.9}]$,中度压力下既有轻按发力感,又不会暴胀。
  3. 扁平度 (Flatness, 33%):

    • 作用:模拟真实钢笔切角笔尖(如平尖/书法尖),创造“横细竖粗”的书法结构。
    • 算法:笔尖设为椭圆截面(倾斜角 $\phi \approx -40^\circ$),沿运笔方向 $\theta = \operatorname{atan2}(dy, dx)$ 投影有效线宽:
      $$W(\theta) = 2 \sqrt{a^2 \sin^2(\theta - \phi) + b^2 \cos^2(\theta - \phi)}$$
      扁平度 33% 对应短半轴压缩约 21%,在汉字横平竖直时产生自然的粗细层次。
  4. 画笔稳定度 (Stabilization, 0%):

    • 作用:0 代表零粘滞、零拖拽延迟。
    • 算法:完全跳过拖尾弹簧/阻尼延时滤波,配合 desynchronized: true 与 getCoalescedEvents(),笔迹 1:1 紧咬 Pencil 笔尖,实现原生的指尖随动感。

核心手感发现:笔画纠偏机制与拉力收敛 (Laplacian Curve Tension)

在 iPad 玻璃表面书写草书、连笔或花体时,若完全按照原生硬件点拟合样条,线条容易显得“花乱、散漫”(肉眼可见的玻璃打滑与生理手颤)。
GoodNotes 之所以即使在“稳定=0”时线条依然极其收敛、紧绷、有骨力,核心在于几何拉力纠偏机制 (Tension Rectification):

  1. 拉普拉斯曲线张力算子 (Laplacian Curve Tension):

    • 仅对平滑曲线和连笔弧度段生效(相邻转折角 $\Delta\theta < 68^\circ$)。
    • 将连续三点中间点 $P_1$ 沿弦中点 $\frac{P_0 + P_2}{2}$ 方向施加内收拉力 $P_1 \leftarrow P_1 + k_{\text{rect}} \cdot (\text{mid} - P_1)$。
    • 效果:消除不规则的微抖,使圆弧、笔圈、连笔呈现如同绷紧橡皮筋般的紧凑内敛感;而在遇到折笔、顿笔($\Delta\theta \ge 70^\circ$)时拉力衰减至零,完整保全锋利转角。
  2. 非对称压感滞后回线 (Asymmetric Pressure Hysteresis):

    • 落笔按压时快速响应($\alpha_{\text{down}} \approx 0.85$),行笔和收笔时平滑衰减($\alpha_{\text{up}} \approx 0.45$)。
    • 消除屏幕电容感应的高频微跳,使笔画宽窄过度极为润泽。
  3. 真实压感数据集捕获与回放套件 (Dataset Studio):

    • 支持逐帧捕获 Apple Pencil 原生硬件微秒级时间戳、坐标、真实压感($p$)与倾斜度($tiltX, tiltY$)。
    • 导出为标准 JSON 数据集,支持在实验室中随时载入并通过不同纠偏/张力参数实时重演回放,用于算法调优拟合。

关键突破:非线性双端有界压感模型 (Dual-Bounded Non-Linear Pressure Transfer Functions)

在真实书写体验中,笔画粗细与 Apple Pencil 硬件压感 $p \in [0, 1]$ 绝非线性关系。人类手指对触觉阻力和按压力的心理感知严格遵循韦伯-费希纳定律 (Weber-Fechner Law) 与史蒂文斯幂律 (Stevens' Power Law):

  1. 轻写起点高 (High Baseline Floor):极轻笔尖接触($p \to 0$ 或 $0.05 \sim 0.15$)必须有坚实的基础保底粗细($50\% \sim 60\%$ 基准线宽),否则线条会如蛛丝般纤细、脆弱、打滑。
  2. 重写饱和封顶 (Ceiling Saturation):深重下压($p > 0.5$)必须有平滑的渐进封顶($120\% \sim 135\%$),防止墨迹过度肥大失控。
  3. 笔锋敏感区 (Working Dynamic Zone):汉字顿笔、收笔的粗细变化主要集中在 $p \in [0.15, 0.45]$ 的微力区间。

公式结构:
$$W(p) = \text{base} \cdot \left[ 1.0 + 2S \cdot \left( F + (C - F) \cdot g(p) - 1.0 \right) \right]$$
其中 $F$ 为保底粗细比(默认 55%),$C$ 为封顶饱和比(默认 130%),$S$ 为压力敏感度(默认 50%),$g(p) \in [0, 1]$ 为五类非线性传递函数模型:

模型名称数学映射 $g(p)$核心手感特征适用场景
对数压缩 (Logarithmic)$\frac{\ln(1 + \beta p)}{\ln(1 + \beta)}$ ($\beta \approx 8$)触觉感知定律,轻起步快,中段饱满,重压平滑贴顶GoodNotes 经典手感,日常中文字符流畅书写
Sigmoid S型阻尼$\frac{1}{1 + e^{-k(p - p_0)}}$ ($p_0 = 0.28$)中心拐点两侧收敛,中度运笔极舒展,深压物理阻尼软锁行草连笔、快写,防止大弧度笔画暴肥
双曲正切弹性 (Tanh)$\frac{\tanh(\alpha p)}{\tanh(\alpha)}$ ($\alpha \approx 3$)纯物理弹簧-阻尼器模型,下压如同按入厚实纸垫,有回弹骨力秀丽笔、书法顿笔
幂律软饱和 (Power Gamma)$p^\gamma$ ($\gamma \approx 0.38$)近零斜率极陡,起步瞬时有肉感,平滑凹面压缩圆珠笔、钢笔素描
分段双斜率膝点 (Piecewise Knee)$p \le 0.32$ 快速爬升;$p > 0.32$ 强阻尼平缓双折线拐点,出锋提笔与顿笔按压层次对比鲜明硬笔书法、正楷、方正字形

实测定案结论:多维混合调和律(终选对数压缩模型 Logarithmic)

“所有单一变量都不能带来质变,手感是多种物理与感知变量协同混合而成的。”

实测验证证明,GoodNotes 的原生手感并非来自单一神奇参数,而是由五个相互制约、相互补偿的维度构成的动态平衡体:

  1. 对数压感压缩 (Logarithmic, 终选):提供了“轻写高起点(55% 保底)与重压软封顶(130% 饱和)”的基石,使起笔不飘、重压不肥。
  2. 扁平切角笔尖 (Flatness 33% @ -40°):打破了圆管线条的单调,使汉字在运笔转折时天然自带“横细竖粗”的刚骨。
  3. 拉普拉斯曲线张力纠偏 (Laplacian Tension 50%):消除玻璃表面的打滑虚浮感,把连笔和圆弧紧绷收敛,又在转折尖角处自动释放。
  4. 出锋与笔尖锐度 (Tip Sharpness 75%):在提笔末端以二次曲线锥形收窄,使汉字的“勾、撇、捺、悬针”拥有尖锐锋芒。
  5. 动态速度变细与非对称滤波:快速挥洒时线宽自然变细,压感下压即刻响应、提笔润泽衰减。

最终黄金手感定案配置清单 (Final Golden Baseline Configuration)

export const GOODNOTES_GOLDEN_BASELINE_CONFIG = {
  engine: 'goodnotes',
  penType: 'fountain',             // 钢笔笔型
  size: 3.5,                       // 基准字号线宽: 3.5px
  tipSharpness: 0.66,              // 笔尖出锋锐度: 66%
  pressureSensitivity: 0.66,       // 硬件压力敏感: 66%
  flatness: 0.66,                  // 扁平切角: 66% (产生鲜明横细竖粗骨架)
  nibAngle: -0.6981,               // 笔身切角: -40°
  stabilization: 1.20,             // 画笔稳定: 120 (0-200 连续微调,对应 66 舒适黄金档,0.85+平滑映射到高阻尼)
  rectification: 1.00,             // 几何纠偏张力: 100% (圆弧草书完全收敛,折笔尖角不钝)
  wobbleFilter: 0.60,              // 玻璃高频微颤抑制: 60%
  // 非线性压感模型 (Logarithmic Weber-Fechner 对数起步)
  pressureModel: 'logarithmic',
  pressureFloor: 0.20,             // 轻写起步保底: 20% (轻下笔清脆有骨)
  pressureCeiling: 1.00,           // 重压饱和封顶: 100% (深重按压严密锁定,绝不肥厚失控)
  pressureGain: 1.80,              // 对数曲率增益: 1.8x (微力区快速过渡到饱满)
  // 直线抗抖与消除节瘤波纹 (第4格满血去波纹配置)
  headingFilter: 0.85,             // 笔向切角惯性滤波: 85% (彻底锁死椭圆自转闪烁)
  resampleStep: 2.2,               // 等距重采样降噪步长: 2.2px (滤除电容屏0.2px亚像素抖动)
  railTension: 0.70,               // 导轨趋势张力: 70% (直线自适应引力走直,折角瞬间释放)
  widthViscosity: 0.75,            // 粗细速度粘滞阻尼: 75% (抹平加减速顿挫脉冲)
  lateralDrag: 0.65                // 侧向位移摩擦阻尼: 65% (模拟纸张侧向行进阻力)
};

提笔抖动与突然变细的根因与像素级保真 (Zero-Jitter Active Canvas Commit)

  • 提笔抖动根因:提笔 pointerup 阶段若盲目调用全笔重绘(redrawCanvas),会导致当前笔划被拉普拉斯全量平滑重新拟合,破坏实时增量贝塞尔曲线的自然连接。
  • 提笔变细根因:全笔重绘时若缺失笔型线宽增益乘数(如钢笔笔尖的 1.15x 墨水延展),会导致整条线条在落笔与提笔瞬间粗细突跳。
  • 终极解决方案:采用 1:1 位图直接转移(mainCtx.drawImage(activeCanvas, 0, 0)),屏幕上运笔时眼睛看到什么,提笔就位图锁定什么,绝对零抖动、零跳跃、零变细。

工作台极简交互范式:四档微调 (Stepped Fine-Tuning: 0 / 33 / 66 / 100)

在全参数收敛锁定后,工作台交互彻底从“三十余个连续细分滑动条”重构为“极简画布 + 四档离散步长切换按钮”:

  • 核心参数按四档步长离散化:0% (关) / 33% (轻度) / 66% (默认舒适黄金档) / 100% (强力/满档)。
  • 画笔稳定度支持 0 ~ 200 放大区间,默认快捷键 66 严格锁定 120 舒适黄金档,并附带内联滑块支持无级连续微调。
  • 用户无需在毫米级滑块上反复对齐,直接点击分段 Toggle 按钮即可即时微调体验。
  • 原始全参数实验室归档为独立路由 /write/archive.html,主路由 /write/ 与极简工作台 /write/simplify 默认启用黄金配置。

直线抗抖与消除节瘤波纹 (Straight Stroke Anti-Wobble & De-Tamping)

1. 现象与物理/算法根因剖析 (Symptoms & Root Causes)

在 iPad 光滑玻璃表面快速下拉画竖笔或直线时,极易产生一连串肉眼可见的“粗细波纹 / 节瘤串珠 (Tamps / Camps)”,而 GoodNotes 在画直线时却异常顺直且带有明显的“玻璃阻尼感”。
通过捕获并实测分析真实 12 笔抖动直线数据集(ds_1789866707643_f94ed7,共 3,604 个物理采样点,平均点距仅 0.27px),发现节瘤波纹并非单纯是手抖,而是三种物理与几何现象的复合共振:

  1. 电容屏高频亚像素微颤 (Subpixel Capacitive Noise):

    • 屏幕采样率极高(单笔 148px 产生了 544 个采样点,点距小于 0.3px),手指与笔尖微颤会导致坐标横向微小左右晃动(实测单笔横向折返达 54 次)。
  2. 切向角翻滚放大效应 (Nib Angle Twisting & Flickering,核心根因):

    • 拟真书法引擎为了实现“横细竖粗”,笔尖采用了扁平椭圆截面(Flatness 33% @ -40°),瞬间线宽直接取决于切向角 $\theta = \operatorname{atan2}(dy, dx)$。
    • 当纵向运笔出现极微小的横向扰动($dx$ 在微米级波动)时,$\operatorname{atan2}$ 会在 $45^\circ \sim 135^\circ$ 之间急剧翻转跳跃(实测单笔角跳 $>30^\circ$ 出现 259 次!)。
    • 后果:笔尖椭圆在零点几毫米内疯狂来回旋转,把原本只有 0.3px 的横向微颤放大为数十倍的视觉粗细突变,形成如同“串珠/节瘤”般的锯齿波纹。
  3. 速度微顿引起的线宽脉冲 (Velocity Stutter):

    • 手部克服玻璃静摩擦力时的微小顿挫导致瞬时速度忽快忽慢,使速度变细函数产生连续的粗细膨胀与收缩。

2. 五维调直与去波纹消除算法 (5-Dimension De-Tamp Pipeline)

针对以上机理,在 GoodNotes 引擎管线中引入五维协同滤波机制:

[原生硬件点列] 
       │
       ▼
 [1. 间距降噪重采样 (Resample Step)] ────► 滤除 <2.2px 的电容屏高频亚像素抖动 (噪点消除率 87%)
       │
       ▼
 [2. 笔向切角惯性向量滤波 (Heading Filter)] ──► 二维方向向量 EMA 阻尼,彻底锁死切向角,消除切角旋转闪烁
       │
       ▼
 [3. 侧向位移阻尼 (Lateral Drag)] ───────► 沿局部正交法向量分解,压缩垂直行进方向的横向打滑
       │
       ▼
 [4. 导轨趋势张力 (Straight Rail Tension)] ─► 识别直线走势(<25°),自适应将微摆向局部弦轴心靠拢
       │
       ▼
 [5. 粗细粘滞阻尼 (Width Viscosity)] ────► 一阶惯性低通平抑速度突变,彻底抹平粗细节瘤
       │
       ▼
 [输出顺直且具阻尼的拟真笔迹]
  1. 笔向切角向量滤波 (Heading Filter, 推荐 85%):

    • 不使用离散标量角度,而是维护归一化的二维行进单位向量 $(\hat{u}_x, \hat{u}_y)$:
      $$\vec{v}_{\text{head}} \leftarrow \vec{v}_{\text{head}} \cdot \alpha_{\text{head}} + \Delta\vec{p} \cdot (1 - \alpha_{\text{head}})$$
    • 切角平滑过度,角度跳跃从 259 次降低到 18 次以下,笔尖椭圆截面保持稳定指向,彻底消除波纹节瘤。
  2. 等距降噪重采样 (Resample Step, 推荐 2.2px):

    • 沿笔划弧长设定步长门限 $d_{\text{step}} = 2.2\text{px}$,剔除亚像素微距离冗余点(544 点精简至 71 点),直接消除屏幕传感器的微观锯齿。
  3. 导轨趋势自适应引力 (Straight Rail Tension, 推荐 70%):

    • 实时计算局部弦向量 $\vec{AB}$ 与当前点 $P$ 的夹角。当夹角 $< 25^\circ$ 时判定为直线段走笔,将 $P$ 点向弦投影点拉回:
      $$P \leftarrow P + (\text{Proj}_{\vec{AB}}(P) - P) \cdot k_{\text{rail}}$$
    • 当遇到折线(夹角 $\ge 25^\circ$)时引力瞬时衰减为 0,确保起笔顿笔与转折尖锐。
  4. 粗细粘滞阻尼 (Width Viscosity, 推荐 75%):

    • 线宽一阶低通滤波 $w_t = w_{t-1} \cdot (1 - \alpha_v) + w_{\text{target}} \cdot \alpha_v$,吸收运笔速度微颤。
  5. 侧向位移阻尼 (Lateral Drag, 推荐 65%):

    • 分解运笔位移为切向分量 $d_\parallel$ 与法向分量 $d_\perp$,将法向横摆衰减 $d'_\perp = d_\perp \cdot (1 - 0.72 k_{\text{lat}})$,产生极具质感的“纸张侧向摩擦阻力”。

3. 直线抗抖专属工作台与 4 格矩阵对比 (Straight Stroke Studio)

已独立上线子路由工作台:https://6767.chat/write/straight.html

  • 同屏 4 格对照:

    • 格 1:原生抖动未滤波 (54 次横向折返、强烈波纹节瘤)
    • 格 2:仅笔向惯性滤波 (切向角锁死、消除切角闪烁波纹)
    • 格 3:笔向 + 间距降噪 (消除 0.2px 传感器高频锯齿串珠)
    • 格 4:GoodNotes 满血调直 (导轨张力 + 侧阻 + 粗细粘滞,线条顺直收敛)
  • 实时五维滑块:可直接在 iPad 屏幕上随写随调,支持一键载入实录 12 笔抖动直线数据与导出代码配置。

跨端手写踩坑与手势架构实战 (2026-09 生产落地总结)

1. Apple Pencil 2 偶发丢失捕获断笔陷阱 (WebKit Lost Pointer Capture Pitfall)

  • 现象 (Symptoms):Apple Pencil Pro 在 iPadOS 上运笔平滑,但在 Apple Pencil 2(或部分低压感手写笔)快速连笔、手掌边缘微触屏幕时,笔画出现明显的断断续续、吞笔画或被切成碎断点。
  • 根因分析 (Root Cause):

    • W3C 指针捕获规范(Pointer Capture API)中,通过 setPointerCapture(pointerId) 锁定事件源;但在 iOS WebKit 实现中,当手掌有轻微边缘触碰或手指手势引擎介入判断时,WebKit 会单方面向 canvas 抛出 lostpointercapture 事件,即使此时笔尖并未离开屏幕物理表面。
    • 旧有手写实现若将 lostpointercapture 监听视同“提笔收笔”(调用 finalizeStroke 并重置 isDrawing = false),后续持续产生的物理 pointermove 采样点就会因校验不通过而被直接丢弃,导致书写被掐断。
  • 治理策略 (Resolution):

    • 彻底移除 lostpointercapture 强制收笔逻辑。
    • 收笔提笔出口严格且仅收敛于两种确凿场景:真实提笔的 pointerup 事件,以及系统级确凿中断的 pointercancel 事件。
    • 在 pointermove 中持续维护活跃指针,杜绝 WebKit 误报丢捕获带来的非预期截断。

2. 无限可写画卷手势系统与手指导航模式 (Infinite Canvas & Touch Gesture Architecture)

  • 设计权衡 (Trade-off):

    • 手写板传统模式往往直接允许手指落墨,导致手掌误触(Palm Rejection 偶发漏检)在纸面上留下大量杂点碎墨,且无法便捷移动与缩放画布。
  • 两级手势状态机:

    1. 手势导航模式(默认推荐):

      • 手指(pointerType === 'touch')绝对不落墨。
      • 单指/多指拖拽:驱动视口平移($panX \leftarrow panX + dx, panY \leftarrow panY + dy$);在嵌入文档(如 PDF)模式下则优雅平移文档滚动容器。
      • 双指捏合(Pinch-to-Zoom):以双指几何中心点为锚点无极缩放(0.2x ~ 5.0x),并同步叠加中心点位移量($zoomAndPan$)。
      • 仅触控笔书写:笔尖接触(pointerType === 'pen')方可落墨。
    2. 允许手指书写模式(可选切换):

      • 单指落墨书写。
      • 视口平移与缩放转移至双指拖拽与双指捏合接管;一旦检测到 $\ge 2$ 指触碰,立即丢弃单指起笔的残墨(cancelActiveStroke),实现无缝手笔分离。
    3. 世界坐标系统一 (World vs Screen Coordinates):

      • 笔画采样点统一存储为不受平移缩放影响的世界真实坐标($x_{\text{world}} = (x_{\text{screen}} - panX) / zoom$)。
      • 画布仅使用 Canvas 2D 变换矩阵(dpr * zoom, panX * dpr)渲染,平移缩放具有零重绘计算开销与硬件抗锯齿优势。
      • 导出图片(PNG)时自动根据世界坐标中所有笔画的实际包围盒(Bounding Box)进行智能自适应裁剪,输出 2x 高清位图。

3. 旧版 Android / 华为平板 WebView 现代 API 缺失与动态懒加载 (Legacy WebView Compatibility)

  • 现象:现代浏览器(iPad Safari、桌面 Chrome)运行正常,但在华为平板等搭载 HarmonyOS 4.0 早期 Chromium M99 内核的设备上打开应用直接白屏。
  • 根因:

    1. 现代 JavaScript 运行环境 API 缺失:Chromium <119 缺少 Promise.withResolvers,Chromium <126 缺少 URL.parse,以及缺少 structuredClone 等,导致 SPA 框架在初始化执行顶层模块时抛出全局 TypeError,整页停滞。
    2. 现代重型引擎首屏静态捆绑(Static Import):如 pdfjs-dist 等现代 PDF 引擎体积大(>2.5MB)且包含现代高级语法,在首屏未经拆包直接加载时容易导致低内存/低版本内核直接崩溃。
  • 治理策略:

    1. 在 HTML 最早期注入内联 Polyfill 兜底与全局未捕获白屏诊断卡片,并在入口 main.ts 最首行挂载 Polyfill 补丁垫片。
    2. 动态按需拆包(Dynamic Import):将 PDF 引擎从首屏关键路径中剥离,仅在用户实际打开 PDF 文件时才异步动态载入(await import('./pdfViewer')),首屏关键 JS chunk 体积直接减小 500KB+,彻底杜绝首屏内核崩溃。

边界

  • 识别(墨迹→文本)比捕获难一个量级:on-device 用 transformers.js + TrOCR,或云 OCR;MVP 建议先只做捕获 + 展示。
  • Android Chrome 同样支持 Pointer Events + 触控笔(S Pen 等)。

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Frontend