feat: 支持静态组合立绘与相对动画 - #1027
Open
starrybamboo wants to merge 3 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds engine support for static composite “Character” figures (managed by a new character script command) and introduces structured animation resources whose frames can be interpreted relative to a target’s resolved/base transform, enabling deferred (async) figure delivery while preserving animation behavior.
Changes:
- Added a new
characterscript command and a Character composition pipeline (template parsing/validation, async image composition, and Pixi delivery sync). - Added “relative frame” animation support via structured animation resources and runtime frame composition on top of a resolved base transform.
- Extended figure/animation state to preserve a
baseTransformfor deferred presentation replay.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/webgal/src/Core/parser/sceneParser.ts | Registers the new character script tag in the runtime script map. |
| packages/webgal/src/Core/Modules/stage/stageInterface.ts | Adds baseTransform to stage animation settings to preserve a resolved baseline transform. |
| packages/webgal/src/Core/Modules/animations.ts | Adds structured animation resource parsing and relative-frame marking via createUserAnimation. |
| packages/webgal/src/Core/Modules/animationFunctions.ts | Composes relative animation frames against a computed/resolved source transform (incl. optional override). |
| packages/webgal/src/Core/initializeScript.ts | Uses createUserAnimation when loading user animation JSON resources. |
| packages/webgal/src/Core/gameScripts/character.ts | Implements the character script command and delegates presentation to changeFigure. |
| packages/webgal/src/Core/gameScripts/changeFigure.ts | Persists baseTransform into animation settings and refactors transform baseline handling. |
| packages/webgal/src/Core/controller/stage/pixi/syncPixiStageState.ts | Integrates Character figure sync and deferred presentation into Pixi stage synchronization. |
| packages/webgal/src/Core/controller/scene/sceneInterface.ts | Adds commandType.character to the runtime command enum. |
| packages/webgal/src/Core/character/characterTemplate.ts | Defines/validates character templates and resolves component/preset selections into ordered layers. |
| packages/webgal/src/Core/character/characterImageComposer.ts | Loads component images and composes them into a single bitmap for delivery. |
| packages/webgal/src/Core/character/characterFigureTarget.ts | Resolves and enumerates figure targets (positional slots + free figures) for Character management. |
| packages/webgal/src/Core/character/characterFigureSourceSync.ts | Handles async composition requests and applies only the latest result per target (epoch gating). |
| packages/webgal/src/Core/character/characterFigureSource.ts | Serializes/parses stable Character figure sources and collects Character targets from stage state. |
| packages/webgal/src/Core/character/characterFigureService.ts | Loads/validates templates and caches in-flight + completed compositions in memory. |
| packages/webgal/src/Core/character/characterDeferredPresentationRuntime.ts | Replays deferred enter animations using stored baseTransform when the composed image arrives. |
| packages/parser/src/interface/sceneInterface.ts | Adds commandType.character to the parser-side command enum. |
| packages/parser/src/config/scriptConfig.ts | Registers character as a supported script token in the parser config. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+200
to
+202
| if (sourceUrl && parseCharacterFigureSource(sourceUrl)) { | ||
| return; | ||
| } |
Comment on lines
+49
to
+54
| for (const target of listFigureTargets(state)) { | ||
| const source = parseCharacterFigureSource(target.source); | ||
| if (source) { | ||
| targets.push({ key: target.key, position: target.position, source }); | ||
| } | ||
| } |
Comment on lines
+23
to
+27
| for (const { layer, image } of loadedLayers) { | ||
| const { width, height } = resolveDrawSize(layer, image); | ||
| context.drawImage(image.source, layer.x, layer.y, width, height); | ||
| } | ||
| return canvas.toDataURL('image/png'); |
Comment on lines
+20
to
+29
| export function createUserAnimation(name: string, resource: UserAnimationResource): IUserAnimation { | ||
| if (Array.isArray(resource)) { | ||
| return { name, effects: resource }; | ||
| } | ||
| return { | ||
| name, | ||
| effects: resource.effects, | ||
| ...(resource.frameMode !== 'absolute' ? { frameMode: 'relative' as const } : {}), | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
关联 #1010,
概要
本 PR 提交以下引擎侧能力:
character脚本管理静态组合立绘;character脚本每条角色声明包含角色名,以及本次需要使用的完整、有序部件列表:
可以按角色名清除,也可以清除所有由
character管理的立绘:同名角色同时只能占用一个 Figure Target。将角色移动到其他位置或 ID 时,会先清除旧目标,再更新新目标。
这个可能需要商榷,我个人是希望能这样的,这样就不用手动管立绘的退场了。(方便AI写脚本)
位置、ID、transform、transition、duration、z-index 与 blend mode 等行为继续委托给现有
changeFigure链路。角色模板
模板固定从以下路径加载:
最小的 Version 1 模板示例:
{ "Version": 1, "canvas": { "width": 1600, "height": 3000 }, "components": { "body": { "src": "body.webp", "x": 0, "y": 0 }, "uniform_summer": { "src": "uniform-summer.webp", "x": 0, "y": 0, "scale": 0.8 }, "face_smile": { "src": "faces/smile.webp", "x": 0, "y": 0, "width": 512, "height": 512 } }, "presets": { "summer_uniform": ["body", "uniform_summer"] } }部件与预设会按声明顺序递归展开,重复引用会被保留;后出现的图层绘制在先出现的图层之上。
部件可以使用图片原始尺寸、正数等比
scale,或成对指定width与height。目前支持静态 PNG、WebP、JPG/JPEG,部件路径必须保持在角色目录内。模板、已完成的组合结果和正在执行的合成任务均使用内存缓存。加载与合成不会阻塞剧本流程。
舞台状态与存档中保存的是稳定的角色逻辑来源。生成结果作为普通图片交付,因此
figure.json不会进入 Live2D 资源解析链路。相对动画资源
原有的纯帧数组动画格式保持不变,但加载后直接使用相对语义:
[ { "position": { "x": 0, "y": -30 }, "duration": 100, "ease": "linear" } ]动画帧会与目标已解析的 transform 组合:
position与rotation使用加法;scale与alpha使用乘法;这是对原有数组格式的语义迁移,不新增
{ "effects": [...] }包装格式,也不增加用户侧frameMode或绝对帧开关。只有引擎内部生成且未标记的 transform、进场与退场时间线继续使用绝对值,避免内部关键帧被重复叠加。为什么放在同一个 PR
组合立绘复用了 Figure 的变换与动画,但最终 Pixi 图片是在脚本完成舞台状态演算后才异步生成的。
图片准备完成时,延迟演出必须以命令执行时解析出的原始 transform 为基准重新构造动画。因此,相对动画帧映射与组合立绘交付会在同一个演出边界相交:异步替换 Pixi 图片后,仍需保留 Figure 的位置基准并重放其入场动画。
将两者放在同一个 PR,可以继续复用统一的 Figure 动画链路,不需要增加一套 Character 专用动画实现。
兼容性与范围
localforage、预取/预热线路或任何新依赖;验证
yarn parser:test --run:2 个测试文件、29 个测试通过;yarn build:Parser Rollup、WebGAL TypeScript 与 Vite 生产构建通过;git diff --check:通过;BA-jump-twice相对动画结束后回到原 transform 基准位置。