Add web-side player and complete MVP implementation of Source Editor#3592
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3592 +/- ##
==========================================
- Coverage 82.57% 82.55% -0.03%
==========================================
Files 707 707
Lines 91382 91382
Branches 25871 25871
==========================================
- Hits 75459 75438 -21
- Misses 10435 10441 +6
- Partials 5488 5503 +15 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
|
||
| // Keyboard shortcut: Space for play/pause | ||
| document.addEventListener('keydown', (e: KeyboardEvent) => { | ||
| if (e.code !== 'Space') return; |
There was a problem hiding this comment.
这里 keydown 仅处理 Space。方向键 ←/→(上一帧/下一帧)以及 editor 的 L 之外没有其它键盘绑定,但 PR 描述与 README 均声称"快捷键:Space / ← / → / L"。建议补上 ArrowLeft/ArrowRight 调用 stepFrame(-1)/stepFrame(1),或修正文案。
There was a problem hiding this comment.
已补上 ArrowLeft/ArrowRight 处理,index.ts 里 keydown 现在支持 Space(播放/暂停)+ ArrowLeft/ArrowRight(上/下一帧),L 键切换编辑器保留在 editor/index.ts。同时避开了 range slider 聚焦时的键冲突。感谢指出。
|
|
||
| // Encodes XML, reparses and redraws the view. Shared by the editor's Apply | ||
| // and Save actions. Returns '' on success, otherwise an error message. | ||
| const applyXmlToView = (xmlText: string): string => { |
There was a problem hiding this comment.
applyXmlToView 仅执行 parsePAGX→buildLayers→draw,缺少 loadPAGXData 中的 updateSize() 与 showPlaybackBar()。若编辑后 XML 的画布尺寸或时长(静态↔动画)发生变化,画布尺寸不会刷新、播放条显隐与时长显示会停留在旧状态。建议重载后复用这两步。
There was a problem hiding this comment.
已抽出 refreshUIAfterReparse()(内部调用 updateSize() + showPlaybackBar()),loadPAGXData 和 applyXmlToView 都复用。这样编辑后 XML 修改画布尺寸或从静态图切换到动画时,backing store、播放条显隐、时长/帧显示都会一起刷新。感谢指出。
| bool isPlaying() const; | ||
| int64_t currentTimeMicros() const; | ||
| int64_t durationMicros() const; | ||
| float currentFrameRate() const; |
There was a problem hiding this comment.
currentFrameRate() 实际只返回动画固定的 frameRate(),current 前缀易被误解为"实时测得 FPS"。建议改名为 frameRate() 与底层 PAGAnimation::frameRate() 保持一致。
There was a problem hiding this comment.
同意,"current" 前缀确实容易被理解成"实时测得 FPS",实际只是文件固定的 PAGAnimation::frameRate()。已重命名 currentFrameRate() → frameRate(),同步改了 C++ 声明/实现、embind 导出(_frameRate)、TS 类型(_frameRate())、pagx-view.ts 包装方法以及 playground 三处调用点。
| // when looping keep playing for the next cycle, otherwise park on the first frame so a | ||
| // finished single pass resets to the start instead of freezing on the last frame. | ||
| if (duration > 0) { | ||
| defaultAnimation->setCurrentTime(0); |
There was a problem hiding this comment.
单次播放(非循环)自然结束时回退到第 0 帧并暂停,配合上层 100ms 定时器会使进度条/时间跳回 0.00s,而非停在最后一帧。多数播放器习惯停在末帧,请确认该行为是否符合预期。
| // Player-level loop switch that overrides the file's loop mode at cycle boundaries: the engine | ||
| // still drives in-cycle motion (including PingPong mirroring), but whether a completed cycle | ||
| // repeats or stops is decided here instead of by the file's LoopMode. Defaults to looping. | ||
| bool loopEnabled = true; |
There was a problem hiding this comment.
loopEnabled 默认 true,且 loadPAGXData 每次加载都 setLoop(true),导致即使文件标记为 Once 也会被强制循环、忽略文件自身 LoopMode。请确认这是预期的产品行为。
| return 0.0f; | ||
| } | ||
|
|
||
| void PAGXView::setCurrentTimeMicros(int64_t micros) { |
There was a problem hiding this comment.
setCurrentTimeMicros 只对 defaultAnimation 做绝对 seek,而 scene(嵌套自动播放合成)只按 delta 推进、无法随之定位。拖动进度条 seek 后,主时间轴与嵌套合成画面会出现错位。MVP 可接受,建议记录为已知限制。
There was a problem hiding this comment.
MVP 阶段接受此限制。已在 PAGXView.cpp 函数上方补了 known-limitation 注释块。
| function hidePlaybackUI(): void { | ||
| const canvas = document.getElementById('pagx-canvas') as HTMLCanvasElement; | ||
| const toolbar = document.getElementById('toolbar') as HTMLDivElement; | ||
| const playbackBar = document.getElementById('playback-bar') as HTMLDivElement; |
There was a problem hiding this comment.
这里对 playback-bar 直接 as HTMLDivElement 后使用 .classList,未判空,而 showPlaybackBar 等处有判空,风格不一致。若后续 DOM 结构调整易 NPE,建议统一判空。
There was a problem hiding this comment.
已改用可选链 document.getElementById('playback-bar')?.classList.add('hidden'),canvas / toolbar 一起统一到这种风格。
| const canvas = document.getElementById('pagx-canvas') as HTMLCanvasElement; | ||
| const toolbar = document.getElementById('toolbar') as HTMLDivElement; | ||
| const navBtns = document.getElementById('nav-btns') as HTMLDivElement; | ||
| const playbackBar = document.getElementById('playback-bar') as HTMLDivElement; |
There was a problem hiding this comment.
同上:goHome 中对 playback-bar 未判空即使用 .classList,建议与其它位置统一判空处理。
There was a problem hiding this comment.
已同 #7 一起改,goHome 里的 canvas / toolbar / nav-btns / playback-bar 四处全部改成可选链的风格,与 showPlaybackBar 一致。
| // Detect the pagx-viewer arch by checking which glue file was copied into wasm-mt/. | ||
| // This must stay in sync with prebuild.js's auto-detection logic. | ||
| function detectGlueInfix() { | ||
| if (process.env.ARCH === 'wasm') return '.st'; |
There was a problem hiding this comment.
这里用 ARCH === "wasm" 表示单线程(多线程反而是 wasm-mt),而 prebuild.js 用 --arch st,两处关键字不一致且 wasm 作为"单线程"别名易误解。建议统一命名以提升可读性。
There was a problem hiding this comment.
已统一。rollup.js 和 prebuild.js 现在都用 ARCH=st|mt,package.json scripts 里也是同一套词汇,三处一致。
| "@codemirror/state": "^6.7.1", | ||
| "@codemirror/view": "^6.43.6", | ||
| "@lezer/highlight": "^1.2.3", | ||
| "codemirror": "^6.0.2", |
There was a problem hiding this comment.
codemirror 元包已重导出上面列出的 @codemirror/* 子包。同时显式列出两者需保证版本区间一致,否则可能引入重复实例;若无锁版本需要可考虑只保留其一。
There was a problem hiding this comment.
已删除 codemirror 元包,只保留显式列出的 @codemirror/state、@codemirror/view、@lezer/highlight 等子包,避免版本漂移导致的重复实例。
|
补充(非代码行,故留普通评论):PR 描述称"移除播放重构后已无引用的 GridBackground 与 ImagePatternMatrixCalculator 两个模块",但这两个文件并不在本 PR 的 diff 中,且在 PR HEAD 的 pagx-viewer/src/cpp 下也已不存在——应是此前已在 main 中删除。建议修正描述以免误导。 |
概述
在
pagx-playground(Web 预览站点)中新增两项面向用户的功能,并在pagx-viewer上补齐相应的播放控制 API。变更范围仅限playground/pagx-playground/与playground/pagx-viewer/,未改动 libpag的公共 API、原生代码或 exporter。
变更内容
pagx-viewer:暴露播放 APIPAGXView新增(C++ / Emscripten binding / TS 包装 /.d.ts):play()/pause()/isPlaying()currentTimeMicros()/durationMicros()/currentFrameRate()setLoop()/isLoop()int64_t返回值统一用double传出(emscripten::bind不支持 64 位整数)。pagx-playground:播放控制条pagx-playground:源码编辑器src/editor/(SourceEditor.ts+index.ts+styles.ts)。L快捷键开关,可拖拽调宽(使用 pointer capture,拖出浏览器窗口不卡死)。
撤销/重做、选中匹配高亮;保留浏览器原生
Ctrl+F。PAGXView,不写文件)、Save(校验 + 重载 + 写回文件)。DOMParser校验 XML,失败时 toast 提示首个错误行。Ctrl+Z穿越文件。window.pagx:loaded事件 +onApply/onSave回调对外通信,不与 playground 主流程耦合。
构建 / 基础设施
pagx-playground新增@codemirror/*与@lezer/highlight依赖,rollup 配置同步更新。
pagx-viewer目录结构调整。TODO
源码编辑器 MVP 已合入,以下改进将在后续 PR 中跟进:
双击某节点后再进入可编辑态,避免误改。
反之在编辑器中定位节点时高亮画布上对应的渲染对象。
reparse/reload 路径,避免长文件下的输入卡顿。
行内标记(gutter marker + 波浪线),并覆盖 schema 层的语义校验
(如未知标签、必填属性缺失)。