// @drama/render-pixi —— Renderer 接口的 PixiJS v8 后端,公共面。 // // 唯一公共入口(架构「禁止深导入」红线)。只导出 createPixiRenderer + CharacterSkin/SlotSkin // typedef(render-pixi §3 / §5.6 公共面最小化)。 // // Pixi 只在本包出现(render-pixi §5.2)。本包对外暴露的方法签名零 Pixi 入参:core 调 // applyActorPose/applyCamera 等时只传 SlotTransform / CameraRenderState / string / number。 // PIXI 命名空间在工厂处一次性解析(不外溢到接口): // - 若 `opts.PIXI` 给了就用它(测试注入 stub、或调用方已持有的命名空间); // - 否则动态 import 'pixi.js'。动态而非顶层静态 import,是为了让无 GPU 的 headless // 单测(注入 stub Sprite)无需安装 / 加载真实 pixi.js 即可跑 §8 的纯映射用例。 import { createPixiRenderer as _createPixiRenderer } from './renderer.js' /** * @typedef {{ * rig: import('@drama/rig').RigDefinition, * PIXI?: *, * loadTexture?: (url:string)=>Promise<*>, * resolveEffect?: (name:string)=>(import('./effects.js').EffectDef|null), * faceFrameDt?: number, * }} RendererOpts 工厂注入项:rig 必填;PIXI 在工厂处一次注入(不外溢到接口)。 */ /** * @typedef {import('@drama/core').Renderer & { * addActor:(actorId:string, skin:CharacterSkin, placement:object)=>void, * removeActor:(actorId:string)=>void, * loadScene:(def?:object)=>Promise, * updateEffects:(dtMs:number)=>void, * }} PixiRenderer @drama/core Renderer(零 Pixi 入参)+ 出场 / 换场扩展方法 */ /** * 创建满足 @drama/core Renderer 接口的 PixiJS 渲染后端。 * @param {import('pixi.js').Application} app 已 init 的 Pixi Application(由 player-vue / composition root 建) * @param {RendererOpts} opts * @returns {PixiRenderer} */ export function createPixiRenderer(app, opts) { if (opts && opts.PIXI) return _createPixiRenderer(app, opts) throw new Error( 'createPixiRenderer: opts.PIXI is required. Pass the imported `* as PIXI` namespace ' + '(e.g. `import * as PIXI from "pixi.js"`). Renderer 方法签名仍零 Pixi——PIXI 仅在工厂处一次注入。', ) } /** * 与 createPixiRenderer 等价,但自动 `import('pixi.js')` 注入 PIXI(浏览器 / 已装 pixi.js 环境)。 * 给 player-vue / studio 直接用;headless 单测走 createPixiRenderer + 注入 stub。 * @param {import('pixi.js').Application} app * @param {Omit} opts 同 createPixiRenderer(无需传 PIXI) * @returns {Promise} */ export async function createPixiRendererAuto(app, opts) { const PIXI = await import('pixi.js') return _createPixiRenderer(app, { ...opts, PIXI }) } // ───────────────────────── 公共形状契约(render-pixi §3) ───────────────────────── /** * @typedef {Object} CharacterSkin 渲染需要的贴皮数据(来自 @drama/assets 的 character 出包)。 * @property {string} rigId * @property {Record} parts slot 名 -> 该部件贴皮 */ /** * @typedef {Object} SlotSkin * @property {string=} url 普通部件贴图 * @property {{x:number,y:number}=} anchor * @property {number=} scale * @property {number=} rotation * @property {boolean=} mirror * @property {number=} zOrder 覆盖 slot 默认层级 * @property {{x:number,y:number}=} bonePos 关节位置覆盖(对齐用) * @property {Record=} emotions face 专用情绪帧 * @property {number=} talkFps 口型轮播帧率(face 用) */