@firetable/project-xiaochun 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-CN.md +24 -14
- package/README.md +24 -14
- package/dist/avatar-element.d.ts +10 -4
- package/dist/chunks/{chunk-T6EHFEEZ.js → chunk-HZ2ADKG7.js} +39 -8
- package/dist/chunks/chunk-HZ2ADKG7.js.map +7 -0
- package/dist/chunks/{chunk-KKRZ3SUD.js → chunk-RHQW4QZH.js} +86 -3
- package/dist/chunks/chunk-RHQW4QZH.js.map +7 -0
- package/dist/chunks/{chunk-KQSKHPVF.js → chunk-UWL65W7D.js} +136 -10
- package/dist/chunks/chunk-UWL65W7D.js.map +7 -0
- package/dist/client.d.ts +64 -5
- package/dist/element.cjs +206 -12
- package/dist/element.cjs.map +2 -2
- package/dist/element.js +4 -4
- package/dist/index.cjs +247 -13
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +20 -6
- package/dist/index.js.map +1 -1
- package/dist/loader.global.js +2 -2
- package/dist/loader.global.js.map +3 -3
- package/dist/protocol.cjs +86 -3
- package/dist/protocol.cjs.map +2 -2
- package/dist/protocol.d.ts +104 -3
- package/dist/protocol.js +18 -4
- package/dist/react.cjs +190 -14
- package/dist/react.cjs.map +2 -2
- package/dist/react.d.ts +6 -0
- package/dist/react.js +23 -9
- package/dist/react.js.map +2 -2
- package/package.json +2 -2
- package/dist/chunks/chunk-KKRZ3SUD.js.map +0 -7
- package/dist/chunks/chunk-KQSKHPVF.js.map +0 -7
- package/dist/chunks/chunk-T6EHFEEZ.js.map +0 -7
package/dist/react.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/react.ts", "../src/protocol.ts", "../src/gesture-box.ts", "../src/client.ts"],
|
|
4
|
-
"sourcesContent": ["'use client';\n/**\n * react.ts \u2014 React \u5C01\u88C5 (\u5B50\u8DEF\u5F84\u5BFC\u51FA `@firetable/project-xiaochun/react`, react \u662F\u53EF\u9009 peerDependency)\u3002\n *\n * import { Xiaochun, useXiaochun } from '@firetable/project-xiaochun/react';\n * <Xiaochun ref={ref} width={320} height={480} transparent onReady={...} />\n * ref.current?.say('\u4F60\u597D') / ref.current?.speakAudio(arrayBuffer)\n *\n * \u8BBE\u8BA1\u8981\u70B9:\n * - \u517C\u5BB9 React 18 / 19 (\u53EA\u7528 forwardRef / useImperativeHandle / useEffect / useState / createElement, \u4E0D\u5199 JSX \u2192 \u65E0\u9700 jsx \u8FD0\u884C\u65F6)\u3002\n * - SSR / Next.js \u5B89\u5168: \u6587\u4EF6\u5934 'use client'; \u670D\u52A1\u7AEF\u53EA\u6E32\u67D3\u4E00\u4E2A**\u56FA\u5B9A\u5C3A\u5BF8**\u7684\u7A7A <div> (\u4E0D\u4EA7\u751F CLS), iframe \u53EA\u5728\u5BA2\u6237\u7AEF effect \u91CC\u521B\u5EFA\u3002\n * - StrictMode \u53CC\u6302\u8F7D\u4E0D\u6CC4\u6F0F: effect cleanup \u4E00\u5B9A destroy(); lazy \u6A21\u5F0F\u4E0B\u5047\u6302\u8F7D\u6839\u672C\u4E0D\u4F1A\u521B\u5EFA iframe\u3002\n * - \u4E0D\u6539\u53D8\u4E3B\u5165\u53E3\u4F53\u79EF: \u4E3B\u5165\u53E3 (index) \u4E0D\u5F15\u7528\u672C\u6587\u4EF6, \u4E0D\u7528 React \u7684\u4EBA\u4E0D\u4F1A\u591A\u62C9\u4E00\u4E2A\u5B57\u8282\u3002\n * - \u521B\u5EFA\u671F\u9009\u9879 (src/lazy/position/\u2026) \u53D8\u5316\u4F1A\u91CD\u5EFA\u5B9E\u4F8B; lang / outfit / scene / paused / mic / width / height / draggable / resizable / borderRadius \u53D8\u5316\u5219\u70ED\u66F4\u65B0\n * (\u4E0D\u91CD\u5EFA iframe, effect \u91CC\u8C03 setter)\u3002\u5C24\u5176 width / height: \u7528\u6237\u7F29\u653E (resizable) \u540E\u5BBF\u4E3B\u628A\u65B0\u5C3A\u5BF8\u5199\u56DE props \u4E5F\u4E0D\u4F1A\u91CD\u5EFA, \u6A21\u578B / \u52A8\u753B\u72B6\u6001\u90FD\u4FDD\u7559\u3002\n */\nimport { createElement, forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';\nimport type { CSSProperties, ForwardedRef, ReactElement } from 'react';\nimport { createXiaochun } from './client';\nimport type {\n XiaochunAudioOptions,\n XiaochunAudioSource,\n XiaochunAudioStream,\n XiaochunEvents,\n XiaochunInstance,\n XiaochunOptions,\n} from './client';\nimport { isXcId } from './protocol';\nimport type { XcConfig, XcExpressionPayload, XcMotionPayload, XcOutfitInfo, XcPrefetchedPayload, XcSceneInfo, XcStatePayload } from './protocol';\n\n/** \u4E8B\u4EF6\u56DE\u8C03 (\u5168\u90E8\u53EF\u9009)\u3002\u5F15\u7528\u53D8\u5316\u4E0D\u4F1A\u91CD\u5EFA\u5B9E\u4F8B (\u5185\u90E8\u7528 ref \u6301\u6709\u6700\u65B0\u503C)\u3002 */\nexport interface XiaochunCallbacks {\n /** xc.ready \u63E1\u624B\u6210\u529F\u3002 */\n onHandshake?: (p: XiaochunEvents['handshake']) => void;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210 (= xc.loaded)\u3002 */\n onReady?: (p: XiaochunEvents['ready']) => void;\n onProgress?: (p: XiaochunEvents['progress']) => void;\n onState?: (p: XiaochunEvents['state']) => void;\n onStt?: (p: XiaochunEvents['stt']) => void;\n onUtterance?: (p: XiaochunEvents['utterance']) => void;\n onHitRegion?: (p: XiaochunEvents['hit-region']) => void;\n /** \u670D\u88C5\u5DF2\u751F\u6548 (\u542B\u9996\u6B21\u52A0\u8F7D initial:true)\u3002 */\n onOutfitChanged?: (p: XiaochunEvents['outfit-changed']) => void;\n /** \u573A\u666F\u5DF2\u751F\u6548 (\u542B\u63E1\u624B\u540E\u4E0A\u62A5\u7684\u5F53\u524D\u573A\u666F initial:true)\u3002 */\n onSceneChanged?: (p: XiaochunEvents['scene-changed']) => void;\n onError?: (p: XiaochunEvents['error']) => void;\n onDestroy?: () => void;\n /** \u7528\u6237\u62D6\u52A8\u5934\u50CF (draggable): start / move / end, \u4F4D\u7F6E\u5DF2\u9650\u5E45 (\u89C6\u53E3\u5750\u6807)\u3002 */\n onMove?: (p: XiaochunEvents['move']) => void;\n /** \u7528\u6237\u7F29\u653E\u5934\u50CF (resizable): start / move / end, \u5C3A\u5BF8\u5DF2\u9650\u5E45\u3002\u60F3\u628A\u5C3A\u5BF8\u540C\u6B65\u8FDB\u81EA\u5DF1\u7684\u72B6\u6001, \u5728 phase === 'end' \u65F6\u5199\u56DE width / height \u5373\u53EF (\u4E0D\u4F1A\u91CD\u5EFA iframe)\u3002 */\n onResize?: (p: XiaochunEvents['resize']) => void;\n}\n\nexport interface XiaochunHookOptions extends Omit<XiaochunOptions, 'container'>, XiaochunCallbacks {\n /** \u53D7\u63A7\u6682\u505C: true = xc.pause, false = xc.resume\u3002 */\n paused?: boolean;\n /** \u53D7\u63A7\u9EA6\u514B\u98CE: true = \u5F00\u59CB\u542C (\u9996\u6B21\u4F1A\u52A0\u8F7D STT), false = \u505C\u3002 */\n mic?: boolean;\n}\n\nexport interface UseXiaochunResult {\n /** \u7ED1\u5B9A\u5230\u4F60\u81EA\u5DF1\u7684\u5BB9\u5668: `<div ref={containerRef} style={{ width: 320, height: 480 }} />`\u3002\u56DE\u8C03 ref, React 18/19 \u901A\u7528\u3002 */\n containerRef: (el: HTMLElement | null) => void;\n /** \u5E95\u5C42 SDK \u5B9E\u4F8B; \u670D\u52A1\u7AEF / \u5C1A\u672A\u6302\u8F7D / \u5DF2\u5378\u8F7D\u65F6\u4E3A null\u3002 */\n client: XiaochunInstance | null;\n /** \u6A21\u578B\u662F\u5426\u52A0\u8F7D\u5B8C\u6210\u3002 */\n ready: boolean;\n /** \u6700\u8FD1\u4E00\u6B21 xc.state\u3002 */\n state: XcStatePayload | null;\n}\n\nconst EVENT_MAP: Array<[keyof XiaochunEvents, keyof XiaochunCallbacks]> = [\n ['handshake', 'onHandshake'],\n ['ready', 'onReady'],\n ['progress', 'onProgress'],\n ['state', 'onState'],\n ['stt', 'onStt'],\n ['utterance', 'onUtterance'],\n ['hit-region', 'onHitRegion'],\n ['outfit-changed', 'onOutfitChanged'],\n ['scene-changed', 'onSceneChanged'],\n ['error', 'onError'],\n ['move', 'onMove'],\n ['resize', 'onResize'],\n ['destroy', 'onDestroy'],\n];\n\n/**\n * \u5728\u4F60\u81EA\u5DF1\u7684\u5BB9\u5668\u91CC\u521B\u5EFA / \u9500\u6BC1\u4E00\u4E2A\u5C0F\u8822\u5B9E\u4F8B (\u5BA2\u6237\u7AEF only)\u3002\n * \u9700\u8981\u5B8C\u5168\u81EA\u5B9A\u4E49\u5E03\u5C40\u65F6\u7528\u5B83; \u60F3\u7701\u4E8B\u7528 <Xiaochun />\u3002\n */\nexport function useXiaochun(options: XiaochunHookOptions = {}): UseXiaochunResult {\n const [el, setEl] = useState<HTMLElement | null>(null);\n const [client, setClient] = useState<XiaochunInstance | null>(null);\n const [ready, setReady] = useState(false);\n const [state, setState] = useState<XcStatePayload | null>(null);\n\n // \u56DE\u8C03\u4E0E\"\u70ED\u66F4\u65B0\u578B\"\u9009\u9879\u653E\u8FDB ref: \u5B83\u4EEC\u53D8\u5316\u4E0D\u5E94\u91CD\u5EFA iframe\n const live = useRef(options);\n live.current = options;\n\n const o = options;\n const originsKey = (o.allowedOrigins ?? []).join(',');\n\n useEffect(() => {\n if (!el) return;\n const cur = live.current;\n const { onHandshake: _a, onReady: _b, onProgress: _c, onState: _d, onStt: _e, onUtterance: _f, onHitRegion: _g, onError: _h, onDestroy: _i, onOutfitChanged: _j, onSceneChanged: _k, onMove: _q, onResize: _r, paused: _p, mic: _m, allowedOrigins, ...create } = cur;\n void [_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _p, _m, _q, _r];\n const inst = createXiaochun({ ...create, allowedOrigins: allowedOrigins?.slice(), container: el });\n const offs: Array<() => void> = [];\n for (const [ev, cbName] of EVENT_MAP) {\n offs.push(inst.on(ev, (p: unknown) => { (live.current[cbName] as ((x: unknown) => void) | undefined)?.(p); }));\n }\n offs.push(inst.on('ready', () => setReady(true)));\n offs.push(inst.on('state', (s) => setState(s)));\n if (cur.paused) inst.pause();\n if (cur.mic) void inst.ready.then(() => inst.mic(true)).catch(() => {});\n setClient(inst);\n return () => {\n // StrictMode \u7684\u5047\u5378\u8F7D / \u771F\u5378\u8F7D / \u91CD\u5EFA \u90FD\u8D70\u8FD9\u91CC: \u5FC5\u987B\u9500\u6BC1, \u5426\u5219 iframe \u4E0E window \u76D1\u542C\u6CC4\u6F0F\n offs.forEach((off) => off());\n inst.destroy();\n setClient(null);\n setReady(false);\n setState(null);\n };\n // \u53EA\u6709\"\u521B\u5EFA\u671F\u9009\u9879\"\u53D8\u5316\u624D\u91CD\u5EFA; lang/outfit/scene/paused/mic/\u56DE\u8C03\u8D70\u4E0B\u9762\u7684\u70ED\u66F4\u65B0\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [el, o.src, o.origin, originsKey, o.lazy, o.lazyMargin, o.placeholder, o.transparent, o.position,\n JSON.stringify(o.ui ?? null), o.heavy, o.controls, o.autoPause, o.passthrough, o.sandbox, o.handshakeTimeout, o.crossOriginIsolated, o.zIndex,\n o.allowCustomModel, o.persist, Array.isArray(o.prefetch) ? o.prefetch.join(',') : o.prefetch]);\n\n // \u70ED\u66F4\u65B0: lang / outfit (model \u662F\u65E7\u522B\u540D) / scene (\u8DF3\u8FC7\u9996\u6B21: \u521B\u5EFA\u65F6\u5DF2\u7ECF\u4F5C\u4E3A\u521D\u59CB\u9009\u9879\u4F20\u5165)\u3002\n // transparent \u662F\u521B\u5EFA\u671F\u9009\u9879 (\u53D8\u5316\u4F1A\u91CD\u5EFA); \u60F3\u4E0D\u91CD\u5EFA\u5730\u5207\u900F\u660E\u8BF7\u7528 scene\u3002\n const wantOutfit = o.outfit ?? o.model;\n const first = useRef({ lang: o.lang, outfit: wantOutfit, scene: o.scene, width: o.width, height: o.height });\n const resizableKey = JSON.stringify(o.resizable ?? false);\n useEffect(() => {\n if (!client || first.current.lang === o.lang) return;\n first.current.lang = o.lang;\n if (o.lang) void client.setConfig({ lang: o.lang }).catch(() => {});\n }, [client, o.lang]);\n useEffect(() => {\n if (!client || first.current.outfit === wantOutfit) return;\n first.current.outfit = wantOutfit;\n // busy / unknown_id \u4F1A\u8D70 onError, \u8FD9\u91CC\u4E0D\u91CD\u590D\u5904\u7406; \u65E7\u7528\u6CD5 model=\"https://\u2026\" \u4ECD\u8D70 setModel (\u53D7 allowCustomModel \u7EA6\u675F)\n if (wantOutfit) void (isXcId(wantOutfit) ? client.setOutfit(wantOutfit) : client.setModel(wantOutfit)).catch(() => {});\n }, [client, wantOutfit]);\n useEffect(() => {\n if (!client || first.current.scene === o.scene) return;\n first.current.scene = o.scene;\n if (o.scene) void client.setScene(o.scene).catch(() => {});\n }, [client, o.scene]);\n // \u5C3A\u5BF8 / \u624B\u52BF\u5F00\u5173: \u70ED\u66F4\u65B0, \u4E0D\u91CD\u5EFA iframe (\u7F29\u653E\u662F\u8FD0\u884C\u65F6\u72B6\u6001; \u53EA\u6709 props \u91CC\u7684\u503C\u771F\u7684\u53D8\u4E86\u624D\u8C03 setSize, \u7528\u6237\u7F29\u653E\u540E\u7684\u5C3A\u5BF8\u4E0D\u4F1A\u88AB\u65E0\u5173\u7684\u91CD\u6E32\u67D3\u8986\u76D6)\n useEffect(() => {\n if (!client || (first.current.width === o.width && first.current.height === o.height)) return;\n first.current.width = o.width; first.current.height = o.height;\n client.setSize(o.width ?? 320, o.height ?? 480);\n }, [client, o.width, o.height]);\n useEffect(() => { client?.setDraggable(o.draggable === true); }, [client, o.draggable]);\n useEffect(() => { client?.setBorderRadius(o.borderRadius); }, [client, o.borderRadius]);\n useEffect(() => { client?.setResizable(o.resizable ?? false); // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, resizableKey]);\n useEffect(() => {\n if (!client || o.paused === undefined) return;\n if (o.paused) client.pause(); else client.resume();\n }, [client, o.paused]);\n const micWanted = useRef(o.mic);\n useEffect(() => {\n if (!client || o.mic === undefined || micWanted.current === o.mic) { micWanted.current = o.mic; return; }\n micWanted.current = o.mic;\n void client.mic(!!o.mic).catch(() => {});\n }, [client, o.mic]);\n\n const containerRef = useCallback((node: HTMLElement | null) => setEl(node), []);\n return { containerRef, client, ready, state };\n}\n\n/** ref \u66B4\u9732\u7684\u547D\u4EE4\u5F0F\u53E5\u67C4 (\u5B9E\u4F8B\u5C1A\u672A\u521B\u5EFA / \u5DF2\u9500\u6BC1\u65F6, \u8FD4\u56DE Promise \u7684\u65B9\u6CD5\u4F1A reject)\u3002 */\nexport interface XiaochunHandle {\n say(text: string, opts?: { mode?: 'speak' | 'chat' }): Promise<void>;\n /** \u76F4\u63A5\u64AD\u653E\u5BBF\u4E3B\u7ED9\u7684\u97F3\u9891 (\u4E0D\u8D70 TTS), \u540C\u65F6\u7531 EMAGE \u751F\u6210\u52A8\u4F5C + \u53E3\u578B\u3002 */\n speakAudio(source: XiaochunAudioSource, opts?: XiaochunAudioOptions): Promise<void>;\n speakAudioStream(opts: XiaochunAudioOptions & { sampleRate: number }): XiaochunAudioStream;\n motion(m: XcMotionPayload | string): Promise<void>;\n expression(name: XcExpressionPayload['name']): Promise<void>;\n /** TODO: \u534F\u8BAE\u5DF2\u9884\u7559, /embed \u6682\u672A\u5B9E\u73B0 \u2192 reject unsupported\u3002 */\n lookAt(x: number, y: number): Promise<void>;\n /** \u6362\u5185\u7F6E\u670D\u88C5 (\u4E32\u884C + last-wins, \u89C1 XiaochunInstance.setOutfit)\u3002 */\n setOutfit(id: string): Promise<void>;\n setScene(id: string): Promise<void>;\n getOutfits(): Promise<XcOutfitInfo[]>;\n getScenes(): Promise<XcSceneInfo[]>;\n /** \u9884\u53D6\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB; ids \u7701\u7565 = \u5168\u90E8 (\u5A5A\u7EB1\u9664\u5916)\u3002 */\n prefetch(ids?: string[]): Promise<XcPrefetchedPayload>;\n /** \u65E7\u547D\u4EE4; \u4EFB\u610F URL \u9700 allowCustomModel\u3002\u5185\u7F6E\u670D\u88C5\u8BF7\u7528 setOutfit\u3002 */\n setModel(m: string | { url?: string; outfit?: string; name?: string }): Promise<void>;\n setConfig(cfg: XcConfig): Promise<void>;\n startListening(): Promise<void>;\n stopListening(): Promise<void>;\n mic(enabled: boolean): Promise<void>;\n pause(): void;\n resume(): void;\n activate(): void;\n destroy(): void;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210\u65F6 resolve\u3002 */\n readonly ready: Promise<void>;\n /** \u5E95\u5C42 SDK \u5B9E\u4F8B (\u670D\u52A1\u7AEF / \u672A\u6302\u8F7D\u65F6 null)\u3002 */\n readonly instance: XiaochunInstance | null;\n}\n\nexport interface XiaochunProps extends XiaochunHookOptions {\n className?: string;\n /** \u5916\u5C42 div \u7684\u6837\u5F0F; width/height \u7531 props \u51B3\u5B9A (\u56FA\u5B9A\u5C3A\u5BF8, \u9632 CLS), \u8FD9\u91CC\u7684\u540C\u540D\u5B57\u6BB5\u4F1A\u88AB\u8986\u76D6\u3002 */\n style?: CSSProperties;\n}\n\nconst css = (v: number | string | undefined, d: string) => (v === undefined ? d : typeof v === 'number' ? `${v}px` : v);\nconst NOT_MOUNTED = () => new Error('[project-xiaochun] <Xiaochun /> is not mounted');\n\nfunction XiaochunInner(props: XiaochunProps, ref: ForwardedRef<XiaochunHandle>): ReactElement {\n const { className, style, ...hookOptions } = props;\n const { containerRef, client } = useXiaochun(hookOptions);\n const clientRef = useRef<XiaochunInstance | null>(null);\n clientRef.current = client;\n\n useImperativeHandle(ref, () => {\n const c = () => clientRef.current;\n const reject = <T,>(): Promise<T> => Promise.reject(NOT_MOUNTED());\n return {\n say: (t, o) => c()?.say(t, o) ?? reject(),\n speakAudio: (s, o) => c()?.speakAudio(s, o) ?? reject(),\n speakAudioStream: (o) => { const x = c(); if (!x) throw NOT_MOUNTED(); return x.speakAudioStream(o); },\n motion: (m) => c()?.motion(m) ?? reject(),\n expression: (n) => c()?.expression(n) ?? reject(),\n lookAt: (x, y) => c()?.lookAt(x, y) ?? reject(),\n setOutfit: (id) => c()?.setOutfit(id) ?? reject(),\n setScene: (id) => c()?.setScene(id) ?? reject(),\n getOutfits: () => c()?.getOutfits() ?? reject(),\n getScenes: () => c()?.getScenes() ?? reject(),\n prefetch: (ids) => c()?.prefetch(ids) ?? reject(),\n setModel: (m) => c()?.setModel(m) ?? reject(),\n setConfig: (cfg) => c()?.setConfig(cfg) ?? reject(),\n startListening: () => c()?.startListening() ?? reject(),\n stopListening: () => c()?.stopListening() ?? reject(),\n mic: (e) => c()?.mic(e) ?? reject(),\n pause: () => c()?.pause(),\n resume: () => c()?.resume(),\n activate: () => c()?.activate(),\n destroy: () => c()?.destroy(),\n get ready() { return c()?.ready ?? reject<void>(); },\n get instance() { return c(); },\n };\n }, []);\n\n // \u670D\u52A1\u7AEF\u4E0E\u9996\u5E27\u5BA2\u6237\u7AEF\u6E32\u67D3\u5B8C\u5168\u4E00\u81F4 (hydration \u5B89\u5168): \u56FA\u5B9A\u5C3A\u5BF8\u7684\u7A7A div\n const box: CSSProperties = {\n ...style,\n width: css(props.width, '320px'),\n height: css(props.height, '480px'),\n maxWidth: '100%',\n position: style?.position ?? 'relative',\n };\n return createElement('div', { ref: containerRef, className, style: box, 'data-xiaochun-host': '' });\n}\n\n/** `<Xiaochun />`: \u5728\u5BA2\u6237\u7AEF\u521B\u5EFA\u5C0F\u8822 iframe; ref \u66B4\u9732 say / speakAudio / motion / \u2026 \u7B49\u547D\u4EE4\u5F0F\u65B9\u6CD5\u3002 */\nexport const Xiaochun = forwardRef<XiaochunHandle, XiaochunProps>(XiaochunInner);\nXiaochun.displayName = 'Xiaochun';\n\nexport type { XiaochunOptions, XiaochunInstance, XiaochunAudioOptions, XiaochunAudioSource, XiaochunAudioStream } from './client';\n", "/**\n * protocol.ts \u2014 Project XiaoChun `<iframe>` \u5D4C\u5165\u534F\u8BAE (\u5E38\u91CF + \u7C7B\u578B, \u96F6\u8FD0\u884C\u65F6\u4F9D\u8D56)\u3002\n *\n * \u5355\u4E00\u4E8B\u5B9E\u6E90: SDK (\u672C\u5305) \u4E0E `/embed` \u9875\u9762 (\u4E3B\u4ED3\u5E93 src/embed/) \u5171\u7528\u8FD9\u4E00\u4EFD\u3002\n * \u6240\u6709\u6D88\u606F\u540D\u7EDF\u4E00 `xc.` \u524D\u7F00; \u4FE1\u5C01 `{ type, v, id?, payload? }`\u3002\n *\n * \u901A\u9053:\n * 1. \u63E1\u624B: iframe \u2192 \u5BBF\u4E3B `xc.ready` (window.postMessage, targetOrigin = \u5BBF\u4E3B origin)\n * \u5BBF\u4E3B \u2192 iframe `xc.init` (window.postMessage, targetOrigin = iframe origin, \u8F6C\u79FB MessagePort)\n * 2. \u63E1\u624B\u540E\u5168\u90E8\u8D70 MessageChannel \u7AEF\u53E3 (\u7AEF\u53E3\u672C\u8EAB\u5373\u51ED\u8BC1, \u4E0D\u518D\u4F9D\u8D56 `*`)\n */\n\n/** \u534F\u8BAE\u7248\u672C; \u4E0D\u517C\u5BB9\u53D8\u66F4\u65F6 +1\u3002 */\nexport const XC_PROTOCOL_VERSION = 1 as const;\n\n/** \u5B98\u65B9\u90E8\u7F72\u7684 origin / embed \u5165\u53E3\u3002 */\nexport const XC_DEFAULT_ORIGIN = 'https://xiaochun.firetable.tech';\nexport const XC_DEFAULT_SRC = `${XC_DEFAULT_ORIGIN}/embed`;\n\n/** \u5BBF\u4E3B \u2192 iframe \u547D\u4EE4\u3002 */\nexport const XC_HOST_TO_FRAME = [\n 'xc.init',\n 'xc.say',\n 'xc.audio',\n 'xc.audio.chunk',\n 'xc.audio.end',\n 'xc.motion',\n 'xc.expression',\n 'xc.lookAt',\n 'xc.pointer',\n 'xc.setModel',\n 'xc.setOutfit',\n 'xc.setScene',\n 'xc.prefetch',\n 'xc.setConfig',\n 'xc.mic',\n 'xc.pause',\n 'xc.resume',\n 'xc.destroy',\n] as const;\n\n/** iframe \u2192 \u5BBF\u4E3B \u4E8B\u4EF6\u3002 */\nexport const XC_FRAME_TO_HOST = [\n 'xc.ready',\n 'xc.load.progress',\n 'xc.loaded',\n 'xc.outfit-changed',\n 'xc.scene-changed',\n 'xc.prefetched',\n 'xc.state',\n 'xc.stt',\n 'xc.utterance',\n 'xc.hit-region',\n 'xc.gesture-move',\n 'xc.gesture-resize',\n 'xc.error',\n] as const;\n\nexport type XcHostMessageType = (typeof XC_HOST_TO_FRAME)[number];\nexport type XcFrameMessageType = (typeof XC_FRAME_TO_HOST)[number];\n\n/** \u5F53\u524D /embed \u5DF2\u5B9E\u73B0\u7684\u547D\u4EE4 (xc.init \u662F\u63E1\u624B, \u4E0D\u8BA1\u5165)\u3002 */\nexport const XC_IMPLEMENTED_COMMANDS = [\n 'xc.say',\n 'xc.audio',\n 'xc.audio.chunk',\n 'xc.audio.end',\n 'xc.motion',\n 'xc.expression',\n 'xc.pointer',\n 'xc.setModel',\n 'xc.setOutfit',\n 'xc.setScene',\n 'xc.prefetch',\n 'xc.setConfig',\n 'xc.mic',\n 'xc.pause',\n 'xc.resume',\n 'xc.destroy',\n] as const satisfies readonly XcHostMessageType[];\n\n/**\n * \u6682\u4E0D\u652F\u6301 (\u5E95\u5C42\u65E0\u5BF9\u5E94\u80FD\u529B), /embed \u56DE `xc.error{code:'unsupported'}`\u3002\n * TODO(xc.lookAt): \u89C6\u7EBF\u76EE\u524D\u7531\u76F8\u673A + \u968F\u673A\u626B\u89C6\u9A71\u52A8 (GazeController), \u6CA1\u6709\"\u5916\u90E8\u6307\u5B9A\u6CE8\u89C6\u70B9\"\u7684\u5165\u53E3;\n * \u9700\u8981\u5148\u5728 gaze \u5C42\u52A0 overrideTarget \u518D\u5F00\u653E\u3002\n */\nexport const XC_UNSUPPORTED_COMMANDS = ['xc.lookAt'] as const satisfies readonly XcHostMessageType[];\n\n/**\n * xc.* \u2194 xiaochun:// \u5BF9\u7167\u8868 (\u540C\u4E00\u8BED\u4E49\u7684\u4E24\u4E2A\u4F20\u8F93\u5C42, \u4E3B\u5E94\u7528\u5185\u8D70\u540C\u4E00\u4E2A handler: src/core/protocol/handler.ts)\u3002\n * - `action`: \u5185\u90E8 protocol action \u5BF9\u8C61 (src/core/protocol/types.ts); null = \u6CA1\u6709 deep link \u5BF9\u5E94\u7269\u3002\n * - `url`: \u5BF9\u5E94\u7684 deep link \u5F62\u5F0F (OS \u7EA7, \u53EA\u5728 Tauri \u58F3\u751F\u6548; iframe \u4E0D\u4F1A\u54CD\u5E94 xiaochun://)\u3002\n */\nexport const XC_PROTOCOL_MAPPING = [\n { xc: 'xc.say', note: 'mode:\"speak\" (\u9ED8\u8BA4)', action: 'speak', url: 'xiaochun://speak?text=\u2026' },\n { xc: 'xc.say', note: 'mode:\"chat\" (\u8D70 LLM)', action: null, url: null },\n { xc: 'xc.audio', note: 'source \u4E3A URL \u5B57\u7B26\u4E32', action: 'speak', url: 'xiaochun://speak?audioUrl=\u2026[&text=\u2026]' },\n { xc: 'xc.audio', note: 'source \u4E3A ArrayBuffer / Blob', action: 'audio', url: null },\n { xc: 'xc.audio.chunk / xc.audio.end', note: '\u6D41\u5F0F PCM', action: 'audio', url: null },\n] as const;\n\nexport type XcErrorCode =\n | 'unsupported' // \u547D\u4EE4/\u53C2\u6570\u5B58\u5728\u4F46\u5E95\u5C42\u6682\u65E0\u80FD\u529B\n | 'bad_request' // \u53C2\u6570\u7F3A\u5931/\u975E\u6CD5\n | 'not_ready' // \u6A21\u578B\u5C1A\u672A\u52A0\u8F7D\u5B8C\u6210\n | 'busy' // \u88AB\u540C\u7C7B\u66F4\u65B0\u7684\u8BF7\u6C42\u53D6\u4EE3 (\u6362\u88C5 last-wins: \u6392\u961F\u4E2D\u7684\u65E7\u8BF7\u6C42\u88AB\u65B0\u8BF7\u6C42\u9876\u6389); \u53EF\u5FFD\u7565, \u4EE5\u6700\u65B0\u4E00\u6B21\u4E3A\u51C6\n | 'unknown_id' // outfit / scene id \u4E0D\u5728 capabilities \u5217\u8868\u91CC (\u542B\u539F\u578B\u952E\u5982 constructor)\n | 'origin_denied' // \u63E1\u624B\u6765\u6E90\u4E0D\u5728\u767D\u540D\u5355\n | 'failed'; // \u6267\u884C\u671F\u5F02\u5E38\n\n/**\n * outfit / scene id \u7684\u7EDF\u4E00\u683C\u5F0F: \u5C0F\u5199\u5B57\u6BCD\u5F00\u5934, \u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u4E0B\u5212\u7EBF, \u6700\u957F 64\u3002\n * \u6240\u6709 id \u5165\u53E3 (xc.setOutfit / xc.setScene / ?outfit= / ?scene=) \u90FD\u5148\u8FC7\u8FD9\u6761\u6B63\u5219, \u518D\u7528 hasOwnProperty \u67E5\u8868,\n * \u8FD9\u6837 `__proto__` / `constructor` / `toString` \u8FD9\u7C7B\u539F\u578B\u952E\u6C38\u8FDC\u4E0D\u4F1A\u88AB\u5F53\u6210\u5408\u6CD5 id\u3002\n */\n/**\n * iframe \u5185\u7F6E\u754C\u9762\u90E8\u4EF6\u540D (`?ui=chat,outfit,scene` / SDK `ui: [...]`)\u3002\n * chat \u5E95\u90E8\u804A\u5929\u680F (ChatBar, \u5BF9\u8BDD\u8D70 WebLLM)\n * bubble \u5934\u9876\u6C14\u6CE1 (\u8BF4\u8BDD\u6587\u672C / \u72B6\u6001)\n * outfit \u6362\u88C5\u6309\u94AE (\u4E0E\u4E3B\u7AD9 TopHeader \u540C\u6B3E)\n * scene \u6362\u573A\u666F(\u80CC\u666F)\u6309\u94AE (\u4E0E\u4E3B\u7AD9 TopHeader \u540C\u6B3E)\n */\n/**\n * \u7A97\u53E3\u5706\u89D2\u534A\u5F84 (CSS px)\u3002Tauri \u684C\u5BA0\u7684\u65E0\u6846\u7A97\u53E3\u5706\u89D2 (src/styles/main.css \u7684 --xc-window-radius) \u4E0E /embed \u975E\u900F\u660E\u573A\u666F\u7684\u9ED8\u8BA4\u5916\u58F3\u5706\u89D2\u5171\u7528\u8FD9\u4E00\u4E2A\u503C,\n * \u6709\u5355\u6D4B\u4FDD\u8BC1\u4E24\u5904\u4E0D\u6F02\u79FB\u3002\u89D2\u843D\u5F27\u7EBF (components/CornerHandle) \u7684\u51E0\u4F55\u5C31\u662F\u6309\u8FD9\u4E2A\u534A\u5F84\u753B\u7684\u3002\n */\nexport const XC_WINDOW_CORNER_RADIUS = 20;\n\nexport const XC_UI_PARTS = ['chat', 'bubble', 'outfit', 'scene'] as const;\nexport type XcUiPart = (typeof XC_UI_PARTS)[number];\nconst XC_UI_PART_SET: ReadonlySet<string> = new Set(XC_UI_PARTS);\n/** 0.1.14 \u91CC `ui=1` / `ui: true` \u7684\u542B\u4E49 = \u5F53\u65F6\u5B58\u5728\u7684\u5168\u90E8\u90E8\u4EF6\u3002 */\nexport const XC_UI_LEGACY_PARTS: readonly XcUiPart[] = ['chat', 'bubble'];\n\nexport interface XcUiParse {\n /** \u767D\u540D\u5355\u5185\u7684\u90E8\u4EF6 (\u53BB\u91CD, \u4FDD\u6301 XC_UI_PARTS \u987A\u5E8F)\u3002 */\n parts: XcUiPart[];\n /** \u88AB\u5FFD\u7565\u7684\u672A\u77E5\u9879 (\u8C03\u7528\u65B9\u8D1F\u8D23 warn)\u3002 */\n unknown: string[];\n /** \u7528\u4E86\u5DF2\u5F03\u7528\u7684 1 / true \u5199\u6CD5 (\u8C03\u7528\u65B9\u8D1F\u8D23 warn)\u3002 */\n legacy: boolean;\n}\n\n/** \u89C4\u6574\u90E8\u4EF6\u540D\u5217\u8868: \u975E\u5B57\u7B26\u4E32 / \u672A\u77E5\u540D\u5B57\u5FFD\u7565\u5E76\u8BB0\u5165 unknown, \u91CD\u590D\u53BB\u91CD\u3002 */\nexport function parseXcUiList(items: readonly unknown[]): XcUiParse {\n const seen = new Set<string>();\n const unknown: string[] = [];\n for (const it of items) {\n const name = typeof it === 'string' ? it.trim().toLowerCase() : '';\n if (XC_UI_PART_SET.has(name)) seen.add(name);\n else unknown.push(typeof it === 'string' ? it.slice(0, 40) : String(typeof it));\n }\n return { parts: XC_UI_PARTS.filter((p) => seen.has(p)), unknown, legacy: false };\n}\n\n/** `?ui=` \u53C2\u6570 / \u5143\u7D20\u5C5E\u6027: \u9017\u53F7\u5206\u9694\u7684\u90E8\u4EF6\u540D; \u7F3A\u7701 / \u7A7A / 0 / false = \u5168\u4E0D\u663E\u793A; 1 / true = \u65E7\u5199\u6CD5 (\u5F03\u7528, \u6620\u5C04\u4E3A chat + bubble)\u3002 */\nexport function parseXcUiParam(raw: string | null | undefined): XcUiParse {\n const v = (raw ?? '').trim().toLowerCase();\n if (v === '' || v === '0' || v === 'false') return { parts: [], unknown: [], legacy: false };\n if (v === '1' || v === 'true') return { parts: [...XC_UI_LEGACY_PARTS], unknown: [], legacy: true };\n return parseXcUiList(v.split(',').filter((x) => x.trim() !== ''));\n}\n\n/** SDK \u9009\u9879 `ui` (\u6570\u7EC4, \u6216\u5F03\u7528\u7684\u5E03\u5C14) \u2192 \u89C4\u6574\u7ED3\u679C\u3002 */\nexport function normalizeXcUiOption(v: unknown): XcUiParse {\n if (v === true) return { parts: [...XC_UI_LEGACY_PARTS], unknown: [], legacy: true };\n if (Array.isArray(v)) return parseXcUiList(v);\n return { parts: [], unknown: [], legacy: false };\n}\n\nexport const XC_ID_RE = /^[a-z][a-z0-9_]{0,63}$/;\nexport const isXcId = (v: unknown): v is string => typeof v === 'string' && XC_ID_RE.test(v);\n/** \u53EA\u8BA4\u5BF9\u8C61\u81EA\u5DF1\u7684\u5C5E\u6027 (\u4E0D\u8D70\u539F\u578B\u94FE); \u7B49\u4EF7\u4E8E Object.hasOwn, \u4F46\u517C\u5BB9 ES2020 \u76EE\u6807\u3002 */\nexport const xcHasOwn = (o: object, k: string): boolean => Object.prototype.hasOwnProperty.call(o, k);\n\n/** \u5185\u7F6E\u573A\u666F id (\u4EE5 xc.ready.capabilities.scenes \u4E3A\u51C6; \u76EE\u524D\u5C31\u8FD9\u4E09\u4E2A\u4E3B\u9898, \u4E0D\u542B\u771F\u5B9E\u573A\u666F\u8D44\u4EA7)\u3002 */\nexport type XcSceneId = 'light' | 'dark' | 'transparent';\nexport type XcLang = 'zh-CN' | 'en' | 'ja';\nexport type XcPhase = 'idle' | 'loading' | 'thinking' | 'speaking' | 'listening' | 'paused';\n/** lazy = \u4E0D\u9884\u70ED WebLLM / EMAGE, \u9996\u6B21\u4E92\u52A8\u518D\u52A0\u8F7D (\u9ED8\u8BA4); eager = \u7ACB\u5373\u9884\u70ED\u3002 */\nexport type XcHeavyMode = 'lazy' | 'eager';\n\nexport interface XcEnvelope<T extends string = string, P = unknown> {\n type: T;\n v: typeof XC_PROTOCOL_VERSION;\n /** \u5BBF\u4E3B\u547D\u4EE4\u53EF\u5E26 id; \u5BF9\u5E94\u7684 xc.error / xc.utterance \u4F1A\u56DE\u5E26\u540C\u4E00\u4E2A id\u3002 */\n id?: string;\n payload: P;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u5BBF\u4E3B \u2192 iframe payload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface XcConfig {\n lang?: XcLang;\n /** \u80CC\u666F\u900F\u660E (\u53E0\u5728\u5BBF\u4E3B\u9875\u9762\u4E0A)\u3002 */\n transparent?: boolean;\n /**\n * \u8981\u663E\u793A\u7684 iframe \u5185\u7F6E\u754C\u9762\u90E8\u4EF6 (\u89C1 XC_UI_PARTS), \u4F8B\u5982 ['outfit','scene']; \u7701\u7565 / \u7A7A\u6570\u7EC4 = \u4E0D\u663E\u793A\u3002\n * \u4F20 true/false \u662F 0.1.14 \u7684\u65E7\u5199\u6CD5 (true = chat + bubble), \u5DF2\u5F03\u7528, \u4EC5\u4E3A\u517C\u5BB9\u4FDD\u7559\u3002\n */\n ui?: XcUiPart[] | boolean;\n /** \u91CD\u8D44\u6E90\u52A0\u8F7D\u7B56\u7565, \u89C1 XcHeavyMode\u3002 */\n heavy?: XcHeavyMode;\n /**\n * \u5141\u8BB8 xc.setModel \u52A0\u8F7D\u4EFB\u610F https URL \u7684 .vrm/.vrmaddon/.vrmbase\u3002\u9ED8\u8BA4 false (\u5173\u95ED): \u53EA\u80FD\u7528 capabilities.outfits \u91CC\u7684\u5185\u7F6E\u670D\u88C5\u3002\n * \u7531\u5BBF\u4E3B SDK \u7684 `allowCustomModel` \u9009\u9879\u53D1\u51FA (\u653E\u5728 xc.init \u7684 config \u91CC)\u3002\n */\n allowCustomModel?: boolean;\n /**\n * \u624B\u52BF\u5F00\u5173 (\u5BBF\u4E3B SDK \u7684 `draggable` / `resizable` \u9009\u9879\u53D1\u51FA; \u653E\u5728 xc.init \u7684 config \u91CC, \u4E5F\u53EF\u7528 xc.setConfig \u8FD0\u884C\u65F6\u6539)\u3002\n * \u9ED8\u8BA4\u5168 false: iframe \u91CC**\u4E0D\u8BC6\u522B**\u5BF9\u5E94\u624B\u52BF\u3001\u4E5F\u4E0D\u62E6\u622A\u4EFB\u4F55\u6307\u9488\u4E8B\u4EF6\u3002\u4EC5\u5F53 capabilities.gestures \u5B58\u5728\u65F6\u624D\u6709\u610F\u4E49 (\u65E7\u7248 /embed \u5FFD\u7565)\u3002\n * move = \u5DE6\u952E\u5728\u89D2\u8272\u4E0A\u62D6\u52A8 \u2192 \u53D1 xc.gesture-move, \u7531\u5BBF\u4E3B\u79FB\u52A8 iframe\n * resize = \u5728 iframe \u56DB\u89D2\u70ED\u533A\u6309\u4E0B\u62D6\u52A8 \u2192 \u53D1 xc.gesture-resize, \u7531\u5BBF\u4E3B\u7F29\u653E iframe\n */\n gestures?: { move?: boolean; resize?: boolean };\n}\n\nexport interface XcInitPayload {\n /** \u5BBF\u4E3B\u58F0\u660E\u7684\u81EA\u8EAB origin (iframe \u4F1A\u4E0E event.origin \u4EA4\u53C9\u6821\u9A8C)\u3002 */\n hostOrigin: string;\n config?: XcConfig;\n}\n\nexport interface XcSayPayload {\n text: string;\n /**\n * 'speak' (\u9ED8\u8BA4): \u76F4\u63A5 TTS + \u52A8\u4F5C, \u4E0D\u7ECF\u8FC7 LLM\u3002\n * 'chat': \u5F53\u4F5C\u7528\u6237\u8F93\u5165\u8D70 WebLLM / \u81EA\u5B9A\u4E49 provider (\u4F1A\u89E6\u53D1\u5927\u6A21\u578B\u52A0\u8F7D)\u3002\n */\n mode?: 'speak' | 'chat';\n}\n\n/** \u5BBF\u4E3B\u97F3\u9891\u7684\u7F16\u7801: encoded = \u5BB9\u5668\u683C\u5F0F (mp3/wav/ogg/aac/webm\u2026 \u7531\u6D4F\u89C8\u5668 decodeAudioData \u51B3\u5B9A); pcm16 / float32 = \u65E0\u5934\u539F\u59CB PCM (\u5C0F\u7AEF, \u4EA4\u9519)\u3002 */\nexport type XcAudioFormat = 'encoded' | 'pcm16' | 'float32';\n\nexport interface XcAudioOptions {\n /** \u6C14\u6CE1\u91CC\u663E\u793A\u7684\u6587\u5B57 (\u53EF\u9009; \u4E0D\u5F71\u54CD\u97F3\u9891\u4E0E\u52A8\u4F5C)\u3002 */\n text?: string;\n /** \u662F\u5426\u7531 EMAGE \u6839\u636E\u8FD9\u6BB5\u97F3\u9891\u751F\u6210\u5168\u8EAB\u52A8\u4F5C, \u9ED8\u8BA4 true\u3002false = \u53EA\u64AD\u653E\u97F3\u9891 (\u6B64\u65F6\u5B8C\u5168\u4E0D\u52A0\u8F7D EMAGE)\u3002 */\n motion?: boolean;\n /** \u662F\u5426\u9A71\u52A8\u53E3\u578B (\u97F3\u91CF RMS \u2192 'aa'), \u9ED8\u8BA4 true\u3002 */\n lipsync?: boolean;\n}\n\n/**\n * xc.audio \u2014 \u6574\u6BB5\u97F3\u9891: iframe \u5185\u89E3\u7801 \u2192 16 kHz \u2192 EMAGE \u7A97\u53E3\u63A8\u7406 + \u540C\u4E00\u6BB5\u97F3\u9891\u64AD\u653E + \u53E3\u578B, \u64AD\u5B8C\u56DE xc.utterance{phase:'end'}\u3002\n * \u4FE1\u5C01 `id` \u7528\u4E8E\u5173\u8054 xc.utterance / xc.error\u3002\u5927 ArrayBuffer \u8BF7\u653E\u8FDB postMessage \u7684 transfer \u5217\u8868 (SDK \u9ED8\u8BA4\u8FD9\u4E48\u505A)\u3002\n */\nexport interface XcAudioPayload extends XcAudioOptions {\n /** ArrayBuffer / Blob (structured clone) \u6216 URL \u5B57\u7B26\u4E32 (iframe \u5185 fetch, \u4EC5 https \u6216\u540C\u6E90, \u9700 CORS)\u3002 */\n source: ArrayBuffer | Blob | string;\n /** MIME \u63D0\u793A, \u5982 'audio/mpeg'\u3002\u4EC5\u4F5C\u4FE1\u606F, \u89E3\u7801\u4EE5\u6D4F\u89C8\u5668\u55C5\u63A2\u4E3A\u51C6\u3002 */\n mimeType?: string;\n /** \u9ED8\u8BA4 'encoded'\u3002 */\n format?: XcAudioFormat;\n /** \u4EC5\u539F\u59CB PCM \u9700\u8981 (\u9ED8\u8BA4 16000); \u5BB9\u5668\u683C\u5F0F\u5FFD\u7565 (\u4EE5\u6587\u4EF6\u5185\u7684\u91C7\u6837\u7387\u4E3A\u51C6)\u3002\u8303\u56F4 8000~96000\u3002 */\n sampleRate?: number;\n /** \u539F\u59CB PCM \u7684\u58F0\u9053\u6570 (\u4EA4\u9519), 1 \u6216 2, \u9ED8\u8BA4 1; \u5185\u90E8\u4E0B\u6DF7\u4E3A\u5355\u58F0\u9053\u3002 */\n channels?: 1 | 2;\n}\n\n/**\n * xc.audio.chunk \u2014 \u6D41\u5F0F\u97F3\u9891\u5206\u5757 (\u539F\u59CB PCM)\u3002\u4FE1\u5C01 `id` = \u6D41 id: \u540C\u4E00\u4E2A id \u7684\u7B2C\u4E00\u4E2A chunk \u5F00\u542F\u4E00\u6B21\u8BF4\u8BDD (\u56DE xc.utterance start),\n * \u4E4B\u540E\u7684 chunk \u8FFD\u52A0; \u4EE5 xc.audio.end \u6536\u5C3E\u3002\u6BCF\u4E2A chunk \u7684 `data` \u5E94\u653E\u8FDB transfer \u5217\u8868\u3002\n * \u9009\u9879 (text/motion/lipsync) \u53EA\u5728\u7B2C\u4E00\u4E2A chunk \u91CC\u751F\u6548; sampleRate/format \u6574\u6761\u6D41\u5FC5\u987B\u4E00\u81F4\u3002\n */\nexport interface XcAudioChunkPayload extends XcAudioOptions {\n data: ArrayBuffer;\n format: Exclude<XcAudioFormat, 'encoded'>;\n /** 8000~96000\u3002 */\n sampleRate: number;\n channels?: 1 | 2;\n}\n\nexport interface XcAudioEndPayload {\n /** true = \u7ACB\u5373\u6253\u65AD (\u4E22\u5F03\u672A\u64AD\u653E\u7684\u97F3\u9891); \u9ED8\u8BA4 false = \u64AD\u5B8C\u5DF2\u6536\u5230\u7684\u97F3\u9891\u540E\u7ED3\u675F\u3002 */\n abort?: boolean;\n}\n\nexport interface XcMotionPayload {\n /** .vrma URL (https:// \u6216\u540C\u6E90\u8DEF\u5F84)\u3002\u4E0E stop \u4E8C\u9009\u4E00\u3002 */\n url?: string;\n /** \u5185\u7F6E\u52A8\u4F5C\u540D, \u76EE\u524D\u4EC5 'thinking'\u3002 */\n name?: 'thinking';\n stop?: boolean;\n loop?: boolean;\n /** \u6DE1\u5165\u6DE1\u51FA\u79D2\u6570, \u8303\u56F4 0.26~3, \u8C03\u5927\u66F4\u67D4\u548C\u4F46\u54CD\u5E94\u66F4\u6162\u3002 */\n fadeDuration?: number;\n /** \u64AD\u653E\u500D\u901F, \u8303\u56F4 0.25~3\u3002 */\n timeScale?: number;\n mask?: 'all' | 'upperBody';\n}\n\nexport interface XcExpressionPayload {\n name: 'neutral' | 'happy' | 'angry' | 'sad' | 'relaxed' | 'surprised';\n}\n\n/** xc.lookAt \u2014 TODO: \u6682\u4E0D\u652F\u6301, \u6536\u5230\u4F1A\u8FD4\u56DE unsupported\u3002 */\nexport interface XcLookAtPayload {\n /** \u5F52\u4E00\u5316 (-1..1), \u76F8\u5BF9 iframe \u4E2D\u5FC3\u3002 */\n x: number;\n y: number;\n}\n\nexport interface XcPointerPayload {\n /** iframe \u5185 client \u5750\u6807 (px)\u3002SDK \u4F1A\u628A\u5BBF\u4E3B pointer \u4E8B\u4EF6\u6362\u7B97\u597D\u518D\u53D1\u3002 */\n x: number;\n y: number;\n}\n\nexport interface XcSetModelPayload {\n /** \u5B8C\u6574 .vrm / .vrmaddon / .vrmbase URL (\u9700 CORS)\u3002**\u9ED8\u8BA4\u5173\u95ED**, \u9700\u8981 xc.init config.allowCustomModel=true, \u5426\u5219\u56DE unsupported\u3002 */\n url?: string;\n /** \u5185\u7F6E\u670D\u88C5 id (capabilities.outfits \u91CC\u7684 id, \u5982 'xiaochun_maid')\u3002\u88F8\u6A21 'base' \u4E0D\u5BF9\u5916\u5F00\u653E (\u56DE unknown_id)\u3002\u65B0\u4EE3\u7801\u8BF7\u7528 xc.setOutfit\u3002 */\n outfit?: string;\n name?: string;\n}\n\n/** xc.setOutfit \u2014 \u6362\u5185\u7F6E\u670D\u88C5 (id \u6765\u81EA xc.ready.capabilities.outfits)\u3002\u4E32\u884C + last-wins, \u89C1 docs/EMBED.md\u3002 */\nexport interface XcSetOutfitPayload {\n id: string;\n}\n\n/**\n * xc.prefetch \u2014 \u9884\u53D6\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB (\u4E4B\u540E xc.setOutfit \u76F4\u63A5\u547D\u4E2D\u7F13\u5B58, \u4E0D\u8D70\u7F51\u7EDC)\u3002\u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u53D1\u751F\u3002\n * \u5168\u5C40\u4E32\u884C (\u5E76\u53D1 1); \u5F00\u4E86 heavy:'eager' \u65F6\u6392\u5728 EMAGE \u52A0\u8F7D\u4E4B\u540E, \u4E5F\u4E0D\u4F1A\u548C\u8FDB\u884C\u4E2D\u7684\u6362\u88C5\u62A2\u5E26\u5BBD\u3002\n * ids \u7701\u7565 = \u5168\u90E8\u5185\u7F6E\u670D\u88C5, **\u9664\u4E86**\u4F53\u79EF\u5927\u7684\u5A5A\u7EB1 (xiaochun_wedding, 13.9MB); \u663E\u5F0F\u70B9\u540D\u5219\u7167\u505A\u3002\n * \u5E94\u7B54 xc.prefetched (\u5E26\u540C\u4E00\u4E2A\u4FE1\u5C01 id)\u3002\n */\nexport interface XcPrefetchPayload {\n ids?: string[];\n}\n\n/** xc.prefetched \u2014 \u9884\u53D6\u5B8C\u6210 (\u9010\u9879\u6210\u8D25\u4E0D\u5F71\u54CD\u6574\u4F53; failed \u91CC\u7684 id \u53EF\u7A0D\u540E\u91CD\u8BD5)\u3002 */\nexport interface XcPrefetchedPayload {\n downloaded: string[];\n cached: string[];\n failed: string[];\n /** 'save-data' = \u7528\u6237\u5F00\u4E86\u7701\u6D41\u91CF\u6A21\u5F0F, \u6574\u4E2A\u8BF7\u6C42\u88AB\u8DF3\u8FC7\u3002 */\n skipped?: 'save-data';\n}\n\n/** xc.setScene \u2014 \u8FD0\u884C\u65F6\u5207\u573A\u666F (id \u6765\u81EA xc.ready.capabilities.scenes: light / dark / transparent)\u3002 */\nexport interface XcSetScenePayload {\n id: string;\n}\n\nexport interface XcMicPayload {\n enabled: boolean;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 iframe \u2192 \u5BBF\u4E3B payload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface XcReadyPayload {\n version: string;\n protocol: typeof XC_PROTOCOL_VERSION;\n capabilities: {\n commands: string[];\n unsupported: string[];\n stt: boolean;\n transparent: boolean;\n /** \u5BBF\u4E3B\u97F3\u9891\u80FD\u529B (xc.audio / xc.audio.chunk)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n audio?: { formats: XcAudioFormat[]; streaming: boolean; maxSeconds: number };\n /** iframe \u5185 `self.crossOriginIsolated` (true = \u53EF\u7528 SharedArrayBuffer / \u591A\u7EBF\u7A0B wasm)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002\u4EC5\u8BCA\u65AD\u7528\u3002 */\n crossOriginIsolated?: boolean;\n /** \u53EF\u6362\u7684\u5185\u7F6E\u670D\u88C5 (\u4E0D\u542B\u88F8\u6A21)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u5BBF\u4E3B\u5E94\u89C6\u4E3A\"\u4E0D\u652F\u6301 xc.setOutfit\"\u3002 */\n outfits?: XcOutfitInfo[];\n /** \u53EF\u5207\u7684\u573A\u666F\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u89C6\u4E3A\"\u4E0D\u652F\u6301 xc.setScene\"\u3002 */\n scenes?: XcSceneInfo[];\n /** \u652F\u6301 xc.prefetch\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n prefetch?: boolean;\n /**\n * iframe \u5185\u624B\u52BF (\u62D6\u52A8 / \u89D2\u843D\u7F29\u653E) \u652F\u6301\u60C5\u51B5; \u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u5BBF\u4E3B\u89C6\u4E3A\"\u4E0D\u652F\u6301\", draggable / resizable \u65E0\u6548\u3002\n * cornerSize = \u56DB\u89D2\u70ED\u533A\u8FB9\u957F (CSS px, iframe \u89C6\u53E3\u5DE6\u4E0A/\u53F3\u4E0A/\u5DE6\u4E0B/\u53F3\u4E0B\u5404\u4E00\u4E2A\u6B63\u65B9\u5F62), \u5BBF\u4E3B UI \u53EF\u636E\u6B64\u63D0\u793A\u3002\n */\n gestures?: { move: boolean; resize: boolean; cornerSize: number };\n };\n}\n\nexport interface XcOutfitInfo {\n id: string;\n /** \u5C55\u793A\u540D (\u82F1\u6587, \u6765\u81EA\u4E3B\u4ED3\u5E93\u914D\u7F6E)\u3002 */\n name: string;\n /** \u670D\u88C5\u6587\u4EF6\u5927\u5C0F\u63D0\u793A (MB, \u5341\u8FDB\u5236, \u7EA6\u503C; \u516C\u5171\u7684\u88F8\u6A21 ~5.7MB \u4E0D\u8BA1)\u3002\u4EC5\u4F9B\u5BBF\u4E3B\u81EA\u5DF1\u7684 UI \u53C2\u8003 (\u5185\u7F6E\u6362\u88C5\u83DC\u5355\u4E0D\u663E\u793A\u4F53\u79EF); \u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n sizeMB?: number;\n}\n\nexport interface XcSceneInfo {\n id: string;\n /** true = \u80CC\u666F\u900F\u660E (\u53E0\u5728\u5BBF\u4E3B\u9875\u4E0A, \u53EF\u5F00\u7A7F\u900F)\u3002 */\n transparent: boolean;\n}\n\nexport interface XcLoadProgressPayload {\n /**\n * 'model' = \u9996\u6B21\u52A0\u8F7D; 'outfit' = \u8FD0\u884C\u4E2D\u6362\u88C5 (id = \u76EE\u6807\u670D\u88C5 id, \u81EA\u5B9A\u4E49 URL \u65F6\u7701\u7565);\n * 'prefetch' = \u5BBF\u4E3B\u53D1\u4E86 xc.prefetch \u540E\u7684\u540E\u53F0\u4E0B\u8F7D (id = \u6B63\u5728\u9884\u53D6\u7684\u670D\u88C5)\u3002\u5DF2\u6709\u7684\"model \u8FDB\u5EA6\u6761\"\u903B\u8F91\u8BF7\u5148\u5224\u65AD phase\u3002\n */\n phase: 'model' | 'outfit' | 'prefetch';\n /** 0~100 */\n progress: number;\n id?: string;\n}\n\nexport interface XcLoadedPayload {\n model: string;\n}\n\n/**\n * xc.outfit-changed \u2014 \u670D\u88C5\u5DF2\u751F\u6548\u3002\u4E09\u79CD\u6765\u6E90: \u9996\u6B21\u52A0\u8F7D (initial:true)\u3001xc.setOutfit / xc.setModel \u7684\u5E94\u7B54 (\u5E26\u540C\u4E00\u4E2A\u4FE1\u5C01 id)\u3002\n * noop:true = \u76EE\u6807\u5DF2\u7ECF\u662F\u5F53\u524D\u670D\u88C5 (\u6216\u4E0E\u53E6\u4E00\u4E2A\u540C\u76EE\u6807\u8BF7\u6C42\u5408\u5E76), \u6CA1\u6709\u91CD\u65B0\u52A0\u8F7D; SDK \u53EA\u7528\u5B83 resolve \u5BF9\u5E94\u7684 Promise, \u4E0D\u518D\u89E6\u53D1\u4E8B\u4EF6\u3002\n */\nexport interface XcOutfitChangedPayload {\n /** \u5185\u7F6E\u670D\u88C5 id; \u81EA\u5B9A\u4E49 URL \u6A21\u578B\u4E3A null\u3002 */\n id: string | null;\n name: string;\n previous?: string | null;\n initial?: boolean;\n noop?: boolean;\n}\n\n/** xc.scene-changed \u2014 \u573A\u666F\u5DF2\u751F\u6548 (\u9996\u6B21\u63E1\u624B\u540E\u7684\u5F53\u524D\u573A\u666F / xc.setScene \u5E94\u7B54 / xc.setConfig{transparent} \u5F15\u8D77\u7684\u5207\u6362)\u3002 */\nexport interface XcSceneChangedPayload {\n id: string;\n transparent: boolean;\n previous?: string | null;\n initial?: boolean;\n noop?: boolean;\n}\n\nexport interface XcStatePayload {\n phase: XcPhase;\n paused: boolean;\n heavy: XcHeavyMode;\n}\n\nexport type XcSttPayload =\n | { kind: 'state'; state: 'idle' | 'loading' | 'listening' | 'recognizing' | 'error' }\n | { kind: 'progress'; percent: number }\n | { kind: 'text'; text: string };\n\nexport interface XcUtterancePayload {\n phase: 'start' | 'end';\n text: string;\n /** 'text' = xc.say (TTS); 'audio' = xc.audio / xc.audio.chunk (\u5BBF\u4E3B\u97F3\u9891, \u6CA1\u6709\u8D70 TTS)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n kind?: 'text' | 'audio';\n}\n\nexport interface XcHitRegionPayload {\n hit: boolean;\n x: number;\n y: number;\n}\n\n/** \u624B\u52BF\u9636\u6BB5: start = \u6309\u4E0B\u540E\u786E\u8BA4\u6210\u624B\u52BF; move = \u589E\u91CF; end = \u7ED3\u675F (\u677E\u624B / \u53D6\u6D88 / \u5931\u7126)\u3002 */\nexport type XcGesturePhase = 'start' | 'move' | 'end';\n\n/**\n * xc.gesture-move / xc.gesture-resize \u7684\u516C\u5171\u5B57\u6BB5\u3002\u5355\u4F4D CSS px (\u5C4F\u5E55\u5750\u6807\u5DEE, iframe \u88AB\u79FB\u52A8\u65F6\u4ECD\u7A33\u5B9A)\u3002\n * - gesture: \u624B\u52BF\u5E8F\u53F7, \u6BCF\u6B21\u65B0\u624B\u52BF +1 (\u4ECE 1 \u8D77); \u5BBF\u4E3B\u636E\u6B64\u533A\u5206\u624B\u52BF, \u4E22\u5F03\u8FC7\u671F\u624B\u52BF\u7684\u8FDF\u5230\u6D88\u606F\u3002\n * - seq: \u8BE5\u624B\u52BF\u5185\u7684\u6D88\u606F\u5E8F\u53F7, start = 0, \u4E4B\u540E\u4E25\u683C\u9012\u589E; \u5BBF\u4E3B\u4E22\u5F03 seq \u4E0D\u9012\u589E\u7684\u6D88\u606F\u3002\n * - dx / dy: \u76F8\u5BF9\u4E0A\u4E00\u6761\u6D88\u606F\u7684\u589E\u91CF; totalDx / totalDy: \u76F8\u5BF9 start \u7684\u7D2F\u8BA1 (\u5BBF\u4E3B\u4EE5\u5B83\u4E3A\u51C6\u8BA1\u7B97, \u589E\u91CF\u53EA\u662F\u53C2\u8003, \u4E22\u5305\u4E5F\u4E0D\u6F02\u79FB)\u3002\n * - reason: \u4EC5 phase='end' \u5E26: up = \u677E\u624B, cancel = \u6307\u9488\u88AB\u7CFB\u7EDF\u53D6\u6D88, blur = \u7A97\u53E3\u5931\u7126\u3002\n */\nexport interface XcGestureBase {\n gesture: number;\n seq: number;\n phase: XcGesturePhase;\n dx: number;\n dy: number;\n totalDx: number;\n totalDy: number;\n reason?: 'up' | 'cancel' | 'blur';\n}\nexport type XcGestureMovePayload = XcGestureBase;\nexport type XcGestureCorner = 'NW' | 'NE' | 'SW' | 'SE';\nexport interface XcGestureResizePayload extends XcGestureBase {\n /** \u88AB\u62D6\u7684\u89D2; \u5BF9\u89D2\u56FA\u5B9A\u4E0D\u52A8\u3002 */\n corner: XcGestureCorner;\n}\n\nexport interface XcErrorPayload {\n code: XcErrorCode;\n message: string;\n /** \u89E6\u53D1\u9519\u8BEF\u7684\u547D\u4EE4\u540D (\u5982 'xc.lookAt')\u3002 */\n command?: string;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u7C7B\u578B\u6620\u5C04 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface XcHostPayloadMap {\n 'xc.init': XcInitPayload;\n 'xc.say': XcSayPayload;\n 'xc.audio': XcAudioPayload;\n 'xc.audio.chunk': XcAudioChunkPayload;\n 'xc.audio.end': XcAudioEndPayload;\n 'xc.motion': XcMotionPayload;\n 'xc.expression': XcExpressionPayload;\n 'xc.lookAt': XcLookAtPayload;\n 'xc.pointer': XcPointerPayload;\n 'xc.setModel': XcSetModelPayload;\n 'xc.setOutfit': XcSetOutfitPayload;\n 'xc.setScene': XcSetScenePayload;\n 'xc.prefetch': XcPrefetchPayload;\n 'xc.setConfig': XcConfig;\n 'xc.mic': XcMicPayload;\n 'xc.pause': undefined;\n 'xc.resume': undefined;\n 'xc.destroy': undefined;\n}\n\nexport interface XcFramePayloadMap {\n 'xc.ready': XcReadyPayload;\n 'xc.load.progress': XcLoadProgressPayload;\n 'xc.loaded': XcLoadedPayload;\n 'xc.outfit-changed': XcOutfitChangedPayload;\n 'xc.scene-changed': XcSceneChangedPayload;\n 'xc.prefetched': XcPrefetchedPayload;\n 'xc.state': XcStatePayload;\n 'xc.stt': XcSttPayload;\n 'xc.utterance': XcUtterancePayload;\n 'xc.hit-region': XcHitRegionPayload;\n 'xc.gesture-move': XcGestureMovePayload;\n 'xc.gesture-resize': XcGestureResizePayload;\n 'xc.error': XcErrorPayload;\n}\n\nexport type XcHostMessage = {\n [K in XcHostMessageType]: XcEnvelope<K, XcHostPayloadMap[K]>;\n}[XcHostMessageType];\n\nexport type XcFrameMessage = {\n [K in XcFrameMessageType]: XcEnvelope<K, XcFramePayloadMap[K]>;\n}[XcFrameMessageType];\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u5C0F\u5DE5\u5177 (SDK \u4E0E /embed \u5171\u7528) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport function xcMessage<K extends XcHostMessageType | XcFrameMessageType>(\n type: K,\n payload?: unknown,\n id?: string,\n): XcEnvelope<K, any> {\n const m: XcEnvelope<K, any> = { type, v: XC_PROTOCOL_VERSION, payload };\n if (id !== undefined) m.id = id;\n return m;\n}\n\n/** \u662F\u5426\u4E3A\u5408\u6CD5 xc \u4FE1\u5C01 (\u53EA\u68C0\u67E5\u7ED3\u6784, \u4E0D\u68C0\u67E5 payload)\u3002 */\nexport function isXcEnvelope(data: unknown): data is XcEnvelope {\n if (!data || typeof data !== 'object') return false;\n const d = data as Record<string, unknown>;\n return typeof d.type === 'string' && d.type.startsWith('xc.') && d.v === XC_PROTOCOL_VERSION;\n}\n\n/**\n * \u628A\u7528\u6237\u7ED9\u7684 origin \u89C4\u6574\u6210\u4E25\u683C\u7684 `scheme://host[:port]`\u3002\n * \u62D2\u7EDD '*' / \u901A\u914D / \u975E http(s) / \u5E26\u8DEF\u5F84\u7684\u5B57\u7B26\u4E32 \u2192 \u8FD4\u56DE null\u3002\n */\nexport function normalizeOrigin(input: string | null | undefined): string | null {\n if (!input || input === '*' || input === 'null') return null;\n try {\n const u = new URL(input);\n if (u.protocol !== 'https:' && u.protocol !== 'http:') return null;\n return u.origin;\n } catch {\n return null;\n }\n}\n", "/**\n * gesture-box.ts \u2014 iframe \u624B\u52BF (xc.gesture-move / xc.gesture-resize) \u5728\u5BBF\u4E3B\u4FA7\u7684\u7EAF\u903B\u8F91: \u6821\u9A8C + \u51E0\u4F55\u9650\u5E45\u3002\u96F6 DOM \u4F9D\u8D56, \u53EF\u5355\u6D4B\u3002\n *\n * \u5BBF\u4E3B SDK \u5BF9 iframe \u53D1\u6765\u7684\u624B\u52BF**\u4E0D\u4FE1\u4EFB**: \u8F7D\u8377\u9010\u5B57\u6BB5\u6821\u9A8C (\u7C7B\u578B / \u6709\u9650\u6570 / \u91CF\u7EA7 / \u89D2\u540D), \u5E8F\u53F7\u5FC5\u987B\u6309\u89C4\u5219\u9012\u589E (GestureGate),\n * \u4F4D\u7F6E / \u5C3A\u5BF8\u5168\u90E8\u5728\u8FD9\u91CC\u6309\"\u5F53\u524D\u89C6\u53E3 + \u6700\u5C0F / \u6700\u5927\u5C3A\u5BF8\"\u5939\u7D27, iframe \u8BF4\u591A\u5C11\u5C31\u79FB\u591A\u5C11\u662F\u4E0D\u53EF\u80FD\u7684\u3002\n * \u8BA1\u7B97\u4E00\u5F8B\u7528 start \u65F6\u7684\u76D2\u5B50 + \u7D2F\u8BA1\u4F4D\u79FB (totalDx / totalDy), \u4E0D\u7D2F\u52A0\u589E\u91CF: \u4E22\u5305 / \u5939\u7D27\u90FD\u4E0D\u4F1A\u8BA9\u7ED3\u679C\u6F02\u79FB\u3002\n */\nimport type { XcGestureCorner } from './protocol';\n\nexport interface Box { left: number; top: number; width: number; height: number }\nexport interface Viewport { width: number; height: number }\nexport interface ResizeLimits { minWidth: number; minHeight: number; maxWidth: number; maxHeight: number }\n\n/** \u9ED8\u8BA4\u9650\u5E45: \u6700\u5C0F 120x180 (\u518D\u5C0F\u89D2\u8272\u57FA\u672C\u770B\u4E0D\u6E05), \u6700\u5927\u53EA\u53D7\u89C6\u53E3\u9650\u5236\u3002 */\nexport const DEFAULT_RESIZE_LIMITS: Readonly<ResizeLimits> = Object.freeze({\n minWidth: 120, minHeight: 180, maxWidth: Infinity, maxHeight: Infinity,\n});\n\nexport interface XiaochunResizeLimits {\n /** \u6700\u5C0F\u5BBD (px), \u9ED8\u8BA4 120\u3002 */\n minWidth?: number;\n /** \u6700\u5C0F\u9AD8 (px), \u9ED8\u8BA4 180\u3002 */\n minHeight?: number;\n /** \u6700\u5927\u5BBD (px), \u9ED8\u8BA4\u53EA\u53D7\u89C6\u53E3\u9650\u5236\u3002 */\n maxWidth?: number;\n /** \u6700\u5927\u9AD8 (px), \u9ED8\u8BA4\u53EA\u53D7\u89C6\u53E3\u9650\u5236\u3002 */\n maxHeight?: number;\n}\n\nconst finitePositive = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v > 0;\n\n/** `resizable` \u9009\u9879 \u2192 \u9650\u5E45; false / undefined \u2192 null (\u5173\u95ED); true \u2192 \u9ED8\u8BA4\u9650\u5E45; \u5BF9\u8C61 \u2192 \u9010\u9879\u8986\u76D6 (\u975E\u6CD5\u503C\u7528\u9ED8\u8BA4)\u3002min \u4E0D\u4F1A\u8D85\u8FC7 max\u3002 */\nexport function normalizeResizable(v: boolean | XiaochunResizeLimits | undefined): ResizeLimits | null {\n if (!v) return null;\n const o = v === true ? {} : v;\n const minWidth = finitePositive(o.minWidth) ? o.minWidth : DEFAULT_RESIZE_LIMITS.minWidth;\n const minHeight = finitePositive(o.minHeight) ? o.minHeight : DEFAULT_RESIZE_LIMITS.minHeight;\n const maxWidth = finitePositive(o.maxWidth) ? Math.max(o.maxWidth, minWidth) : Infinity;\n const maxHeight = finitePositive(o.maxHeight) ? Math.max(o.maxHeight, minHeight) : Infinity;\n return { minWidth, minHeight, maxWidth, maxHeight };\n}\n\nconst clamp = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), Math.max(lo, hi));\n\n/** \u79FB\u52A8: \u8D77\u70B9\u76D2\u5B50 + \u7D2F\u8BA1\u4F4D\u79FB, \u5939\u5728\u89C6\u53E3\u5185 (\u76D2\u5B50\u6BD4\u89C6\u53E3\u5927\u65F6\u8D34\u5DE6\u4E0A)\u3002 */\nexport function moveBox(start: Box, totalDx: number, totalDy: number, vp: Viewport): Box {\n return {\n left: clamp(start.left + totalDx, 0, vp.width - start.width),\n top: clamp(start.top + totalDy, 0, vp.height - start.height),\n width: start.width,\n height: start.height,\n };\n}\n\n/**\n * \u7F29\u653E: \u88AB\u62D6\u7684\u89D2\u8DDF\u624B, \u5BF9\u89D2\u56FA\u5B9A; \u5BBD\u9AD8\u5939\u5728 [min, min(max, \u89C6\u53E3\u5185\u8FD8\u80FD\u4F38\u5C55\u7684\u7A7A\u95F4)]\u3002\n * \u4F8B: \u62D6 SE \u89D2 \u2192 \u5DE6\u4E0A\u56FA\u5B9A, \u53F3 / \u4E0B\u8FB9\u754C\u4E0D\u80FD\u8D8A\u8FC7\u89C6\u53E3; \u62D6 NW \u89D2 \u2192 \u53F3\u4E0B\u56FA\u5B9A, \u5DE6 / \u4E0A\u8FB9\u754C\u4E0D\u80FD\u8D8A\u8FC7\u89C6\u53E3\u3002\n */\nexport function resizeBox(start: Box, corner: XcGestureCorner, totalDx: number, totalDy: number, limits: ResizeLimits, vp: Viewport): Box {\n const west = corner === 'NW' || corner === 'SW';\n const north = corner === 'NW' || corner === 'NE';\n const right = start.left + start.width, bottom = start.top + start.height;\n const wantW = west ? start.width - totalDx : start.width + totalDx;\n const wantH = north ? start.height - totalDy : start.height + totalDy;\n const roomW = west ? right : vp.width - start.left;\n const roomH = north ? bottom : vp.height - start.top;\n const width = clamp(wantW, limits.minWidth, Math.min(limits.maxWidth, roomW));\n const height = clamp(wantH, limits.minHeight, Math.min(limits.maxHeight, roomH));\n return { left: west ? right - width : start.left, top: north ? bottom - height : start.top, width, height };\n}\n\n/** \u7A97\u53E3 / \u89C6\u53E3\u53D8\u5C0F\u540E\u628A\u76D2\u5B50\u91CD\u65B0\u5939\u56DE\u89C6\u53E3 (\u5C3A\u5BF8\u4E5F\u4E0D\u8D85\u8FC7\u89C6\u53E3)\u3002 */\nexport function fitBox(b: Box, vp: Viewport): Box {\n const width = Math.min(b.width, Math.max(1, vp.width)), height = Math.min(b.height, Math.max(1, vp.height));\n return { left: clamp(b.left, 0, vp.width - width), top: clamp(b.top, 0, vp.height - height), width, height };\n}\n\n// \u2500\u2500 \u8F7D\u8377\u6821\u9A8C \u2500\u2500\nconst CORNERS = new Set(['NW', 'NE', 'SW', 'SE']);\nconst PHASES = new Set(['start', 'move', 'end']);\nconst REASONS = new Set(['up', 'cancel', 'blur']);\n/** \u5355\u6B21\u7D2F\u8BA1\u4F4D\u79FB\u7684\u5408\u7406\u4E0A\u9650 (CSS px)\u3002\u5C4F\u5E55\u518D\u5927\u4E5F\u5230\u4E0D\u4E86, \u8D85\u8FC7\u7684\u4E00\u5F8B\u5F53\u4F5C\u4F2A\u9020\u3002 */\nexport const MAX_GESTURE_DELTA = 20_000;\n\nexport interface ParsedGesture {\n gesture: number;\n seq: number;\n phase: 'start' | 'move' | 'end';\n totalDx: number;\n totalDy: number;\n corner?: XcGestureCorner;\n}\n\nconst delta = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && Math.abs(v) <= MAX_GESTURE_DELTA;\nconst counter = (v: unknown): v is number => typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;\n\n/** \u6821\u9A8C iframe \u53D1\u6765\u7684\u624B\u52BF\u8F7D\u8377; \u4E0D\u5408\u6CD5\u8FD4\u56DE null\u3002kind='resize' \u8FD8\u8981\u6C42\u5408\u6CD5\u7684 corner\u3002 */\nexport function parseGesturePayload(kind: 'move' | 'resize', raw: unknown): ParsedGesture | null {\n if (raw === null || typeof raw !== 'object') return null;\n const p = raw as Record<string, unknown>;\n if (!counter(p.gesture) || !counter(p.seq) || typeof p.phase !== 'string' || !PHASES.has(p.phase)) return null;\n if (!delta(p.dx) || !delta(p.dy) || !delta(p.totalDx) || !delta(p.totalDy)) return null;\n if (p.reason !== undefined && (typeof p.reason !== 'string' || !REASONS.has(p.reason))) return null;\n const out: ParsedGesture = { gesture: p.gesture, seq: p.seq, phase: p.phase as ParsedGesture['phase'], totalDx: p.totalDx, totalDy: p.totalDy };\n if (kind === 'resize') {\n if (typeof p.corner !== 'string' || !CORNERS.has(p.corner)) return null;\n out.corner = p.corner as XcGestureCorner;\n }\n return out;\n}\n\n/**\n * \u624B\u52BF\u5E8F\u53F7\u95F8\u95E8: \u53EA\u653E\u884C\"\u5408\u6CD5\u7684\u624B\u52BF\u5E8F\u5217\" \u2014\u2014 start(gesture \u6BD4\u4E0A\u4E00\u4E2A\u5927, seq=0) \u2192 move* (seq \u4E25\u683C\u9012\u589E) \u2192 end\u3002\n * \u8FDF\u5230 / \u91CD\u653E / \u4E71\u5E8F / \u6CA1\u6709 start \u7684\u6D88\u606F\u4E00\u5F8B\u62D2\u7EDD\u3002\u4E00\u4E2A\u95F8\u95E8\u5BF9\u5E94\u4E00\u79CD\u624B\u52BF (move \u6216 resize)\u3002\n */\nexport class GestureGate {\n private lastGesture = 0;\n private lastSeq = -1;\n private open = false;\n\n get active(): boolean { return this.open; }\n\n accept(p: Pick<ParsedGesture, 'gesture' | 'seq' | 'phase'>): boolean {\n if (p.phase === 'start') {\n if (p.gesture <= this.lastGesture || p.seq !== 0) return false;\n this.lastGesture = p.gesture;\n this.lastSeq = 0;\n this.open = true;\n return true;\n }\n if (!this.open || p.gesture !== this.lastGesture || p.seq <= this.lastSeq) return false;\n this.lastSeq = p.seq;\n if (p.phase === 'end') this.open = false;\n return true;\n }\n\n /** \u5BBF\u4E3B\u4E3B\u52A8\u7ED3\u675F (\u5173\u95ED\u624B\u52BF / \u9500\u6BC1): \u4E4B\u540E\u540C\u4E00\u624B\u52BF\u7684\u8FDF\u5230\u6D88\u606F\u88AB\u62D2\u7EDD\u3002 */\n close(): void { this.open = false; }\n}\n", "/**\n * client.ts \u2014 \u65E0\u6846\u67B6\u3001\u96F6\u8FD0\u884C\u65F6\u4F9D\u8D56\u7684 Project XiaoChun \u5D4C\u5165 SDK\u3002\n *\n * const xc = createXiaochun({ container: '#avatar', transparent: true });\n * await xc.ready; // \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210 (xc.loaded)\n * await xc.say('\u4F60\u597D\u5440'); // \u5FF5\u5B8C (xc.utterance end) \u624D resolve\n *\n * \u9ED8\u8BA4 lazy: \u5148\u653E\u56FA\u5B9A\u5C3A\u5BF8\u7684\u5360\u4F4D (\u4E0D\u4EA7\u751F CLS), \u6D4F\u89C8\u5668\u7A7A\u95F2 + \u8FDB\u5165\u89C6\u53E3 + (\u6216\u70B9\u51FB/\u8C03\u7528 API) \u4E4B\u540E\u624D\u521B\u5EFA iframe\u3002\n */\nimport {\n XC_DEFAULT_SRC,\n isXcEnvelope,\n isXcId,\n normalizeOrigin,\n normalizeXcUiOption,\n XC_UI_PARTS,\n XC_WINDOW_CORNER_RADIUS,\n xcMessage,\n type XcAudioFormat,\n type XcAudioOptions,\n type XcConfig,\n type XcErrorCode,\n type XcExpressionPayload,\n type XcFrameMessage,\n type XcHeavyMode,\n type XcHitRegionPayload,\n type XcHostMessageType,\n type XcLang,\n type XcLoadProgressPayload,\n type XcMotionPayload,\n type XcOutfitChangedPayload,\n type XcOutfitInfo,\n type XcPrefetchedPayload,\n type XcReadyPayload,\n type XcSceneChangedPayload,\n type XcSceneId,\n type XcSceneInfo,\n type XcSttPayload,\n type XcStatePayload,\n type XcUiPart,\n type XcUtterancePayload,\n} from './protocol';\nimport {\n GestureGate, fitBox, moveBox, normalizeResizable, parseGesturePayload, resizeBox,\n type Box, type ResizeLimits, type Viewport, type XiaochunResizeLimits,\n} from './gesture-box';\n\nexport type { XiaochunResizeLimits } from './gesture-box';\nexport type XiaochunPosition = 'inline' | 'bottom-right' | 'bottom-left';\n/** lazy: false=\u7ACB\u5373\u521B\u5EFA; true/'idle'=\u8FDB\u5165\u89C6\u53E3\u4E14\u7A7A\u95F2\u540E\u521B\u5EFA; 'click'=\u4EC5\u70B9\u51FB\u5360\u4F4D\u6216\u8C03\u7528 API \u65F6\u521B\u5EFA\u3002 */\nexport type XiaochunLazy = boolean | 'idle' | 'click';\n\nexport interface XiaochunOptions {\n /** \u6302\u8F7D\u5BB9\u5668 (\u5143\u7D20\u6216\u9009\u62E9\u5668)\u3002 */\n container: HTMLElement | string;\n /** /embed \u9875\u9762\u5730\u5740, \u9ED8\u8BA4\u5B98\u65B9\u90E8\u7F72\u3002\u81EA\u5EFA/\u672C\u5730\u8C03\u8BD5\u65F6\u8986\u76D6\u3002 */\n src?: string;\n /** iframe \u7684 origin, \u9ED8\u8BA4\u7531 src \u63A8\u5BFC\u3002\u6240\u6709\u63E1\u624B/\u6D88\u606F\u6821\u9A8C\u90FD\u4EE5\u5B83\u4E3A\u51C6\u3002 */\n origin?: string;\n /** \u989D\u5916\u5141\u8BB8\u53D1 xc.ready \u7684 origin (\u5982 CDN \u91CD\u5B9A\u5411); \u9ED8\u8BA4\u53EA\u6709 origin\u3002\u4E0D\u652F\u6301 '*'\u3002 */\n allowedOrigins?: string[];\n lazy?: XiaochunLazy;\n /** \u8DDD\u89C6\u53E3\u591A\u5C11 px \u5185\u5C31\u5F00\u59CB\u52A0\u8F7D (IntersectionObserver rootMargin)\u3002\u8C03\u5927=\u66F4\u65E9\u52A0\u8F7D, \u66F4\u8017\u6D41\u91CF; \u8C03\u5C0F=\u66F4\u7701\u4F46\u6EDA\u5230\u65F6\u53EF\u80FD\u8FD8\u6CA1\u597D\u3002\u9ED8\u8BA4 200\u3002 */\n lazyMargin?: number;\n /** \u5360\u4F4D\u56FE URL / \u5143\u7D20; false = \u4E0D\u8981\u5360\u4F4D\u3002 */\n placeholder?: string | HTMLElement | false;\n /**\n * \u80CC\u666F\u900F\u660E (\u53E0\u5728\u5BBF\u4E3B\u9875\u4E0A)\u3002\u7B49\u4EF7\u4E8E `scene: 'transparent'`; \u540C\u65F6\u7ED9\u4E86 `scene` \u6216\u5DF2\u4FDD\u5B58\u7684\u504F\u597D\u65F6, \u4EE5\u5B83\u4EEC\u4E3A\u51C6\u3002\n * \u8FD0\u884C\u4E2D\u60F3\u5207\u6362\u8BF7\u7528 `setScene()`: SDK \u4F1A\u540C\u6B65\u5916\u58F3\u80CC\u666F\u548C\u7A7F\u900F\u3002\n */\n transparent?: boolean;\n /** \u521D\u59CB\u573A\u666F: 'light' | 'dark' | 'transparent' (\u4EE5 getScenes() \u4E3A\u51C6)\u3002\u7701\u7565 = \u8DDF\u968F transparent \u9009\u9879 / \u7CFB\u7EDF\u4EAE\u6697\u3002 */\n scene?: XcSceneId | (string & {});\n /** \u56FA\u5B9A\u5C3A\u5BF8, \u6570\u5B57=px, \u5B57\u7B26\u4E32=CSS \u957F\u5EA6\u3002\u52A1\u5FC5\u7ED9\u5B9A, \u5426\u5219\u65E0\u6CD5\u9884\u7559\u7A7A\u95F4 (CLS)\u3002\u9ED8\u8BA4 320x480\u3002 */\n width?: number | string;\n height?: number | string;\n position?: XiaochunPosition;\n /**\n * \u5141\u8BB8\u7528\u6237\u62D6\u52A8\u5934\u50CF, \u9ED8\u8BA4 false\u3002**\u624B\u52BF\u62D6\u52A8**: \u5728\u89D2\u8272\u4E0A\u6309\u4F4F\u5DE6\u952E\u62D6 (\u89E6\u5C4F: \u624B\u6307\u62D6) = \u79FB\u52A8\u6574\u4E2A\u5934\u50CF (\u8BC6\u522B\u5728 iframe \u91CC, \u590D\u7528 Tauri \u684C\u5BA0\u7684\u624B\u52BF\u72B6\u6001\u673A,\n * \u5BBF\u4E3B\u6267\u884C\u79FB\u52A8\u5E76\u9650\u5E45\u5728\u89C6\u53E3\u5185); \u900F\u660E + \u7A7F\u900F\u573A\u666F\u4E0B\u53EA\u6709\u70B9\u5728\u89D2\u8272\u4E0A\u624D\u63A5\u7BA1, \u5176\u4F59\u4F4D\u7F6E\u4ECD\u7A7F\u900F\u7ED9\u5BBF\u4E3B\u9875\u3002\u5185\u8054 (position: 'inline') \u7528 CSS translate \u4F4D\u79FB, \u4E0D\u6539\u53D8\u5E03\u5C40\u6D41\u3002\n * \u60AC\u6D6E\u6A21\u5F0F (bottom-right / bottom-left) \u540C\u6837\u8D70\u624B\u52BF (\u6539 left/top)\u3002\u8FD0\u884C\u4E2D\u53EF\u7528 `setDraggable()` \u5F00\u5173, \u4E0D\u91CD\u5EFA iframe\u3002\n * \u9700\u8981 /embed \u7684 capabilities.gestures (\u65E7\u7248\u6CA1\u6709 \u2192 \u624B\u52BF\u65E0\u6548, \u5E76\u89E6\u53D1\u4E00\u6B21 error{code:'unsupported'})\u3002\n */\n draggable?: boolean;\n /**\n * \u5916\u58F3\u5706\u89D2 (iframe / \u5360\u4F4D\u56FE / \u5916\u58F3\u4E00\u8D77\u88C1), \u6570\u5B57 = px, \u6216\u4EFB\u610F CSS \u957F\u5EA6\u3002\u9ED8\u8BA4: **\u975E\u900F\u660E\u573A\u666F (light / dark) = 20px** (\u4E0E Tauri \u684C\u5BA0\u7A97\u53E3\u7684\u5706\u89D2\u540C\u503C,\n * \u89C1 XC_WINDOW_CORNER_RADIUS), \u900F\u660E\u573A\u666F = 0 (\u6CA1\u6709\u5E95\u8272\u53EF\u88C1, \u89D2\u8272\u4E0D\u88AB\u88C1\u89D2)\u3002`--xc-radius` CSS \u53D8\u91CF\u4F18\u5148\u7EA7\u66F4\u9AD8\u3002\u8FD0\u884C\u4E2D\u53EF\u7528 `setBorderRadius()` \u6539, \u4E0D\u91CD\u5EFA iframe\u3002\n * \u5706\u89D2\u534A\u5F84\u662F\u56FA\u5B9A px, \u7F29\u653E (resizable) \u65F6\u4E0D\u968F\u5C3A\u5BF8\u53D8\u5F62\u3002\u4F20 0 \u6062\u590D\u65B9\u89D2\u3002\n */\n borderRadius?: number | string;\n /**\n * \u5141\u8BB8\u7528\u6237\u7F29\u653E\u5934\u50CF, \u9ED8\u8BA4 false\u3002**\u89D2\u843D\u7F29\u653E**: iframe \u56DB\u4E2A\u89D2\u5404\u6709\u4E00\u4E2A 40px \u70ED\u533A (\u60AC\u505C\u51FA\u73B0\u5706\u5F27\u63D0\u793A, \u5149\u6807\u53D8\u6210\u7F29\u653E\u7BAD\u5934), \u6309\u4F4F\u62D6\u52A8 = \u7F29\u653E, \u5BF9\u89D2\u56FA\u5B9A\u3002\n * true = \u9ED8\u8BA4\u9650\u5E45 (\u6700\u5C0F 120x180, \u6700\u5927\u53EA\u53D7\u89C6\u53E3\u9650\u5236); \u5BF9\u8C61\u53EF\u81EA\u5B9A\u4E49 minWidth / minHeight / maxWidth / maxHeight (px)\u3002\n * \u7F29\u653E\u53EA\u6539\u5916\u58F3\u5C3A\u5BF8, **\u4E0D\u91CD\u5EFA iframe**: \u6A21\u578B / \u52A8\u753B / \u5BF9\u8BDD\u72B6\u6001\u90FD\u4FDD\u6301\u3002\u901A\u8FC7 `resize` \u4E8B\u4EF6\u62FF\u5230\u65B0\u5C3A\u5BF8, `getBox()` \u968F\u65F6\u8BFB\u53D6\u3002\u8FD0\u884C\u4E2D\u53EF\u7528 `setResizable()` \u5F00\u5173\u3002\n * \u9700\u8981 capabilities.gestures (\u65E7\u7248 /embed \u65E0\u6548, \u89E6\u53D1\u4E00\u6B21 error{code:'unsupported'})\u3002\n */\n resizable?: boolean | XiaochunResizeLimits;\n lang?: XcLang;\n /** \u521D\u59CB\u670D\u88C5: \u5185\u7F6E\u670D\u88C5 id (\u5982 'xiaochun_maid', \u89C1 getOutfits())\u3002\u672A\u77E5 id \u56DE\u9000\u9ED8\u8BA4\u670D\u88C5, \u5E76\u89E6\u53D1 error{code:'unknown_id'}\u3002 */\n outfit?: string;\n /**\n * @deprecated \u8BF7\u6539\u7528 `outfit`\u3002\u503C\u662F\u5185\u7F6E\u670D\u88C5 id \u65F6\u7B49\u4EF7\u4E8E `outfit`; https URL \u4E0D\u80FD\u518D\u901A\u8FC7\u521B\u5EFA\u9009\u9879\u4F20\u5165\n * (\u4EFB\u610F URL \u9700\u8981 `allowCustomModel: true`, \u4E4B\u540E\u7528 `setModel({ url })`)\u3002\n */\n model?: string;\n /**\n * \u5141\u8BB8 `setModel({ url })` \u52A0\u8F7D\u4EFB\u610F https .vrm/.vrmaddon/.vrmbase, \u9ED8\u8BA4 false (\u5173\u95ED)\u3002\n * \u6A21\u578B\u662F\u7B2C\u4E09\u65B9\u6587\u4EF6, \u4F1A\u5728 iframe \u91CC\u88AB\u89E3\u6790, \u53EA\u5728\u4F60\u4FE1\u4EFB\u8BE5 URL \u65F6\u6253\u5F00\u3002\u5185\u7F6E\u670D\u88C5 (`setOutfit`) \u4E0D\u53D7\u5F71\u54CD\u3002\n */\n allowCustomModel?: boolean;\n /**\n * \u504F\u597D (\u670D\u88C5 + \u573A\u666F) \u5728\u5BBF\u4E3B\u9875\u7684\u989D\u5916\u4FDD\u5B58 (\u53EF\u9009), \u9ED8\u8BA4 false\u3002\u4FDD\u5B58\u4F4D\u7F6E\u662F**\u5BBF\u4E3B\u9875**\u7684 localStorage; \u8BFB\u51FA\u6765\u540E\u4F5C\u4E3A\u663E\u5F0F\u503C\u4F20\u7ED9 iframe, \u6240\u4EE5\u4F1A\u76D6\u8FC7 iframe \u81EA\u5DF1 localStorage \u91CC\u5B58\u7684 (iframe \u672C\u6765\u5C31\u4F1A\u8BB0\u4F4F\u7528\u6237\u7684\u9009\u62E9, \u4F46\u5B83\u7684\u5B58\u50A8\u53EF\u80FD\u88AB\u6D4F\u89C8\u5668\u5206\u533A)\u3002\n * false \u4E0D\u4FDD\u5B58\n * 'host' \u4FDD\u5B58\u5230 localStorage['xiaochun:prefs']\n * \u5176\u5B83\u5B57\u7B26\u4E32 \u4FDD\u5B58\u5230 localStorage[\u8BE5\u5B57\u7B26\u4E32] (\u540C\u9875\u591A\u4E2A\u5B9E\u4F8B\u4E92\u4E0D\u8986\u76D6\u65F6\u7528)\n * \u4F18\u5148\u7EA7: \u663E\u5F0F\u7684 outfit / scene \u9009\u9879 > \u5DF2\u4FDD\u5B58\u7684\u504F\u597D > \u9ED8\u8BA4\u3002\u53EA\u6709 setOutfit / setScene \u5F15\u8D77\u7684\u53D8\u5316\u4F1A\u5199\u5165\u3002\n */\n persist?: false | 'host' | (string & {});\n /**\n * \u8981\u663E\u793A\u7684 iframe \u5185\u7F6E\u754C\u9762\u90E8\u4EF6 (\u6570\u7EC4, \u9ED8\u8BA4\u4E0D\u5199 = \u5168\u4E0D\u663E\u793A):\n * 'chat' \u5E95\u90E8\u804A\u5929\u680F (\u5BF9\u8BDD\u8D70 WebLLM, \u4F1A\u591A\u4E0B\u8F7D\u4E00\u90E8\u5206\u4EE3\u7801)\n * 'bubble' \u5934\u9876\u6C14\u6CE1 (\u8BF4\u8BDD\u6587\u672C / \u72B6\u6001)\n * 'outfit' \u6362\u88C5\u6309\u94AE } \u5916\u89C2/\u6587\u6848/\u4EA4\u4E92\u4E0E\u4E3B\u7AD9 TopHeader \u4E00\u81F4; \u70B9\u6309\u94AE\u8D70\u548C setOutfit() / setScene() \u540C\u4E00\u6761\u767D\u540D\u5355 + \u4E32\u884C (last-wins) \u8DEF\u5F84,\n * 'scene' \u6362\u573A\u666F\u6309\u94AE } \u7167\u5E38\u89E6\u53D1 outfit-changed / scene-changed, \u5BBF\u4E3B\u7528 SDK \u6362\u88C5\u65F6\u6309\u94AE\u72B6\u6001\u540C\u6B65\u3002\u504F\u597D\u7531 iframe \u81EA\u5DF1\u7684 localStorage \u8BB0\u4F4F (\u663E\u5F0F outfit/scene \u4F18\u5148); \u60F3\u81EA\u5DF1\u5B58\u4E5F\u53EF\u7528 persist \u6216\u76D1\u542C\u4E8B\u4EF6\u3002\n * \u4F8B: `ui: ['outfit', 'scene']`\u3002\u672A\u77E5\u540D\u5B57\u5FFD\u7565\u5E76 console.warn\u3002\u521B\u5EFA\u671F\u9009\u9879: \u53D8\u5316\u4F1A\u91CD\u5EFA iframe\u3002\n * 'outfit' / 'scene' \u53EA\u5BF9\u65B0\u7248 /embed \u6709\u6548 (\u65E7\u7248\u5FFD\u7565\u672A\u77E5\u90E8\u4EF6\u540D)\u3002\n * @deprecated \u5E03\u5C14\u5199\u6CD5: `ui: true` (0.1.14 \u7684\u65E7\u5199\u6CD5) \u7B49\u4EF7\u4E8E `['chat', 'bubble']` \u5E76 console.warn; \u4E0D\u8981\u518D\u7528\u3002\n */\n ui?: XcUiPart[] | boolean;\n heavy?: XcHeavyMode;\n /**\n * \u81EA\u52A8\u9884\u53D6\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB (\u4E4B\u540E setOutfit \u4E0D\u8D70\u7F51\u7EDC), \u9ED8\u8BA4 false\u3002\n * true = \u5168\u90E8\u5185\u7F6E\u670D\u88C5 **\u9664\u4E86**\u5A5A\u7EB1 (13.9MB); string[] = \u53EA\u9884\u53D6\u8FD9\u4E9B id\u3002\n * \u53EA\u5728 `heavy: 'eager'` \u65F6\u81EA\u52A8\u89E6\u53D1 (\u6A21\u578B\u9996\u6B21\u52A0\u8F7D\u5B8C\u6210\u540E\u53D1\u4E00\u6B21 xc.prefetch): \u5E76\u53D1 1, \u6392\u5728 EMAGE \u52A0\u8F7D\u4E4B\u540E, \u4E0D\u4F1A\u548C\u6362\u88C5\u62A2\u5E26\u5BBD\u3002\n * heavy \u4E3A\u9ED8\u8BA4 'lazy' \u65F6\u672C\u9009\u9879\u4E0D\u751F\u6548 \u2014\u2014 \u60F3\u6309\u9700\u9884\u53D6\u8BF7\u76F4\u63A5\u8C03\u7528 `prefetch()`\u3002\n */\n prefetch?: boolean | string[];\n /**\n * iframe \u5185\u6EDA\u8F6E\u7F29\u653E, \u9ED8\u8BA4 true (\u4E0E\u4E3B\u7AD9\u4E00\u81F4)\u3002\u900F\u660E\u573A\u666F\u53EA\u5728\u6307\u9488\u843D\u5728\u89D2\u8272\u4E0A\u65F6\u7F29\u653E, \u5176\u4F59\u4F4D\u7F6E\u6EDA\u8F6E\u7A7F\u900F\u7ED9\u5BBF\u4E3B\u9875;\n * \u4E0D\u900F\u660E\u573A\u666F\u6574\u4E2A iframe \u533A\u57DF\u7684\u6EDA\u8F6E = \u7F29\u653E (\u4F1A\u541E\u6389\u8BE5\u533A\u57DF\u7684\u9875\u9762\u6EDA\u52A8)\u3002\u4F20 false \u9501\u5B9A (URL controls=0)\u3002\n */\n controls?: boolean;\n /** \u89C6\u53E3\u5916\u81EA\u52A8 xc.pause / \u56DE\u6765 xc.resume, \u9ED8\u8BA4 true\u3002 */\n autoPause?: boolean;\n /** \u900F\u660E\u6A21\u5F0F\u4E0B\u6309\"\u662F\u5426\u70B9\u5728\u89D2\u8272\u4E0A\"\u5207\u6362 iframe \u7684 pointer-events, \u9ED8\u8BA4 = transparent\u3002 */\n passthrough?: boolean;\n /** iframe sandbox \u5C5E\u6027; false = \u4E0D\u52A0\u3002\u9ED8\u8BA4\u5141\u8BB8 scripts/same-origin/popups\u3002 */\n sandbox?: string | false;\n /** \u63E1\u624B\u8D85\u65F6 (ms), \u8D85\u65F6 emit error{code:'timeout'}\u3002\u8C03\u5927\u9002\u5408\u6162\u7F51\u7EDC, \u8C03\u5C0F\u53CD\u9988\u66F4\u5FEB\u3002\u9ED8\u8BA4 20000\u3002 */\n handshakeTimeout?: number;\n /**\n * \u7ED9 iframe \u7684 `allow` \u8FFD\u52A0 `cross-origin-isolated` (\u9ED8\u8BA4 false: allow \u4ECD\u662F 'microphone; autoplay')\u3002\n * \u4EC5\u5F53\u5BBF\u4E3B\u9875\u81EA\u5DF1\u5DF2\u8DE8\u6E90\u9694\u79BB (\u54CD\u5E94\u5934 COOP: same-origin + COEP: credentialless / require-corp) \u65F6\u624D\u751F\u6548;\n * \u5F00\u542F\u540E iframe \u5185 crossOriginIsolated=true \u2192 EMAGE \u7684 onnxruntime-web \u53EF\u7528\u591A\u7EBF\u7A0B wasm (SharedArrayBuffer)\u3002\n * \u526F\u4F5C\u7528: \u5BBF\u4E3B\u9875\u4E0A\u7684\u7B2C\u4E09\u65B9\u8D44\u6E90/iframe \u4E5F\u5FC5\u987B\u6EE1\u8DB3 COEP, \u89C1 docs/EMBED.md\u3002\u5BBF\u4E3B\u672A\u9694\u79BB\u65F6\u5F00\u4E86\u4E5F\u65E0\u5BB3 (\u6D4F\u89C8\u5668\u5FFD\u7565)\u3002\n */\n crossOriginIsolated?: boolean;\n zIndex?: number;\n}\n\n/** speakAudio / speakAudioStream \u7684\u9009\u9879\u3002 */\nexport interface XiaochunAudioOptions extends XcAudioOptions {\n /** \u7F16\u7801; \u7701\u7565 = 'encoded' (\u5BB9\u5668\u683C\u5F0F)\u3002\u4F20 ArrayBuffer \u7684\u539F\u59CB PCM \u65F6\u5FC5\u987B\u5199 'pcm16' | 'float32'\u3002 */\n format?: XcAudioFormat;\n /** MIME \u63D0\u793A (\u5982 'audio/mpeg'); Blob \u4F1A\u81EA\u52A8\u53D6 blob.type\u3002 */\n mimeType?: string;\n /** \u539F\u59CB PCM \u7684\u91C7\u6837\u7387 (8000~96000, \u6574\u6BB5\u9ED8\u8BA4 16000, \u6D41\u5F0F\u5FC5\u586B); \u5BB9\u5668\u683C\u5F0F\u5FFD\u7565\u3002 */\n sampleRate?: number;\n /** \u539F\u59CB PCM \u58F0\u9053\u6570 (\u4EA4\u9519), 1 \u6216 2\u3002 */\n channels?: 1 | 2;\n /**\n * ArrayBuffer \u662F\u5426\u7528 transferable \u96F6\u62F7\u8D1D\u53D1\u9001 (\u9ED8\u8BA4 true)\u3002\n * true: \u53D1\u51FA\u540E\u4F20\u5165\u7684\u90A3\u4E2A ArrayBuffer \u4F1A\u88AB detach (byteLength \u53D8 0), \u9002\u5408\u5927\u97F3\u9891;\n * false: \u7ED3\u6784\u5316\u514B\u9686\u4E00\u4EFD, \u539F buffer \u4ECD\u53EF\u7528, \u4F46\u591A\u4E00\u6B21\u62F7\u8D1D\u3002TypedArray \u89C6\u56FE\u603B\u662F\u62F7\u8D1D\u5176\u8303\u56F4\u540E\u518D\u8F6C\u79FB\u3002\n */\n transfer?: boolean;\n /** URL \u5B57\u7B26\u4E32\u7684\u83B7\u53D6\u4F4D\u7F6E: 'host' (\u9ED8\u8BA4) = \u5BBF\u4E3B\u9875 fetch \u540E\u8F6C\u79FB\u7ED9 iframe, \u4E0D\u9700\u8981 iframe \u80FD\u8BBF\u95EE\u8BE5 URL; 'frame' = \u628A URL \u4EA4\u7ED9 iframe fetch (\u9700 https + CORS)\u3002 */\n fetch?: 'host' | 'frame';\n /** \u89E6\u53D1\u540E\u7ACB\u5373\u6253\u65AD\u8FD9\u6B21\u8BF4\u8BDD (\u53D1 xc.audio.end{abort:true})\u3002 */\n signal?: AbortSignal;\n}\n\nexport type XiaochunAudioSource = ArrayBuffer | ArrayBufferView | Blob | string;\n\n/** \u6D41\u5F0F\u97F3\u9891\u53E5\u67C4: write \u539F\u59CB PCM \u5757, end \u6536\u5C3E, abort \u7ACB\u5373\u6253\u65AD; done \u5728\u8BF4\u8BDD\u7ED3\u675F (\u6216\u88AB\u62A2\u5360) \u65F6 resolve\u3002 */\nexport interface XiaochunAudioStream {\n write(data: Int16Array | Float32Array | ArrayBuffer): void;\n end(): void;\n abort(): void;\n readonly done: Promise<void>;\n}\n\nexport type XiaochunErrorCode = XcErrorCode | 'timeout';\nexport interface XiaochunError { code: XiaochunErrorCode; message: string; command?: string }\n\n/** `move` / `resize` \u4E8B\u4EF6\u8F7D\u8377: \u624B\u52BF\u5404\u9636\u6BB5\u5916\u58F3\u5728\u89C6\u53E3\u4E2D\u7684\u4F4D\u7F6E\u4E0E\u5C3A\u5BF8 (CSS px)\u3002 */\nexport interface XiaochunBoxEvent { phase: 'start' | 'move' | 'end'; left: number; top: number; width: number; height: number }\n\nexport interface XiaochunEvents {\n /** xc.ready \u63E1\u624B\u6210\u529F (\u534F\u8BAE\u5C42)\u3002 */\n handshake: XcReadyPayload;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210 (= xc.loaded)\u3002 */\n ready: { model: string };\n progress: XcLoadProgressPayload;\n state: XcStatePayload;\n stt: XcSttPayload;\n utterance: XcUtterancePayload;\n 'hit-region': XcHitRegionPayload;\n /** \u670D\u88C5\u5DF2\u751F\u6548 (\u542B\u9996\u6B21\u52A0\u8F7D, initial:true)\u3002\u540C\u76EE\u6807\u7684\u91CD\u590D\u8BF7\u6C42\u4E0D\u4F1A\u518D\u89E6\u53D1\u3002 */\n 'outfit-changed': XcOutfitChangedPayload;\n /** \u573A\u666F\u5DF2\u751F\u6548 (\u542B\u63E1\u624B\u540E\u4E0A\u62A5\u7684\u5F53\u524D\u573A\u666F, initial:true)\u3002 */\n 'scene-changed': XcSceneChangedPayload;\n /** \u7528\u6237\u62D6\u52A8\u5934\u50CF (draggable): start / move / end \u5404\u53D1\u4E00\u6B21, \u4F4D\u7F6E\u5DF2\u9650\u5E45\u3002 */\n move: XiaochunBoxEvent;\n /** \u7528\u6237\u7F29\u653E\u5934\u50CF (resizable): start / move / end \u5404\u53D1\u4E00\u6B21, \u5C3A\u5BF8\u5DF2\u9650\u5E45\u3002 */\n resize: XiaochunBoxEvent;\n error: XiaochunError;\n destroy: undefined;\n}\n\nexport interface XiaochunInstance {\n readonly element: HTMLElement;\n readonly iframe: HTMLIFrameElement | null;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210\u65F6 resolve; destroy \u65F6 reject\u3002 */\n readonly ready: Promise<void>;\n /** \u624B\u52A8\u521B\u5EFA iframe (lazy \u6A21\u5F0F\u4E0B\u7B49\u4EF7\u4E8E\"\u7528\u6237\u70B9\u51FB\")\u3002 */\n activate(): void;\n say(text: string, opts?: { mode?: 'speak' | 'chat' }): Promise<void>;\n /**\n * \u76F4\u63A5\u64AD\u653E\u5BBF\u4E3B\u7ED9\u7684\u97F3\u9891 (\u4E0D\u7ECF\u8FC7 TTS): iframe \u5185\u89E3\u7801 \u2192 EMAGE \u751F\u6210\u52A8\u4F5C + \u53E3\u578B, \u5FF5\u5B8C (xc.utterance end) \u624D resolve\u3002\n * \u9996\u6B21\u8C03\u7528\u624D\u52A0\u8F7D EMAGE \u6A21\u578B (\u9996\u6B21\u4F1A\u6162); opts.motion=false \u5219\u53EA\u64AD\u653E\u4E0D\u52A0\u8F7D\u3002\n */\n speakAudio(source: XiaochunAudioSource, opts?: XiaochunAudioOptions): Promise<void>;\n /** \u6D41\u5F0F\u97F3\u9891 (\u539F\u59CB PCM \u5206\u5757)\u3002sampleRate \u5FC5\u586B; \u9996\u4E2A write \u5F00\u542F\u8BF4\u8BDD\u3002 */\n speakAudioStream(opts: XiaochunAudioOptions & { sampleRate: number }): XiaochunAudioStream;\n motion(m: XcMotionPayload | string): Promise<void>;\n expression(name: XcExpressionPayload['name']): Promise<void>;\n /** TODO: \u534F\u8BAE\u5DF2\u9884\u7559, /embed \u6682\u672A\u5B9E\u73B0 \u2192 \u4F1A\u6536\u5230 error{code:'unsupported'}\u3002 */\n lookAt(x: number, y: number): Promise<void>;\n /**\n * \u6362\u5185\u7F6E\u670D\u88C5 (id \u89C1 getOutfits())\u3002Promise \u5728\u670D\u88C5**\u751F\u6548\u540E** resolve (xc.outfit-changed)\u3002\n * \u5E76\u53D1\u89C4\u5219: \u4E32\u884C + last-wins \u2014\u2014 \u52A0\u8F7D\u4E2D\u518D\u6B21\u8C03\u7528\u4F1A\u6392\u961F, \u6392\u961F\u7684\u65E7\u8BF7\u6C42\u88AB\u66F4\u65B0\u7684\u9876\u6389\u65F6 reject `[busy]` (\u53EF\u5FFD\u7565, \u4EE5\u6700\u65B0\u4E00\u6B21\u4E3A\u51C6);\n * \u8BF4\u8BDD\u4E0D\u4F1A\u88AB\u6253\u65AD, \u6362\u88C5\u5728\u540E\u53F0\u5B8C\u6210\u540E\u624D\u751F\u6548\u3002\u76EE\u6807\u5DF2\u662F\u5F53\u524D\u670D\u88C5\u5219\u76F4\u63A5 resolve\u3002\n * \u65E7\u7248 /embed (\u63E1\u624B\u91CC\u6CA1\u6709 capabilities.outfits) \u4F1A reject `[unsupported]`\u3002\n */\n setOutfit(id: string): Promise<void>;\n /** \u5207\u573A\u666F ('light' | 'dark' | 'transparent', \u89C1 getScenes())\u3002SDK \u540C\u6B65\u5916\u58F3\u80CC\u666F\u3001\u7A7F\u900F\u5F00\u5173\u4E0E pointer-events\u3002 */\n setScene(id: XcSceneId | (string & {})): Promise<void>;\n /**\n * \u9884\u53D6\u5185\u7F6E\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB (\u53EA\u4E0B\u8F7D, \u4E0D\u89E3\u538B\u4E0D\u5408\u6210)\u3002ids \u7701\u7565 = \u5168\u90E8\u5185\u7F6E\u670D\u88C5, \u5A5A\u7EB1 (13.9MB) \u9664\u5916; \u663E\u5F0F\u70B9\u540D\u5219\u7167\u505A\u3002\n * \u5168\u5C40\u4E32\u884C (\u5E76\u53D1 1); resolve \u7684\u7ED3\u679C\u91CC failed \u975E\u7A7A\u65F6\u53EF\u7A0D\u540E\u91CD\u8BD5\u3002\u8FDB\u5EA6\u89C1 progress \u4E8B\u4EF6 (payload.phase === 'prefetch')\u3002\n * \u65E7\u7248 /embed reject `[unsupported]`; \u7528\u6237\u5F00\u4E86\u7701\u6D41\u91CF\u6A21\u5F0F\u65F6 resolve \u4E14 skipped:'save-data'\u3002\n */\n prefetch(ids?: string[]): Promise<XcPrefetchedPayload>;\n /** \u63E1\u624B\u540E\u8FD4\u56DE\u53EF\u6362\u7684\u5185\u7F6E\u670D\u88C5 (\u4E0D\u542B\u88F8\u6A21); \u65E7\u7248 /embed \u8FD4\u56DE []\u3002\u4F1A\u89E6\u53D1 iframe \u521B\u5EFA (lazy \u6A21\u5F0F)\u3002 */\n getOutfits(): Promise<XcOutfitInfo[]>;\n /** \u63E1\u624B\u540E\u8FD4\u56DE\u53EF\u5207\u7684\u573A\u666F; \u65E7\u7248 /embed \u8FD4\u56DE []\u3002 */\n getScenes(): Promise<XcSceneInfo[]>;\n /** \u6700\u8FD1\u4E00\u6B21 xc.outfit-changed \u7684\u670D\u88C5 id (\u81EA\u5B9A\u4E49 URL \u6A21\u578B / \u5C1A\u672A\u52A0\u8F7D = null)\u3002 */\n readonly outfit: string | null;\n /** \u6700\u8FD1\u4E00\u6B21 xc.scene-changed \u7684\u573A\u666F id (\u63E1\u624B\u524D = null)\u3002 */\n readonly scene: string | null;\n /**\n * \u65E7\u547D\u4EE4, \u4FDD\u7559\u517C\u5BB9\u3002\u5185\u7F6E\u670D\u88C5\u8BF7\u6539\u7528 `setOutfit` (\u5E76\u53D1\u66F4\u7A33\u3001\u80FD\u62FF\u5230\u5B8C\u6210\u901A\u77E5)\u3002\n * `{ url }` \u9ED8\u8BA4\u88AB\u62D2\u7EDD (reject `[unsupported]`), \u9700\u521B\u5EFA\u9009\u9879 `allowCustomModel: true`\u3002\n */\n setModel(m: string | { url?: string; outfit?: string; name?: string }): Promise<void>;\n setConfig(cfg: XcConfig): Promise<void>;\n /** \u8FD0\u884C\u65F6\u8BBE\u7F6E\u5916\u58F3\u5C3A\u5BF8 (\u6570\u5B57 = px, \u5B57\u7B26\u4E32 = CSS \u957F\u5EA6); \u4E0D\u91CD\u5EFA iframe\u3002\u7528\u6237\u7F29\u653E\u540E\u5BBF\u4E3B\u8981\u540C\u6B65\u81EA\u5DF1\u7684\u72B6\u6001\u65F6\u7528 `resize` \u4E8B\u4EF6\u3002 */\n setSize(width: number | string, height: number | string): void;\n /** \u5916\u58F3\u5F53\u524D\u5728\u89C6\u53E3\u4E2D\u7684\u4F4D\u7F6E\u4E0E\u5C3A\u5BF8 (CSS px)\u3002 */\n getBox(): { left: number; top: number; width: number; height: number };\n /** \u8FD0\u884C\u65F6\u5F00\u5173\u624B\u52BF\u62D6\u52A8 (\u7B49\u4EF7\u4E8E `draggable` \u9009\u9879), \u4E0D\u91CD\u5EFA iframe\u3002 */\n /** \u6539\u5916\u58F3\u5706\u89D2 (\u6570\u5B57 px / CSS \u957F\u5EA6); \u4F20 undefined \u6062\u590D\u9ED8\u8BA4 (\u975E\u900F\u660E 20px / \u900F\u660E 0)\u3002 */\n setBorderRadius(radius: number | string | undefined): void;\n setDraggable(on: boolean): void;\n /** \u8FD0\u884C\u65F6\u5F00\u5173 / \u8C03\u6574\u89D2\u843D\u7F29\u653E (\u7B49\u4EF7\u4E8E `resizable` \u9009\u9879), \u4E0D\u91CD\u5EFA iframe\u3002false = \u5173\u3002 */\n setResizable(on: boolean | XiaochunResizeLimits): void;\n startListening(): Promise<void>;\n stopListening(): Promise<void>;\n mic(enabled: boolean): Promise<void>;\n pause(): void;\n resume(): void;\n destroy(): void;\n on<K extends keyof XiaochunEvents>(event: K, cb: (payload: XiaochunEvents[K]) => void): () => void;\n}\n\nconst FALLBACK_PLACEHOLDER =\n 'data:image/svg+xml;utf8,' +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 120 180\"><defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#f6b8ae\"/><stop offset=\"1\" stop-color=\"#ea8377\"/></linearGradient></defs><ellipse cx=\"60\" cy=\"170\" rx=\"34\" ry=\"6\" fill=\"#000\" opacity=\".12\"/><circle cx=\"60\" cy=\"48\" r=\"26\" fill=\"url(#g)\" opacity=\".75\"/><path d=\"M26 160c2-40 18-62 34-62s32 22 34 62z\" fill=\"url(#g)\" opacity=\".6\"/></svg>',\n );\n\nconst css = (v: number | string | undefined, d: string) =>\n v === undefined ? d : typeof v === 'number' ? `${v}px` : v;\n\nexport function createXiaochun(options: XiaochunOptions): XiaochunInstance {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n throw new Error('[project-xiaochun] createXiaochun must run in a browser');\n }\n const container =\n typeof options.container === 'string' ? document.querySelector<HTMLElement>(options.container) : options.container;\n if (!container) throw new Error(`[project-xiaochun] container not found: ${String(options.container)}`);\n\n // \u2500\u2500 \u5730\u5740 / origin \u2500\u2500\n const src = options.src ?? XC_DEFAULT_SRC;\n let srcUrl: URL;\n try { srcUrl = new URL(src, window.location.href); } catch { throw new Error(`[project-xiaochun] invalid src: ${src}`); }\n const frameOrigin = normalizeOrigin(options.origin ?? srcUrl.origin);\n if (!frameOrigin) throw new Error('[project-xiaochun] invalid origin (wildcards are not allowed)');\n const trusted = new Set<string>([frameOrigin]);\n for (const o of options.allowedOrigins ?? []) {\n const n = normalizeOrigin(o);\n if (!n) throw new Error(`[project-xiaochun] invalid allowedOrigins entry: ${o} (wildcards are not allowed)`);\n trusted.add(n);\n }\n\n // \u2500\u2500 \u504F\u597D (persist, \u53EF\u9009): \u5BBF\u4E3B localStorage; iframe \u53E6\u6709\u81EA\u5DF1\u7684\u5B58\u50A8 \u2500\u2500\n const prefsKey = options.persist === 'host' ? 'xiaochun:prefs' : typeof options.persist === 'string' && options.persist ? options.persist : null;\n type Prefs = { outfit?: string; scene?: string };\n const readPrefs = (): Prefs => {\n if (!prefsKey) return {};\n try {\n const raw = JSON.parse(window.localStorage.getItem(prefsKey) ?? 'null') as Record<string, unknown> | null;\n const out: Prefs = {};\n if (raw && typeof raw === 'object') {\n if (isXcId(raw.outfit)) out.outfit = raw.outfit;\n if (isXcId(raw.scene)) out.scene = raw.scene;\n }\n return out;\n } catch { return {}; }\n };\n const writePrefs = (patch: { [K in keyof Prefs]?: string | null }) => {\n if (!prefsKey) return;\n try {\n const next: Record<string, string> = { ...readPrefs() };\n for (const [k, v] of Object.entries(patch)) { if (v) next[k] = v; else delete next[k]; }\n window.localStorage.setItem(prefsKey, JSON.stringify(next));\n } catch { /* localStorage \u4E0D\u53EF\u7528 (\u9690\u79C1\u6A21\u5F0F / \u914D\u989D): \u9759\u9ED8\u653E\u5F03\u4FDD\u5B58 */ }\n };\n const prefs = readPrefs();\n\n if (options.model !== undefined && options.outfit === undefined) {\n console.warn('[project-xiaochun] option \"model\" is deprecated, use \"outfit\" (built-in outfit id).');\n }\n // ui: \u90E8\u4EF6\u540D\u6570\u7EC4 (\u767D\u540D\u5355); \u5E03\u5C14 true \u662F\u5F03\u7528\u7684\u65E7\u5199\u6CD5 (= chat + bubble)\n const uiParse = normalizeXcUiOption(options.ui);\n const uiParts = uiParse.parts;\n if (uiParse.legacy) console.warn('[project-xiaochun] option \"ui: true\" is deprecated, use an array of parts, e.g. ui: [\\'chat\\', \\'bubble\\', \\'outfit\\', \\'scene\\'].');\n if (uiParse.unknown.length) console.warn(`[project-xiaochun] ignoring unknown ui part(s): ${uiParse.unknown.join(', ')} (known: ${XC_UI_PARTS.join(', ')})`);\n const outfitOpt = options.outfit ?? (isXcId(options.model) ? options.model : undefined);\n const initialOutfit = outfitOpt ?? prefs.outfit;\n const initialScene = options.scene ?? prefs.scene ?? (options.transparent ? 'transparent' : undefined);\n // \u573A\u666F\u540D\u672A\u77E5 (\u65E7\u7248/\u81EA\u5B9A\u4E49\u90E8\u7F72) \u65F6\u9000\u56DE transparent \u9009\u9879; \u63E1\u624B\u540E\u7684 xc.scene-changed \u4F1A\u6821\u6B63\n let transparent = initialScene === 'transparent' || (initialScene !== 'light' && initialScene !== 'dark' && (options.transparent ?? false));\n let passthrough = options.passthrough ?? transparent;\n const lazy: XiaochunLazy = options.lazy ?? true;\n const position = options.position ?? 'inline';\n const handshakeTimeout = options.handshakeTimeout ?? 20_000;\n\n // \u2500\u2500 DOM: wrapper (\u56FA\u5B9A\u5C3A\u5BF8, \u9632 CLS) \u2500\u2500\n const wrapper = document.createElement('div');\n wrapper.setAttribute('data-xiaochun', '');\n const ws = wrapper.style;\n ws.position = position === 'inline' ? 'relative' : 'fixed';\n ws.width = css(options.width, '320px');\n ws.height = css(options.height, '480px');\n ws.maxWidth = '100%';\n ws.overflow = 'visible';\n ws.contain = 'layout style';\n // \u2500\u2500 \u6837\u5F0F hook: \u5BBF\u4E3B\u7528 CSS \u81EA\u5B9A\u4E49\u5C5E\u6027\u63A7\u5236\u5916\u89C2 (\u81EA\u5B9A\u4E49\u5C5E\u6027\u4F1A\u7A7F\u900F Shadow DOM, \u5728\u5BB9\u5668\u6216\u4EFB\u610F\u7956\u5148\u4E0A\u8BBE\u7F6E\u5373\u53EF) \u2500\u2500\n // \u6CE8\u610F: \u53EA\u80FD\u5F71\u54CD iframe \u7684\u300C\u5916\u58F3\u300D(\u5706\u89D2/\u9634\u5F71/\u4F4D\u7F6E/\u5C42\u7EA7/\u80CC\u666F); iframe \u5185\u90E8 (\u89D2\u8272\u6E32\u67D3\u3001\u6C14\u6CE1) \u662F\u8DE8\u57DF\u6587\u6863, \u5BBF\u4E3B CSS \u78B0\u4E0D\u5230\u3002\n // --xc-radius \u5706\u89D2, CSS \u957F\u5EA6, \u9ED8\u8BA4 0\u3002\u8303\u56F4 0 ~ \u5BBD\u5EA6\u7684\u4E00\u534A (50% = \u5706\u5F62\u5934\u50CF\u6846)\u3002\u8C03\u5927 = \u66F4\u5706; \u8FC7\u5927\u4F1A\u88C1\u6389\u89D2\u8272\u7684\u5934/\u811A\u3002\n // --xc-shadow box-shadow \u7B80\u5199, \u9ED8\u8BA4 none\u3002\u900F\u660E\u60AC\u6D6E\u5934\u50CF\u5EFA\u8BAE\u4FDD\u6301 none (\u5426\u5219\u4F1A\u51FA\u73B0\u4E00\u4E2A\u65B9\u5757\u9634\u5F71); \u5361\u7247\u5F0F\u5D4C\u5165\u53EF\u7528 '0 8px 24px rgba(0,0,0,.18)'\u3002\n // --xc-z-index \u4EC5\u60AC\u6D6E (position\u2260inline) \u751F\u6548, \u9ED8\u8BA4 2147483000 (\u63A5\u8FD1 int \u4E0A\u9650, \u76D6\u4F4F\u7EDD\u5927\u591A\u6570\u9875\u9762\u5143\u7D20)\u3002\u8C03\u5C0F = \u8BA9\u5BBF\u4E3B\u7684\u5F39\u7A97/\u5BFC\u822A\u76D6\u5728\u5934\u50CF\u4E0A\u9762\u3002\n // --xc-offset-x \u4EC5\u60AC\u6D6E: \u8DDD\u5C4F\u5E55\u5DE6/\u53F3\u8FB9\u7684\u8FB9\u8DDD, \u9ED8\u8BA4 16px\u3002\u8C03\u5927 = \u79BB\u8FB9\u7F18\u66F4\u8FDC (\u79FB\u52A8\u7AEF\u6CE8\u610F\u907F\u5F00\u7CFB\u7EDF\u624B\u52BF\u533A, \u5EFA\u8BAE \u2265 12px)\u3002\n // --xc-offset-y \u4EC5\u60AC\u6D6E: \u8DDD\u5C4F\u5E55\u5E95\u8FB9\u7684\u8FB9\u8DDD, \u9ED8\u8BA4 16px\u3002\u8C03\u5927 = \u62AC\u9AD8 (\u907F\u5F00\u5E95\u90E8\u5BFC\u822A\u680F/Cookie \u6A2A\u5E45)\u3002\n // --xc-bg \u975E\u900F\u660E\u6A21\u5F0F\u4E0B iframe \u52A0\u8F7D\u524D/\u5706\u89D2\u5916\u7684\u5E95\u8272, \u9ED8\u8BA4 transparent\u3002transparent: true \u65F6\u5FFD\u7565\u3002\n ws.boxShadow = 'var(--xc-shadow, none)';\n const applyWrapperBg = () => { ws.background = transparent ? '' : 'var(--xc-bg, transparent)'; };\n applyWrapperBg();\n // \u5706\u89D2: \u9009\u9879 > (\u975E\u900F\u660E 20px / \u900F\u660E 0); \u5BBF\u4E3B\u7684 --xc-radius CSS \u53D8\u91CF\u59CB\u7EC8\u4F18\u5148\n let radiusOpt: number | string | undefined = options.borderRadius;\n const radiusValue = () => (radiusOpt !== undefined ? css(radiusOpt, '0px') : transparent ? '0px' : `${XC_WINDOW_CORNER_RADIUS}px`);\n const applyRadius = () => {\n const v = `var(--xc-radius, ${radiusValue()})`;\n ws.borderRadius = v;\n if (placeholderEl) placeholderEl.style.borderRadius = v;\n if (iframe) iframe.style.borderRadius = v;\n };\n ws.borderRadius = `var(--xc-radius, ${radiusValue()})`;\n if (position === 'bottom-right') { ws.right = 'var(--xc-offset-x, 16px)'; ws.bottom = 'var(--xc-offset-y, 16px)'; }\n if (position === 'bottom-left') { ws.left = 'var(--xc-offset-x, 16px)'; ws.bottom = 'var(--xc-offset-y, 16px)'; }\n if (position !== 'inline') ws.zIndex = `var(--xc-z-index, ${options.zIndex ?? 2147483000})`;\n ws.pointerEvents = 'none'; // \u5BB9\u5668\u672C\u8EAB\u4E0D\u5403\u4E8B\u4EF6; \u5360\u4F4D/iframe \u5404\u81EA\u5F00\n wrapper.setAttribute('part', 'wrapper'); // ::part(wrapper) (\u4EC5 <xiaochun-avatar> \u7684 Shadow DOM \u5185\u6709\u610F\u4E49)\n container.appendChild(wrapper);\n\n let placeholderEl: HTMLElement | null = null;\n if (options.placeholder !== false) {\n if (options.placeholder instanceof HTMLElement) placeholderEl = options.placeholder;\n else {\n const img = document.createElement('img');\n img.src = options.placeholder || FALLBACK_PLACEHOLDER;\n img.alt = 'Project XiaoChun';\n img.decoding = 'async';\n img.width = 320; img.height = 480; // \u6709 width/height \u5C5E\u6027 + \u4E0B\u9762\u7684 100% \u6837\u5F0F, \u89E3\u7801\u524D\u4E5F\u4E0D\u6296\u52A8\n placeholderEl = img;\n }\n const ps = placeholderEl.style;\n placeholderEl.setAttribute('part', 'placeholder');\n ps.borderRadius = `var(--xc-radius, ${radiusValue()})`;\n ps.position = 'absolute'; ps.inset = '0'; ps.width = '100%'; ps.height = '100%';\n ps.objectFit = 'contain'; ps.transition = 'opacity .25s ease'; ps.pointerEvents = 'auto';\n ps.cursor = lazy === false ? 'default' : 'pointer';\n placeholderEl.addEventListener('click', () => activate());\n wrapper.appendChild(placeholderEl);\n }\n\n // \u2500\u2500 \u4E8B\u4EF6 \u2500\u2500\n const listeners = new Map<string, Set<(p: any) => void>>();\n const emit = <K extends keyof XiaochunEvents>(ev: K, payload: XiaochunEvents[K]) => {\n listeners.get(ev)?.forEach((cb) => { try { cb(payload); } catch (e) { console.error('[project-xiaochun] listener error', e); } });\n };\n\n // \u2500\u2500 ready promise \u2500\u2500\n let resolveReady!: () => void;\n let rejectReady!: (e: Error) => void;\n const ready = new Promise<void>((res, rej) => { resolveReady = res; rejectReady = rej; });\n ready.catch(() => {}); // \u907F\u514D\u6CA1\u4EBA await \u65F6\u7684 unhandled rejection\n\n // \u2500\u2500 \u72B6\u6001 \u2500\u2500\n let iframe: HTMLIFrameElement | null = null;\n let port: MessagePort | null = null;\n let destroyed = false;\n let userPaused = false;\n let autoPaused = false;\n let loaded = false;\n let lastHit = false;\n let caps: XcReadyPayload['capabilities'] | null = null;\n let currentOutfit: string | null = null;\n let currentScene: string | null = null;\n /** \u547D\u4EE4\u4F9D\u8D56\u7684 capabilities \u5B57\u6BB5; \u63E1\u624B\u540E\u82E5 iframe \u6CA1\u6709 (\u65E7\u7248 /embed) \u5C31\u672C\u5730 reject, \u4E0D\u53D1\u51FA\u53BB\u3002 */\n type CapKey = 'outfits' | 'scenes' | 'prefetch';\n const queue: Array<{ type: XcHostMessageType; payload?: unknown; id?: string; transfer?: Transferable[]; requires?: CapKey }> = [];\n const pending = new Map<string, { resolve: (v?: unknown) => void; reject: (e: Error) => void; sawEnd: boolean }>();\n let idSeq = 0;\n let handshakeTimer: ReturnType<typeof setTimeout> | null = null;\n let io: IntersectionObserver | null = null;\n let idleHandle: number | null = null;\n let resolveHandshake!: () => void;\n const handshaked = new Promise<void>((res) => { resolveHandshake = res; });\n\n /** \u672C\u5730\u62D2\u7EDD\u4E00\u6761\u547D\u4EE4 (iframe \u4E0D\u652F\u6301): reject \u5BF9\u5E94 Promise + \u89E6\u53D1 error \u4E8B\u4EF6\u3002 */\n const failLocal = (type: XcHostMessageType, id: string | undefined, code: XiaochunErrorCode, message: string) => {\n emit('error', { code, message, command: type });\n const p = id ? pending.get(id) : undefined;\n if (p && id) { pending.delete(id); p.reject(new Error(`[${code}] ${message}`)); }\n };\n const unsupportedByFrame = (type: XcHostMessageType, id: string | undefined) =>\n failLocal(type, id, 'unsupported', `${type} is not supported by this /embed deployment (older version; its xc.ready has no capabilities for it)`);\n\n const postToFrame = (type: XcHostMessageType, payload?: unknown, id?: string, transfer?: Transferable[], requires?: CapKey) => {\n if (!port) { queue.push({ type, payload, id, transfer, requires }); return; }\n if (requires && !caps?.[requires]) { unsupportedByFrame(type, id); return; }\n port.postMessage(xcMessage(type, payload, id), transfer ?? []);\n };\n\n const send = (type: XcHostMessageType, payload?: unknown, wait = false, transfer?: Transferable[], fixedId?: string, requires?: CapKey): Promise<any> => {\n if (destroyed) return Promise.reject(new Error('[project-xiaochun] instance destroyed'));\n if (!iframe) activate(); // \u4EFB\u4F55\u4EA4\u4E92 API \u90FD\u89C6\u4E3A\"\u7528\u6237\u610F\u56FE\", \u7ACB\u5373\u521B\u5EFA\n const id = fixedId ?? `c${++idSeq}`;\n // \u547D\u4EE4\u5E94\u7B54\u53EF\u4EE5\u5E26\u4E00\u4E2A\u503C (\u5982 xc.prefetched \u7684\u7ED3\u679C); \u5176\u5B83\u547D\u4EE4 resolve(undefined)\n const p: Promise<any> = wait\n ? new Promise<any>((resolve, reject) => pending.set(id, { resolve, reject, sawEnd: false }))\n : Promise.resolve();\n postToFrame(type, payload, id, transfer, requires);\n return p;\n };\n\n // \u2500\u2500 \u5BBF\u4E3B\u97F3\u9891 \u2500\u2500\n /** TypedArray \u89C6\u56FE \u2192 \u53EA\u542B\u5176\u8303\u56F4\u7684\u72EC\u7ACB ArrayBuffer (\u62F7\u8D1D); ArrayBuffer \u539F\u6837\u8FD4\u56DE\u3002 */\n const toBuffer = (d: ArrayBuffer | ArrayBufferView): ArrayBuffer =>\n d instanceof ArrayBuffer ? d : (d.buffer as ArrayBuffer).slice(d.byteOffset, d.byteOffset + d.byteLength);\n const bindAbort = (signal: AbortSignal | undefined, id: string) => {\n if (!signal) return;\n const abort = () => { if (!destroyed) postToFrame('xc.audio.end', { abort: true }, id); };\n if (signal.aborted) abort(); else signal.addEventListener('abort', abort, { once: true });\n };\n const speakAudio = async (source: XiaochunAudioSource, opts: XiaochunAudioOptions = {}): Promise<void> => {\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n if (!iframe) activate(); // \u5148\u521B\u5EFA iframe (lazy \u6A21\u5F0F\u4E0B\u4E0E fetch \u5E76\u884C, \u7701\u4E00\u70B9\u9996\u6B21\u5EF6\u8FDF)\n const { signal, transfer, fetch: fetchWhere, ...rest } = opts;\n const payload: Record<string, unknown> = { ...rest };\n const list: Transferable[] = [];\n if (typeof source === 'string') {\n if (fetchWhere === 'frame') payload.source = source;\n else {\n const res = await fetch(source);\n if (!res.ok) throw new Error(`[project-xiaochun] audio fetch failed: HTTP ${res.status}`);\n const buf = await res.arrayBuffer();\n payload.source = buf; list.push(buf);\n payload.mimeType ??= res.headers.get('content-type') ?? undefined;\n }\n } else if (typeof Blob !== 'undefined' && source instanceof Blob) {\n payload.source = source; // Blob \u8D70\u7ED3\u6784\u5316\u514B\u9686 (\u6D4F\u89C8\u5668\u5185\u90E8\u5F15\u7528\u540C\u4E00\u4EFD\u6570\u636E, \u4E0D\u6574\u6BB5\u590D\u5236)\n payload.mimeType ??= source.type || undefined;\n } else {\n const buf = toBuffer(source as ArrayBuffer | ArrayBufferView);\n payload.source = buf;\n // \u89C6\u56FE\u603B\u662F\u62F7\u8D1D\u540E\u7684\u65B0 buffer \u2192 \u8F6C\u79FB; \u7528\u6237\u4F20\u5165\u7684 ArrayBuffer \u4EC5\u5728 transfer !== false \u65F6\u8F6C\u79FB (\u4F1A\u88AB detach)\n if (!(source instanceof ArrayBuffer) || transfer !== false) list.push(buf);\n }\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n const id = `c${++idSeq}`;\n const done = send('xc.audio', payload, true, list, id);\n bindAbort(signal, id); // \u5FC5\u987B\u5728 send \u4E4B\u540E (\u4FE1\u53F7\u5DF2 aborted \u65F6, abort \u6D88\u606F\u8981\u6392\u5728 xc.audio \u540E\u9762)\n return done;\n };\n const speakAudioStream = (opts: XiaochunAudioOptions & { sampleRate: number }): XiaochunAudioStream => {\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n const { signal, transfer, fetch: _f, mimeType: _m, ...rest } = opts;\n const id = `c${++idSeq}`;\n let started = false;\n let ended = false;\n let fmt: 'pcm16' | 'float32' | null = rest.format === 'pcm16' || rest.format === 'float32' ? rest.format : null;\n let done: Promise<void> = Promise.resolve();\n const handle: XiaochunAudioStream = {\n write(data) {\n if (ended) throw new Error('[project-xiaochun] audio stream already ended');\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n if (data instanceof Int16Array) fmt ??= 'pcm16';\n else if (data instanceof Float32Array) fmt ??= 'float32';\n if (!fmt) throw new Error('[project-xiaochun] speakAudioStream: set opts.format when writing raw ArrayBuffers');\n const buf = toBuffer(data);\n const body: Record<string, unknown> = { data: buf, format: fmt, sampleRate: rest.sampleRate, channels: rest.channels };\n if (!started) {\n started = true;\n body.text = rest.text; body.motion = rest.motion; body.lipsync = rest.lipsync;\n done = send('xc.audio.chunk', body, true, [buf], id);\n bindAbort(signal, id);\n } else {\n postToFrame('xc.audio.chunk', body, id, !(data instanceof ArrayBuffer) || transfer !== false ? [buf] : []);\n }\n },\n end() {\n if (ended) return;\n ended = true;\n if (started) postToFrame('xc.audio.end', {}, id);\n },\n abort() {\n if (ended && !started) return;\n ended = true;\n if (started) postToFrame('xc.audio.end', { abort: true }, id);\n },\n get done() { return done; },\n };\n return handle;\n };\n\n // \u2500\u2500 iframe \u521B\u5EFA \u2500\u2500\n function buildUrl(): string {\n const u = new URL(srcUrl.href);\n u.searchParams.set('host', window.location.origin); // iframe \u7AEF\u7528\u5B83\u505A\u63E1\u624B\u767D\u540D\u5355\n if (transparent) u.searchParams.set('transparent', '1');\n if (uiParts.length) u.searchParams.set('ui', uiParts.join(','));\n if (options.lang) u.searchParams.set('lang', options.lang);\n if (options.heavy) u.searchParams.set('heavy', options.heavy);\n if (options.controls === false) u.searchParams.set('controls', '0');\n if (initialScene && isXcId(initialScene)) u.searchParams.set('scene', initialScene);\n if (initialOutfit) u.searchParams.set('outfit', initialOutfit);\n return u.href;\n }\n\n function activate(): void {\n if (destroyed || iframe) return;\n cancelIdle();\n io?.disconnect(); io = null;\n const f = document.createElement('iframe');\n f.title = 'Project XiaoChun';\n f.loading = 'lazy';\n f.allow = options.crossOriginIsolated === true\n ? 'microphone; autoplay; cross-origin-isolated' // \u5BBF\u4E3B\u5DF2 COOP/COEP \u9694\u79BB\u65F6, \u989D\u5916\u59D4\u6D3E\u8DE8\u6E90\u9694\u79BB \u2192 iframe \u5185 SharedArrayBuffer / \u591A\u7EBF\u7A0B wasm\n : 'microphone; autoplay'; // \u5BBF\u4E3B\u5FC5\u987B\u59D4\u6D3E: \u9EA6\u514B\u98CE (STT) + \u81EA\u52A8\u64AD\u653E (TTS \u97F3\u9891; \u7F3A\u5B83\u5219\u70B9\u51FB\u5BBF\u4E3B\u9875\u540E iframe \u5185 AudioContext \u4ECD\u88AB\u62E6)\n f.referrerPolicy = 'strict-origin-when-cross-origin';\n if (options.sandbox !== false) {\n f.setAttribute('sandbox', options.sandbox ?? 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox');\n }\n f.setAttribute('allowtransparency', 'true');\n f.setAttribute('scrolling', 'no');\n const s = f.style;\n s.position = 'absolute'; s.inset = '0'; s.width = '100%'; s.height = '100%';\n s.border = '0'; s.background = 'transparent'; s.colorScheme = 'normal';\n s.borderRadius = `var(--xc-radius, ${radiusValue()})`; // \u5706\u89D2\u88C1\u526A iframe \u5185\u5BB9 (\u5BBF\u4E3B CSS \u53EA\u80FD\u6539\u8FD9\u5C42\u5916\u58F3, \u6539\u4E0D\u5230 iframe \u5185\u90E8)\n f.setAttribute('part', 'iframe');\n s.opacity = '0'; s.transition = 'opacity .25s ease';\n s.pointerEvents = passthrough ? 'none' : 'auto';\n f.src = buildUrl();\n iframe = f;\n wrapper.appendChild(f);\n if (placeholderEl) placeholderEl.style.cursor = 'default';\n handshakeTimer = setTimeout(() => {\n if (!port) emit('error', { code: 'timeout', message: `no xc.ready from ${frameOrigin} within ${handshakeTimeout}ms` });\n }, handshakeTimeout);\n setupAutoPause();\n if (passthrough) enablePassthrough();\n }\n\n // \u2500\u2500 \u6765\u81EA iframe \u7684\u63E1\u624B (window message) \u2500\u2500\n const onWindowMessage = (ev: MessageEvent) => {\n if (destroyed || !iframe || ev.source !== iframe.contentWindow) return; // \u53EA\u8BA4\u6211\u4EEC\u8FD9\u4E2A iframe\n if (!trusted.has(ev.origin)) {\n emit('error', { code: 'origin_denied', message: `ignored message from untrusted origin ${ev.origin}` });\n return;\n }\n const data = ev.data;\n if (!isXcEnvelope(data) || data.type !== 'xc.ready' || port) return; // \u63E1\u624B\u53EA\u505A\u4E00\u6B21\n const ch = new MessageChannel();\n port = ch.port1;\n port.onmessage = onPortMessage;\n caps = (data.payload as XcReadyPayload | undefined)?.capabilities ?? null;\n // targetOrigin = \u5DF2\u6821\u9A8C\u7684 ev.origin, \u7EDD\u4E0D\u7528 '*'\u3002allowCustomModel \u8D70 xc.init \u7684 config (\u4E0D\u8FDB URL), \u65E7 iframe \u4F1A\u5FFD\u7565\u672A\u77E5\u5B57\u6BB5\n // \u624B\u52BF\u5F00\u5173\u968F xc.init \u4E00\u8D77\u4EA4\u7ED9 iframe (iframe \u9ED8\u8BA4\u4E0D\u8BC6\u522B\u4EFB\u4F55\u624B\u52BF); \u65E7\u7248 /embed \u6CA1\u6709 capabilities.gestures \u2192 \u4E0D\u53D1\n const gWant = wantGestures();\n sentGestures = gWant;\n const initConfig: XcConfig = {\n ...(options.allowCustomModel ? { allowCustomModel: true } : {}),\n ...(gWant.move || gWant.resize ? { gestures: gWant } : {}),\n };\n iframe.contentWindow!.postMessage(\n xcMessage('xc.init', { hostOrigin: window.location.origin, ...(Object.keys(initConfig).length ? { config: initConfig } : {}) }),\n ev.origin,\n [ch.port2],\n );\n warnGestureUnsupported();\n if (handshakeTimer) { clearTimeout(handshakeTimer); handshakeTimer = null; }\n emit('handshake', data.payload as XcReadyPayload);\n resolveHandshake();\n for (const m of queue.splice(0)) {\n if (m.requires && !caps?.[m.requires]) unsupportedByFrame(m.type, m.id);\n else port.postMessage(xcMessage(m.type, m.payload, m.id), m.transfer ?? []);\n }\n syncPause();\n };\n window.addEventListener('message', onWindowMessage);\n\n /** \u547D\u4EE4\u5E94\u7B54: \u7528\u540C\u4E00\u4E2A\u4FE1\u5C01 id resolve \u5BF9\u5E94\u7684 Promise (xc.outfit-changed / xc.scene-changed)\u3002 */\n function ack(id: string | undefined, value?: unknown) {\n const p = id ? pending.get(id) : undefined;\n if (p && id) { pending.delete(id); p.resolve(value); }\n }\n\n // \u2500\u2500 \u6765\u81EA iframe \u7684\u7AEF\u53E3\u6D88\u606F \u2500\u2500\n function onPortMessage(ev: MessageEvent) {\n const data = ev.data as XcFrameMessage;\n if (!isXcEnvelope(data)) return;\n switch (data.type) {\n case 'xc.load.progress': emit('progress', data.payload); break;\n case 'xc.loaded':\n if (!loaded) {\n loaded = true;\n // \u81EA\u52A8\u9884\u53D6: \u53EA\u5728 heavy:'eager' \u4E14 iframe \u58F0\u660E\u652F\u6301\u65F6; \u5931\u8D25 / \u90E8\u5206\u5931\u8D25\u90FD\u4E0D\u6253\u6270\u5BBF\u4E3B (\u663E\u5F0F prefetch() \u624D\u8FD4\u56DE\u7ED3\u679C)\n if (options.prefetch && options.heavy === 'eager' && caps?.prefetch) {\n const ids = Array.isArray(options.prefetch) ? options.prefetch : undefined;\n void api.prefetch(ids).catch(() => {});\n }\n if (iframe) iframe.style.opacity = '1';\n if (placeholderEl) {\n const el = placeholderEl;\n el.style.opacity = '0'; el.style.pointerEvents = 'none';\n setTimeout(() => el.remove(), 300);\n placeholderEl = null;\n }\n resolveReady();\n }\n emit('ready', data.payload);\n break;\n case 'xc.outfit-changed': {\n const pl = data.payload;\n if (!pl.noop) {\n currentOutfit = pl.id;\n emit('outfit-changed', pl);\n if (!pl.initial && pl.id) writePrefs({ outfit: pl.id }); // \u53EA\u8BB0\u7528\u6237/\u5BBF\u4E3B\u4E3B\u52A8\u6362\u7684, \u4E0D\u8BB0\u9ED8\u8BA4\u670D\u88C5\n }\n ack(data.id);\n break;\n }\n case 'xc.scene-changed': {\n const pl = data.payload;\n currentScene = pl.id;\n if (pl.transparent !== transparent) applyTransparency(pl.transparent); // iframe \u662F\u4E8B\u5B9E\u6E90: \u540C\u6B65\u5916\u58F3\u80CC\u666F / \u7A7F\u900F / pointer-events\n if (!pl.noop) {\n emit('scene-changed', pl);\n if (!pl.initial) writePrefs({ scene: pl.id });\n }\n ack(data.id);\n break;\n }\n case 'xc.prefetched': ack(data.id, data.payload); break;\n case 'xc.state': emit('state', data.payload); break;\n case 'xc.stt': emit('stt', data.payload); break;\n case 'xc.utterance': {\n emit('utterance', data.payload);\n const p = data.id ? pending.get(data.id) : undefined;\n if (p && data.payload.phase === 'end') { pending.delete(data.id!); p.resolve(); }\n break;\n }\n case 'xc.hit-region': {\n const { hit } = data.payload;\n emit('hit-region', data.payload);\n if (passthrough && iframe && hit !== lastHit) {\n lastHit = hit;\n iframe.style.pointerEvents = hit ? 'auto' : 'none';\n }\n break;\n }\n case 'xc.gesture-move': onGesture('move', data.payload); break;\n case 'xc.gesture-resize': onGesture('resize', data.payload); break;\n case 'xc.error': {\n const { code, message, command } = data.payload;\n emit('error', { code, message, command });\n // \u521D\u59CB ?outfit= / ?scene= \u88AB iframe \u5224\u4E3A\u975E\u6CD5: \u5DF2\u4FDD\u5B58\u7684\u504F\u597D\u662F\u574F\u7684, \u6E05\u6389\u514D\u5F97\u6BCF\u6B21\u90FD\u62A5\n if (code === 'unknown_id' && (command === 'outfit' || command === 'scene')) writePrefs({ [command]: null });\n const p = data.id ? pending.get(data.id) : undefined;\n if (p && data.id) { pending.delete(data.id); p.reject(new Error(`[${code}] ${message}`)); }\n break;\n }\n default: break;\n }\n }\n\n // \u2500\u2500 \u5BBF\u4E3B pointer \u2192 iframe (\u900F\u660E\u7A7F\u900F\u6A21\u5F0F) \u2500\u2500\n // iframe \u5904\u4E8E pointer-events:none \u65F6, \u5BBF\u4E3B\u9875\u7684 pointermove \u624D\u662F\u552F\u4E00\u7EBF\u7D22:\n // - \u6307\u9488\u4E0D\u5728 iframe \u8303\u56F4\u5185\u65F6\u53EA\u505A\u4E00\u6B21\u5EC9\u4EF7\u7684\u77E9\u5F62\u6BD4\u8F83 (\u77E9\u5F62\u7F13\u5B58, \u4E0D\u5728\u6BCF\u5E27 getBoundingClientRect \u4EE5\u514D\u5F3A\u5236\u56DE\u6D41);\n // - \u6307\u9488\u5728\u8303\u56F4\u5185\u65F6\u6BCF\u5E27\u6700\u591A\u53D1\u4E00\u6B21 xc.pointer, \u4E14\u79FB\u52A8\u4E0D\u8DB3 2px \u6216\u8DDD\u4E0A\u6B21\u4E0D\u8DB3 32ms \u5219\u8DF3\u8FC7, \u907F\u514D iframe \u91CC\u6BCF\u5E27\u4E00\u6B21\u5C04\u7EBF\u68C0\u6D4B\u3002\n const POINTER_MIN_INTERVAL_MS = 32;\n const POINTER_MIN_MOVE_PX = 2;\n let pointerRaf = 0;\n let lastPtr: { x: number; y: number } | null = null;\n let lastPosted: { x: number; y: number; t: number } | null = null;\n let rectCache: DOMRect | null = null;\n let rectRo: ResizeObserver | null = null;\n let rectAt = 0;\n const invalidateRect = () => { rectCache = null; };\n const getRect = (): DOMRect | null => {\n if (!iframe) return null;\n const now = performance.now();\n // \u515C\u5E95 TTL: \u5185\u8054\u5E03\u5C40\u88AB\u9875\u9762\u5176\u5B83\u5185\u5BB9\u63A8\u52A8 (\u4E0D\u89E6\u53D1 resize/scroll) \u65F6, \u6700\u591A 400ms \u540E\u81EA\u6108\n if (!rectCache || now - rectAt > 400) { rectCache = iframe.getBoundingClientRect(); rectAt = now; }\n return rectCache;\n };\n const onHostPointer = (e: PointerEvent) => {\n if (!iframe || !port || iframe.style.pointerEvents === 'auto') return; // iframe \u81EA\u5DF1\u62FF\u5230\u4E8B\u4EF6\u65F6\u7531\u5B83\u4E0A\u62A5\n lastPtr = { x: e.clientX, y: e.clientY };\n if (pointerRaf) return;\n pointerRaf = requestAnimationFrame(() => {\n pointerRaf = 0;\n if (!iframe || !port || !lastPtr) return;\n const r = getRect();\n if (!r) return;\n const x = lastPtr.x - r.left, y = lastPtr.y - r.top;\n if (x < 0 || y < 0 || x > r.width || y > r.height) {\n lastPosted = null;\n if (lastHit) { lastHit = false; iframe.style.pointerEvents = 'none'; }\n return;\n }\n const now = performance.now();\n if (lastPosted && now - lastPosted.t < POINTER_MIN_INTERVAL_MS) return;\n if (lastPosted && Math.abs(x - lastPosted.x) < POINTER_MIN_MOVE_PX && Math.abs(y - lastPosted.y) < POINTER_MIN_MOVE_PX) return;\n lastPosted = { x, y, t: now };\n port.postMessage(xcMessage('xc.pointer', { x, y }));\n });\n };\n // \u7A7F\u900F\u76D1\u542C\u53EF\u542F\u505C (\u8FD0\u884C\u4E2D\u5207 scene \u65F6\u9700\u8981): enable / disable \u90FD\u5E42\u7B49\u3002\n let passthroughActive = false;\n function enablePassthrough() {\n if (passthroughActive || !iframe) return;\n passthroughActive = true;\n window.addEventListener('pointermove', onHostPointer, { passive: true });\n // \u89E6\u5C4F\u6CA1\u6709 hover: \u70B9\u4E00\u4E0B (pointerdown) \u4E5F\u63A2\u6D4B\u4E00\u6B21\u547D\u4E2D, \u547D\u4E2D\u540E iframe \u8F6C auto, \u4E0B\u4E00\u6B21\u70B9\u51FB\u5373\u53EF\u843D\u5230\u89D2\u8272 / \u5185\u7F6E\u6309\u94AE\u4E0A\n window.addEventListener('pointerdown', onHostPointer, { passive: true });\n window.addEventListener('scroll', invalidateRect, { passive: true, capture: true });\n window.addEventListener('resize', invalidateRect, { passive: true });\n if (typeof ResizeObserver !== 'undefined') {\n rectRo = new ResizeObserver(invalidateRect);\n rectRo.observe(iframe);\n }\n }\n function disablePassthrough() {\n if (!passthroughActive) return;\n passthroughActive = false;\n window.removeEventListener('pointermove', onHostPointer);\n window.removeEventListener('pointerdown', onHostPointer);\n window.removeEventListener('scroll', invalidateRect, true);\n window.removeEventListener('resize', invalidateRect);\n rectRo?.disconnect(); rectRo = null;\n if (pointerRaf) { cancelAnimationFrame(pointerRaf); pointerRaf = 0; }\n lastPtr = null;\n }\n /**\n * \u8FD0\u884C\u4E2D\u5207\u6362\u900F\u660E \u2194 \u975E\u900F\u660E (xc.scene-changed \u9A71\u52A8): \u540C\u6B65\u5916\u58F3\u80CC\u666F\u3001\u5F00\u5173\u7A7F\u900F\u76D1\u542C\u3001\u91CD\u7F6E\u547D\u4E2D\u72B6\u6001\u3002\n * - \u5207\u5230\u975E\u900F\u660E: \u5F3A\u5236 iframe pointer-events:auto (\u6574\u5757\u753B\u5E03\u90FD\u662F\u89D2\u8272\u80CC\u666F, \u4E0D\u8BE5\u7A7F\u900F), \u5173\u6389\u7A7F\u900F\u76D1\u542C;\n * - \u5207\u5230\u900F\u660E: passthrough \u9009\u9879\u663E\u5F0F\u7ED9\u4E86\u5C31\u6309\u5B83, \u5426\u5219\u6253\u5F00; iframe \u5148 none, \u7B49 xc.pointer / xc.hit-region \u518D\u5207 auto;\n * - \u4E24\u79CD\u60C5\u51B5\u90FD\u6E05\u6389 lastHit / lastPosted / \u77E9\u5F62\u7F13\u5B58, \u5426\u5219 iframe \u4FA7\u5DF2\u91CD\u7F6E\u7684\u53BB\u91CD\u72B6\u6001\u4F1A\u548C\u8FD9\u91CC\u5BF9\u4E0D\u4E0A, \u5BFC\u81F4\u6307\u9488\u4E0D\u52A8\u65F6\u7B2C\u4E00\u6B21\u547D\u4E2D\u88AB\u541E\u3002\n */\n function applyTransparency(next: boolean) {\n transparent = next;\n applyWrapperBg();\n applyRadius();\n passthrough = next ? (options.passthrough ?? true) : false;\n lastHit = false; lastPosted = null; rectCache = null;\n if (passthrough) enablePassthrough(); else disablePassthrough();\n if (iframe) iframe.style.pointerEvents = passthrough ? 'none' : 'auto';\n }\n\n // \u2500\u2500 \u89C6\u53E3\u5916\u81EA\u52A8\u6682\u505C \u2500\u2500\n let pauseIo: IntersectionObserver | null = null;\n function setupAutoPause() {\n if (options.autoPause === false || typeof IntersectionObserver === 'undefined') return;\n pauseIo = new IntersectionObserver((entries) => {\n const visible = entries[entries.length - 1]?.isIntersecting ?? true;\n autoPaused = !visible;\n syncPause();\n });\n pauseIo.observe(wrapper);\n }\n let sentPaused = false;\n function syncPause() {\n if (!port) return;\n const want = userPaused || autoPaused;\n if (want === sentPaused) return;\n sentPaused = want;\n port.postMessage(xcMessage(want ? 'xc.pause' : 'xc.resume'));\n }\n\n // \u2500\u2500 lazy \u8C03\u5EA6 \u2500\u2500\n function cancelIdle() {\n if (idleHandle === null) return;\n const w = window as Window & { cancelIdleCallback?: (h: number) => void };\n if (w.cancelIdleCallback) w.cancelIdleCallback(idleHandle); else clearTimeout(idleHandle);\n idleHandle = null;\n }\n function scheduleLazy() {\n if (lazy === false) { activate(); return; }\n if (lazy === 'click') return;\n const go = () => {\n const w = window as Window & { requestIdleCallback?: (cb: () => void, o?: { timeout: number }) => number };\n // \u7A7A\u95F2\u56DE\u8C03 timeout 3s: \u4E3B\u7EBF\u7A0B\u4E00\u76F4\u5FD9\u4E5F\u6700\u8FDF 3s \u540E\u521B\u5EFA, \u8C03\u5927\u66F4\u4E0D\u5F71\u54CD\u9996\u5C4F, \u8C03\u5C0F\u66F4\u5FEB\u51FA\u73B0\n idleHandle = w.requestIdleCallback ? w.requestIdleCallback(() => { idleHandle = null; activate(); }, { timeout: 3000 }) : (setTimeout(activate, 1200) as unknown as number);\n };\n if (typeof IntersectionObserver === 'undefined') { go(); return; }\n io = new IntersectionObserver((entries) => {\n if (entries.some((e) => e.isIntersecting)) { io?.disconnect(); io = null; go(); }\n }, { rootMargin: `${options.lazyMargin ?? 200}px` });\n io.observe(wrapper);\n }\n\n // \u2500\u2500 \u624B\u52BF: \u62D6\u52A8 / \u7F29\u653E (iframe \u91CC\u8BC6\u522B, \u5BBF\u4E3B\u8FD9\u91CC\u6267\u884C + \u9650\u5E45) \u2500\u2500\n // \u534F\u8BAE: xc.gesture-move / xc.gesture-resize (\u89C1 protocol.ts \u7684 XcGestureBase)\u3002\u5BBF\u4E3B\u4E0D\u4FE1\u4EFB iframe \u53D1\u6765\u7684\u4EFB\u4F55\u6570:\n // \u6821\u9A8C\u8F7D\u8377 (parseGesturePayload) \u2192 \u5E8F\u53F7\u95F8\u95E8 (GestureGate) \u2192 \u4EE5\"\u624B\u52BF\u5F00\u59CB\u65F6\u7684\u76D2\u5B50 + \u7D2F\u8BA1\u4F4D\u79FB\"\u5939\u5728\u89C6\u53E3 / \u6700\u5C0F\u6700\u5927\u5C3A\u5BF8\u5185 (gesture-box.ts)\u3002\n // \u5BBF\u4E3B\u6CA1\u5F00 draggable / resizable \u65F6, \u5BF9\u5E94\u6D88\u606F\u4E00\u5F8B\u5FFD\u7565; \u540C\u4E00\u65F6\u523B\u53EA\u5141\u8BB8\u4E00\u4E2A\u624B\u52BF\u3002\n let draggableOn = options.draggable === true;\n let resizeLimits: ResizeLimits | null = normalizeResizable(options.resizable);\n const gates = { move: new GestureGate(), resize: new GestureGate() };\n let activeGesture: { kind: 'move' | 'resize'; start: Box; inlineBase: { left: number; top: number } | null; corner?: 'NW' | 'NE' | 'SW' | 'SE' } | null = null;\n /** \u5185\u8054\u6A21\u5F0F\u9760 CSS translate \u4F4D\u79FB (\u4E0D\u6539\u5E03\u5C40\u6D41); \u8BB0\u4E0B\u5F53\u524D\u4F4D\u79FB, \u624D\u80FD\u8FD8\u539F\u51FA\"\u6D41\u5185\u539F\u70B9\"\u3002 */\n let inlineShift = { x: 0, y: 0 };\n let userMoved = false;\n let sentGestures: { move: boolean; resize: boolean } | null = null;\n let warnedGesture = false;\n const viewport = (): Viewport => ({\n width: document.documentElement.clientWidth || window.innerWidth,\n height: document.documentElement.clientHeight || window.innerHeight,\n });\n const readBox = (): Box => { const r = wrapper.getBoundingClientRect(); return { left: r.left, top: r.top, width: r.width, height: r.height }; };\n const wantGestures = () => ({ move: draggableOn && caps?.gestures?.move === true, resize: resizeLimits !== null && caps?.gestures?.resize === true });\n\n function applyBox(b: Box, inlineBase: { left: number; top: number } | null, withSize: boolean): void {\n if (withSize) { ws.width = `${b.width}px`; ws.height = `${b.height}px`; ws.maxWidth = 'none'; } // maxWidth:100% \u4F1A\u628A\u7528\u6237\u62C9\u5927\u7684\u5BBD\u5EA6\u538B\u56DE\u5BB9\u5668\u5BBD\n if (position === 'inline') {\n const base = inlineBase ?? { left: b.left - inlineShift.x, top: b.top - inlineShift.y };\n inlineShift = { x: b.left - base.left, y: b.top - base.top };\n ws.setProperty('translate', `${inlineShift.x}px ${inlineShift.y}px`);\n } else {\n ws.left = `${b.left}px`; ws.top = `${b.top}px`; ws.right = 'auto'; ws.bottom = 'auto';\n }\n userMoved = true;\n invalidateRect();\n }\n\n // \u62D6\u52A8\u671F\u95F4\u4E0D\u51FA\u73B0\u9009\u4E2D\u84DD\u6846: \u5BBF\u4E3B\u9875\u4E34\u65F6 user-select:none \u5E76\u6E05\u6389\u5DF2\u6709\u9009\u533A (iframe \u5185\u90E8\u53E6\u6709\u5904\u7406)\n let selectionLock: { us: string; wus: string } | null = null;\n function lockSelection(on: boolean): void {\n const de = document.documentElement;\n if (on && !selectionLock) {\n selectionLock = { us: de.style.getPropertyValue('user-select'), wus: de.style.getPropertyValue('-webkit-user-select') };\n de.style.setProperty('user-select', 'none'); de.style.setProperty('-webkit-user-select', 'none');\n try { window.getSelection()?.removeAllRanges(); } catch { /* ignore */ }\n } else if (!on && selectionLock) {\n de.style.setProperty('user-select', selectionLock.us); de.style.setProperty('-webkit-user-select', selectionLock.wus);\n selectionLock = null;\n }\n }\n function endActiveGesture(kind?: 'move' | 'resize'): void {\n if (!activeGesture || (kind && activeGesture.kind !== kind)) return;\n gates[activeGesture.kind].close();\n const b = readBox();\n emit(activeGesture.kind, { phase: 'end', ...b });\n activeGesture = null;\n lockSelection(false);\n }\n\n function onGesture(kind: 'move' | 'resize', raw: unknown): void {\n if (destroyed || !caps?.gestures) return;\n if (kind === 'move' ? !draggableOn : resizeLimits === null) return; // \u5BBF\u4E3B\u6CA1\u5F00: \u5FFD\u7565\n const p = parseGesturePayload(kind, raw);\n if (!p) return;\n if (p.phase === 'start' ? activeGesture !== null : activeGesture?.kind !== kind) return; // \u540C\u4E00\u65F6\u523B\u53EA\u5141\u8BB8\u4E00\u4E2A\u624B\u52BF\n if (!gates[kind].accept(p)) return;\n if (p.phase === 'start') {\n const start = readBox();\n activeGesture = {\n kind, start, corner: p.corner,\n inlineBase: position === 'inline' ? { left: start.left - inlineShift.x, top: start.top - inlineShift.y } : null,\n };\n lockSelection(true);\n emit(kind, { phase: 'start', ...start });\n return;\n }\n const a = activeGesture!;\n const vp = viewport();\n const next = kind === 'move'\n ? moveBox(a.start, p.totalDx, p.totalDy, vp)\n : resizeBox(a.start, a.corner!, p.totalDx, p.totalDy, resizeLimits!, vp);\n applyBox(next, a.inlineBase, kind === 'resize');\n emit(kind, { phase: p.phase, ...next });\n if (p.phase === 'end') { activeGesture = null; lockSelection(false); }\n }\n\n /** \u628A draggable / resizable \u7684\u5F53\u524D\u503C\u540C\u6B65\u7ED9 iframe (\u53EA\u5728\u53D8\u5316\u65F6\u53D1 xc.setConfig{gestures}); \u63E1\u624B\u65F6\u5DF2\u968F xc.init \u53D1\u8FC7\u4E00\u6B21\u3002 */\n function syncGestures(): void {\n if (destroyed) return;\n const want = wantGestures();\n if (!want.move) endActiveGesture('move');\n if (!want.resize) endActiveGesture('resize');\n if (!port || !caps) return;\n warnGestureUnsupported();\n if (sentGestures && sentGestures.move === want.move && sentGestures.resize === want.resize) return;\n sentGestures = want;\n if (caps.gestures) port.postMessage(xcMessage('xc.setConfig', { gestures: want }));\n }\n /** \u65E7\u7248 /embed (\u63E1\u624B\u91CC\u6CA1\u6709 capabilities.gestures) \u5374\u5F00\u4E86\u624B\u52BF: \u544A\u77E5\u4E00\u6B21\u3002 */\n function warnGestureUnsupported(): void {\n if (warnedGesture || !caps || caps.gestures) return;\n const needMove = draggableOn;\n if (!needMove && resizeLimits === null) return;\n warnedGesture = true;\n const what = [needMove ? 'draggable' : '', resizeLimits !== null ? 'resizable' : ''].filter(Boolean).join(' / ');\n emit('error', { code: 'unsupported', message: `${what} needs gesture support (capabilities.gestures), which this /embed deployment does not advertise (older version)`, command: 'gestures' });\n }\n\n // \u7A97\u53E3\u53D8\u5C0F\u540E\u628A\u7528\u6237\u62D6\u8FC7 / \u7F29\u8FC7\u7684\u5934\u50CF\u5939\u56DE\u89C6\u53E3 (\u6CA1\u52A8\u8FC7\u5C31\u4E0D\u7BA1, \u4EA4\u7ED9\u9875\u9762\u81EA\u5DF1\u7684\u5E03\u5C40)\n const onWindowResize = () => {\n if (!userMoved || activeGesture || destroyed) return;\n const cur = readBox();\n const fit = fitBox(cur, viewport());\n if (fit.left === cur.left && fit.top === cur.top && fit.width === cur.width && fit.height === cur.height) return;\n applyBox(fit, position === 'inline' ? { left: cur.left - inlineShift.x, top: cur.top - inlineShift.y } : null, fit.width !== cur.width || fit.height !== cur.height);\n };\n window.addEventListener('resize', onWindowResize, { passive: true });\n\n scheduleLazy();\n\n const api: XiaochunInstance = {\n element: wrapper,\n get iframe() { return iframe; },\n ready,\n activate,\n say: (text, opts) => send('xc.say', { text, mode: opts?.mode }, true),\n speakAudio,\n speakAudioStream,\n motion: (m) => send('xc.motion', typeof m === 'string' ? (m.startsWith('http') || m.startsWith('/') ? { url: m } : { name: m }) : m),\n expression: (name) => send('xc.expression', { name }),\n lookAt: (x, y) => send('xc.lookAt', { x, y }),\n setOutfit: (id) => {\n if (!isXcId(id)) return Promise.reject(new Error('[bad_request] invalid outfit id'));\n return send('xc.setOutfit', { id }, true, undefined, undefined, 'outfits');\n },\n setScene: (id) => {\n if (!isXcId(id)) return Promise.reject(new Error('[bad_request] invalid scene id'));\n return send('xc.setScene', { id }, true, undefined, undefined, 'scenes');\n },\n prefetch: (ids) => {\n if (ids !== undefined && (!Array.isArray(ids) || ids.some((x) => !isXcId(x)))) {\n return Promise.reject(new Error('[bad_request] prefetch ids must be an array of outfit ids'));\n }\n return send('xc.prefetch', ids ? { ids } : {}, true, undefined, undefined, 'prefetch');\n },\n getOutfits: async () => { if (!iframe) activate(); await handshaked; return caps?.outfits ? caps.outfits.slice() : []; },\n getScenes: async () => { if (!iframe) activate(); await handshaked; return caps?.scenes ? caps.scenes.slice() : []; },\n get outfit() { return currentOutfit; },\n get scene() { return currentScene; },\n setModel: (m) => {\n const msg = typeof m === 'string' ? (/^(https?:)?\\/|\\.vrm/i.test(m) ? { url: m } : { outfit: m }) : m;\n if (msg.url !== undefined && msg.outfit === undefined && !options.allowCustomModel) {\n const message = 'custom model URLs are disabled; pass allowCustomModel: true to createXiaochun() (only for URLs you trust) or use setOutfit() with a built-in id';\n emit('error', { code: 'unsupported', message, command: 'xc.setModel' });\n return Promise.reject(new Error(`[unsupported] ${message}`));\n }\n return send('xc.setModel', msg);\n },\n setConfig: (cfg) => send('xc.setConfig', cfg),\n setSize(width, height) {\n if (destroyed) return;\n ws.width = css(width, '320px'); ws.height = css(height, '480px');\n invalidateRect();\n },\n getBox: () => readBox(),\n setBorderRadius(radius) {\n radiusOpt = radius;\n applyRadius();\n },\n setDraggable(on) {\n draggableOn = on === true;\n syncGestures();\n },\n setResizable(on) {\n resizeLimits = normalizeResizable(on);\n syncGestures();\n },\n startListening: () => send('xc.mic', { enabled: true }),\n stopListening: () => send('xc.mic', { enabled: false }),\n mic: (enabled) => send('xc.mic', { enabled }),\n pause() { userPaused = true; syncPause(); },\n resume() { userPaused = false; syncPause(); },\n destroy() {\n if (destroyed) return;\n try { port?.postMessage(xcMessage('xc.destroy')); } catch { /* ignore */ }\n destroyed = true;\n cancelIdle();\n io?.disconnect(); pauseIo?.disconnect();\n if (handshakeTimer) clearTimeout(handshakeTimer);\n if (pointerRaf) cancelAnimationFrame(pointerRaf);\n window.removeEventListener('message', onWindowMessage);\n window.removeEventListener('resize', onWindowResize);\n lockSelection(false);\n disablePassthrough();\n resolveHandshake(); // \u8FD8\u5728\u7B49 getOutfits() / getScenes() \u7684\u8C03\u7528\u65B9\u62FF\u5230 [] \u800C\u4E0D\u662F\u6C38\u8FDC\u6302\u8D77\n try { port?.close(); } catch { /* ignore */ }\n port = null;\n for (const p of pending.values()) p.reject(new Error('[project-xiaochun] instance destroyed'));\n pending.clear();\n queue.length = 0;\n if (!loaded) rejectReady(new Error('[project-xiaochun] destroyed before ready'));\n wrapper.remove(); // \u540C\u65F6\u79FB\u9664 iframe \u2192 \u6D4F\u89C8\u5668\u91CA\u653E WebGL \u4E0A\u4E0B\u6587\n iframe = null;\n emit('destroy', undefined);\n listeners.clear();\n },\n on(event, cb) {\n let set = listeners.get(event);\n if (!set) { set = new Set(); listeners.set(event, set); }\n set.add(cb as (p: any) => void);\n return () => { set!.delete(cb as (p: any) => void); };\n },\n };\n return api;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["'use client';\n/**\n * react.ts \u2014 React \u5C01\u88C5 (\u5B50\u8DEF\u5F84\u5BFC\u51FA `@firetable/project-xiaochun/react`, react \u662F\u53EF\u9009 peerDependency)\u3002\n *\n * import { Xiaochun, useXiaochun } from '@firetable/project-xiaochun/react';\n * <Xiaochun ref={ref} width={320} height={480} transparent onReady={...} />\n * ref.current?.say('\u4F60\u597D') / ref.current?.speakAudio(arrayBuffer)\n *\n * \u8BBE\u8BA1\u8981\u70B9:\n * - \u517C\u5BB9 React 18 / 19 (\u53EA\u7528 forwardRef / useImperativeHandle / useEffect / useState / createElement, \u4E0D\u5199 JSX \u2192 \u65E0\u9700 jsx \u8FD0\u884C\u65F6)\u3002\n * - SSR / Next.js \u5B89\u5168: \u6587\u4EF6\u5934 'use client'; \u670D\u52A1\u7AEF\u53EA\u6E32\u67D3\u4E00\u4E2A**\u56FA\u5B9A\u5C3A\u5BF8**\u7684\u7A7A <div> (\u4E0D\u4EA7\u751F CLS), iframe \u53EA\u5728\u5BA2\u6237\u7AEF effect \u91CC\u521B\u5EFA\u3002\n * - StrictMode \u53CC\u6302\u8F7D\u4E0D\u6CC4\u6F0F: effect cleanup \u4E00\u5B9A destroy(); lazy \u6A21\u5F0F\u4E0B\u5047\u6302\u8F7D\u6839\u672C\u4E0D\u4F1A\u521B\u5EFA iframe\u3002\n * - \u4E0D\u6539\u53D8\u4E3B\u5165\u53E3\u4F53\u79EF: \u4E3B\u5165\u53E3 (index) \u4E0D\u5F15\u7528\u672C\u6587\u4EF6, \u4E0D\u7528 React \u7684\u4EBA\u4E0D\u4F1A\u591A\u62C9\u4E00\u4E2A\u5B57\u8282\u3002\n * - \u521B\u5EFA\u671F\u9009\u9879 (src/lazy/position/\u2026) \u53D8\u5316\u4F1A\u91CD\u5EFA\u5B9E\u4F8B; lang / outfit / scene / paused / mic / width / height / draggable / resizable / borderRadius / camera \u53D8\u5316\u5219\u70ED\u66F4\u65B0\n * (\u4E0D\u91CD\u5EFA iframe, effect \u91CC\u8C03 setter)\u3002\u5C24\u5176 width / height: \u7528\u6237\u7F29\u653E (resizable) \u540E\u5BBF\u4E3B\u628A\u65B0\u5C3A\u5BF8\u5199\u56DE props \u4E5F\u4E0D\u4F1A\u91CD\u5EFA, \u6A21\u578B / \u52A8\u753B\u72B6\u6001\u90FD\u4FDD\u7559\u3002\n */\nimport { createElement, forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';\nimport type { CSSProperties, ForwardedRef, ReactElement } from 'react';\nimport { createXiaochun, defaultHeightCss, defaultWidthCss } from './client';\nimport type {\n XiaochunAudioOptions,\n XiaochunAudioSource,\n XiaochunAudioStream,\n XiaochunEvents,\n XiaochunInstance,\n XiaochunOptions,\n} from './client';\nimport { isXcId } from './protocol';\nimport type { XcConfig, XcExpressionPayload, XcMotionPayload, XcOutfitInfo, XcPrefetchedPayload, XcSceneInfo, XcStatePayload } from './protocol';\n\n/** \u4E8B\u4EF6\u56DE\u8C03 (\u5168\u90E8\u53EF\u9009)\u3002\u5F15\u7528\u53D8\u5316\u4E0D\u4F1A\u91CD\u5EFA\u5B9E\u4F8B (\u5185\u90E8\u7528 ref \u6301\u6709\u6700\u65B0\u503C)\u3002 */\nexport interface XiaochunCallbacks {\n /** xc.ready \u63E1\u624B\u6210\u529F\u3002 */\n onHandshake?: (p: XiaochunEvents['handshake']) => void;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210 (= xc.loaded)\u3002 */\n onReady?: (p: XiaochunEvents['ready']) => void;\n onProgress?: (p: XiaochunEvents['progress']) => void;\n onState?: (p: XiaochunEvents['state']) => void;\n onStt?: (p: XiaochunEvents['stt']) => void;\n onUtterance?: (p: XiaochunEvents['utterance']) => void;\n onHitRegion?: (p: XiaochunEvents['hit-region']) => void;\n /** \u670D\u88C5\u5DF2\u751F\u6548 (\u542B\u9996\u6B21\u52A0\u8F7D initial:true)\u3002 */\n onOutfitChanged?: (p: XiaochunEvents['outfit-changed']) => void;\n /** \u573A\u666F\u5DF2\u751F\u6548 (\u542B\u63E1\u624B\u540E\u4E0A\u62A5\u7684\u5F53\u524D\u573A\u666F initial:true)\u3002 */\n onSceneChanged?: (p: XiaochunEvents['scene-changed']) => void;\n /** iframe \u754C\u9762\u8BED\u8A00\u5DF2\u751F\u6548 (\u542B\u63E1\u624B\u540E\u4E0A\u62A5\u7684\u5F53\u524D\u8BED\u8A00 initial:true; \u7528\u6237\u70B9\u8BED\u8A00\u6309\u94AE / setConfig({ lang }) \u5F15\u8D77\u7684\u53D8\u5316)\u3002 */\n onLangChanged?: (p: XiaochunEvents['lang-changed']) => void;\n onError?: (p: XiaochunEvents['error']) => void;\n onDestroy?: () => void;\n /** \u7528\u6237\u62D6\u52A8\u5934\u50CF (draggable): start / move / end, \u4F4D\u7F6E\u5DF2\u9650\u5E45 (\u89C6\u53E3\u5750\u6807)\u3002 */\n onMove?: (p: XiaochunEvents['move']) => void;\n /** \u7528\u6237\u7F29\u653E\u5934\u50CF (resizable): start / move / end, \u5C3A\u5BF8\u5DF2\u9650\u5E45\u3002\u60F3\u628A\u5C3A\u5BF8\u540C\u6B65\u8FDB\u81EA\u5DF1\u7684\u72B6\u6001, \u5728 phase === 'end' \u65F6\u5199\u56DE width / height \u5373\u53EF (\u4E0D\u4F1A\u91CD\u5EFA iframe)\u3002 */\n onResize?: (p: XiaochunEvents['resize']) => void;\n}\n\nexport interface XiaochunHookOptions extends Omit<XiaochunOptions, 'container'>, XiaochunCallbacks {\n /** \u53D7\u63A7\u6682\u505C: true = xc.pause, false = xc.resume\u3002 */\n paused?: boolean;\n /** \u53D7\u63A7\u9EA6\u514B\u98CE: true = \u5F00\u59CB\u542C (\u9996\u6B21\u4F1A\u52A0\u8F7D STT), false = \u505C\u3002 */\n mic?: boolean;\n}\n\nexport interface UseXiaochunResult {\n /** \u7ED1\u5B9A\u5230\u4F60\u81EA\u5DF1\u7684\u5BB9\u5668: `<div ref={containerRef} style={{ width: 320, height: 480 }} />`\u3002\u56DE\u8C03 ref, React 18/19 \u901A\u7528\u3002 */\n containerRef: (el: HTMLElement | null) => void;\n /** \u5E95\u5C42 SDK \u5B9E\u4F8B; \u670D\u52A1\u7AEF / \u5C1A\u672A\u6302\u8F7D / \u5DF2\u5378\u8F7D\u65F6\u4E3A null\u3002 */\n client: XiaochunInstance | null;\n /** \u6A21\u578B\u662F\u5426\u52A0\u8F7D\u5B8C\u6210\u3002 */\n ready: boolean;\n /** \u6700\u8FD1\u4E00\u6B21 xc.state\u3002 */\n state: XcStatePayload | null;\n}\n\nconst EVENT_MAP: Array<[keyof XiaochunEvents, keyof XiaochunCallbacks]> = [\n ['handshake', 'onHandshake'],\n ['ready', 'onReady'],\n ['progress', 'onProgress'],\n ['state', 'onState'],\n ['stt', 'onStt'],\n ['utterance', 'onUtterance'],\n ['hit-region', 'onHitRegion'],\n ['outfit-changed', 'onOutfitChanged'],\n ['scene-changed', 'onSceneChanged'],\n ['lang-changed', 'onLangChanged'],\n ['error', 'onError'],\n ['move', 'onMove'],\n ['resize', 'onResize'],\n ['destroy', 'onDestroy'],\n];\n\n/**\n * \u5728\u4F60\u81EA\u5DF1\u7684\u5BB9\u5668\u91CC\u521B\u5EFA / \u9500\u6BC1\u4E00\u4E2A\u5C0F\u8822\u5B9E\u4F8B (\u5BA2\u6237\u7AEF only)\u3002\n * \u9700\u8981\u5B8C\u5168\u81EA\u5B9A\u4E49\u5E03\u5C40\u65F6\u7528\u5B83; \u60F3\u7701\u4E8B\u7528 <Xiaochun />\u3002\n */\nexport function useXiaochun(options: XiaochunHookOptions = {}): UseXiaochunResult {\n const [el, setEl] = useState<HTMLElement | null>(null);\n const [client, setClient] = useState<XiaochunInstance | null>(null);\n const [ready, setReady] = useState(false);\n const [state, setState] = useState<XcStatePayload | null>(null);\n\n // \u56DE\u8C03\u4E0E\"\u70ED\u66F4\u65B0\u578B\"\u9009\u9879\u653E\u8FDB ref: \u5B83\u4EEC\u53D8\u5316\u4E0D\u5E94\u91CD\u5EFA iframe\n const live = useRef(options);\n live.current = options;\n\n const o = options;\n const originsKey = (o.allowedOrigins ?? []).join(',');\n\n useEffect(() => {\n if (!el) return;\n const cur = live.current;\n const { onHandshake: _a, onReady: _b, onProgress: _c, onState: _d, onStt: _e, onUtterance: _f, onHitRegion: _g, onError: _h, onDestroy: _i, onOutfitChanged: _j, onSceneChanged: _k, onLangChanged: _l, onMove: _q, onResize: _r, paused: _p, mic: _m, allowedOrigins, ...create } = cur;\n void [_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _p, _m, _q, _r];\n const inst = createXiaochun({ ...create, allowedOrigins: allowedOrigins?.slice(), container: el });\n const offs: Array<() => void> = [];\n for (const [ev, cbName] of EVENT_MAP) {\n offs.push(inst.on(ev, (p: unknown) => { (live.current[cbName] as ((x: unknown) => void) | undefined)?.(p); }));\n }\n offs.push(inst.on('ready', () => setReady(true)));\n offs.push(inst.on('state', (s) => setState(s)));\n if (cur.paused) inst.pause();\n if (cur.mic) void inst.ready.then(() => inst.mic(true)).catch(() => {});\n setClient(inst);\n return () => {\n // StrictMode \u7684\u5047\u5378\u8F7D / \u771F\u5378\u8F7D / \u91CD\u5EFA \u90FD\u8D70\u8FD9\u91CC: \u5FC5\u987B\u9500\u6BC1, \u5426\u5219 iframe \u4E0E window \u76D1\u542C\u6CC4\u6F0F\n offs.forEach((off) => off());\n inst.destroy();\n setClient(null);\n setReady(false);\n setState(null);\n };\n // \u53EA\u6709\"\u521B\u5EFA\u671F\u9009\u9879\"\u53D8\u5316\u624D\u91CD\u5EFA; lang/outfit/scene/paused/mic/\u56DE\u8C03\u8D70\u4E0B\u9762\u7684\u70ED\u66F4\u65B0\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [el, o.src, o.origin, originsKey, o.lazy, o.lazyMargin, o.placeholder, o.transparent, o.position,\n JSON.stringify(o.ui ?? null), o.uiAutoHide, o.heavy, o.controls, o.autoPause, o.passthrough, o.sandbox, o.handshakeTimeout, o.crossOriginIsolated, o.zIndex,\n o.allowCustomModel, o.persist, o.persistBox, Array.isArray(o.prefetch) ? o.prefetch.join(',') : o.prefetch]);\n\n // \u70ED\u66F4\u65B0: lang / outfit (model \u662F\u65E7\u522B\u540D) / scene (\u8DF3\u8FC7\u9996\u6B21: \u521B\u5EFA\u65F6\u5DF2\u7ECF\u4F5C\u4E3A\u521D\u59CB\u9009\u9879\u4F20\u5165)\u3002\n // transparent \u662F\u521B\u5EFA\u671F\u9009\u9879 (\u53D8\u5316\u4F1A\u91CD\u5EFA); \u60F3\u4E0D\u91CD\u5EFA\u5730\u5207\u900F\u660E\u8BF7\u7528 scene\u3002\n const wantOutfit = o.outfit ?? o.model;\n const cameraKey = JSON.stringify(o.camera ?? null);\n const first = useRef({ lang: o.lang, outfit: wantOutfit, scene: o.scene, width: o.width, height: o.height, camera: cameraKey });\n const resizableKey = JSON.stringify(o.resizable ?? false);\n useEffect(() => {\n if (!client || first.current.lang === o.lang) return;\n first.current.lang = o.lang;\n if (o.lang) void client.setConfig({ lang: o.lang }).catch(() => {});\n }, [client, o.lang]);\n useEffect(() => {\n if (!client || first.current.outfit === wantOutfit) return;\n first.current.outfit = wantOutfit;\n // busy / unknown_id \u4F1A\u8D70 onError, \u8FD9\u91CC\u4E0D\u91CD\u590D\u5904\u7406; \u65E7\u7528\u6CD5 model=\"https://\u2026\" \u4ECD\u8D70 setModel (\u53D7 allowCustomModel \u7EA6\u675F)\n if (wantOutfit) void (isXcId(wantOutfit) ? client.setOutfit(wantOutfit) : client.setModel(wantOutfit)).catch(() => {});\n }, [client, wantOutfit]);\n // camera: \u70ED\u66F4\u65B0 (\u521B\u5EFA\u65F6\u5DF2\u968F URL \u4F20\u5165; \u4E4B\u540E\u53D8\u5316\u8D70 setConfig, \u5C11\u5199\u7684\u9879 = null \u6062\u590D\u9ED8\u8BA4; \u7ACB\u523B\u91CD\u65B0\u53D6\u666F\u5E76\u53D6\u6D88\u8FDB\u884C\u4E2D\u7684\u63A8\u955C\u5934)\n useEffect(() => {\n if (!client || first.current.camera === cameraKey) return;\n first.current.camera = cameraKey;\n const c = o.camera;\n void client.setConfig({ camera: { fov: c?.fov ?? null, distance: c?.distance ?? null, height: c?.height ?? null, intro: c?.intro ?? null } }).catch(() => {});\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, cameraKey]);\n useEffect(() => {\n if (!client || first.current.scene === o.scene) return;\n first.current.scene = o.scene;\n if (o.scene) void client.setScene(o.scene).catch(() => {});\n }, [client, o.scene]);\n // \u5C3A\u5BF8 / \u624B\u52BF\u5F00\u5173: \u70ED\u66F4\u65B0, \u4E0D\u91CD\u5EFA iframe (\u7F29\u653E\u662F\u8FD0\u884C\u65F6\u72B6\u6001; \u53EA\u6709 props \u91CC\u7684\u503C\u771F\u7684\u53D8\u4E86\u624D\u8C03 setSize, \u7528\u6237\u7F29\u653E\u540E\u7684\u5C3A\u5BF8\u4E0D\u4F1A\u88AB\u65E0\u5173\u7684\u91CD\u6E32\u67D3\u8986\u76D6)\n useEffect(() => {\n if (!client || (first.current.width === o.width && first.current.height === o.height)) return;\n first.current.width = o.width; first.current.height = o.height;\n client.setSize(o.width, o.height); // undefined = \u9ED8\u8BA4 600x1080 (\u53D7\u89C6\u53E3\u9650\u5236)\n }, [client, o.width, o.height]);\n useEffect(() => { client?.setDraggable(o.draggable === true); }, [client, o.draggable]);\n useEffect(() => { client?.setBorderRadius(o.borderRadius); }, [client, o.borderRadius]);\n useEffect(() => { client?.setResizable(o.resizable ?? false); // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, resizableKey]);\n useEffect(() => {\n if (!client || o.paused === undefined) return;\n if (o.paused) client.pause(); else client.resume();\n }, [client, o.paused]);\n const micWanted = useRef(o.mic);\n useEffect(() => {\n if (!client || o.mic === undefined || micWanted.current === o.mic) { micWanted.current = o.mic; return; }\n micWanted.current = o.mic;\n void client.mic(!!o.mic).catch(() => {});\n }, [client, o.mic]);\n\n const containerRef = useCallback((node: HTMLElement | null) => setEl(node), []);\n return { containerRef, client, ready, state };\n}\n\n/** ref \u66B4\u9732\u7684\u547D\u4EE4\u5F0F\u53E5\u67C4 (\u5B9E\u4F8B\u5C1A\u672A\u521B\u5EFA / \u5DF2\u9500\u6BC1\u65F6, \u8FD4\u56DE Promise \u7684\u65B9\u6CD5\u4F1A reject)\u3002 */\nexport interface XiaochunHandle {\n say(text: string, opts?: { mode?: 'speak' | 'chat' }): Promise<void>;\n /** \u76F4\u63A5\u64AD\u653E\u5BBF\u4E3B\u7ED9\u7684\u97F3\u9891 (\u4E0D\u8D70 TTS), \u540C\u65F6\u7531 EMAGE \u751F\u6210\u52A8\u4F5C + \u53E3\u578B\u3002 */\n speakAudio(source: XiaochunAudioSource, opts?: XiaochunAudioOptions): Promise<void>;\n speakAudioStream(opts: XiaochunAudioOptions & { sampleRate: number }): XiaochunAudioStream;\n motion(m: XcMotionPayload | string): Promise<void>;\n expression(name: XcExpressionPayload['name']): Promise<void>;\n /** TODO: \u534F\u8BAE\u5DF2\u9884\u7559, /embed \u6682\u672A\u5B9E\u73B0 \u2192 reject unsupported\u3002 */\n lookAt(x: number, y: number): Promise<void>;\n /** \u6362\u5185\u7F6E\u670D\u88C5 (\u4E32\u884C + last-wins, \u89C1 XiaochunInstance.setOutfit)\u3002 */\n setOutfit(id: string): Promise<void>;\n setScene(id: string): Promise<void>;\n getOutfits(): Promise<XcOutfitInfo[]>;\n getScenes(): Promise<XcSceneInfo[]>;\n /** \u6E05\u9664 persistBox \u4FDD\u5B58\u7684\u4F4D\u7F6E / \u5927\u5C0F; { reset: true } \u540C\u65F6\u8FD8\u539F\u5230\u521D\u59CB\u4F4D\u7F6E\u548C\u5927\u5C0F\u3002 */\n clearPersistedBox(opts?: { reset?: boolean }): void;\n /** \u9884\u53D6\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB; ids \u7701\u7565 = \u5168\u90E8 (\u5A5A\u7EB1\u9664\u5916)\u3002 */\n prefetch(ids?: string[]): Promise<XcPrefetchedPayload>;\n /** \u65E7\u547D\u4EE4; \u4EFB\u610F URL \u9700 allowCustomModel\u3002\u5185\u7F6E\u670D\u88C5\u8BF7\u7528 setOutfit\u3002 */\n setModel(m: string | { url?: string; outfit?: string; name?: string }): Promise<void>;\n setConfig(cfg: XcConfig): Promise<void>;\n startListening(): Promise<void>;\n stopListening(): Promise<void>;\n mic(enabled: boolean): Promise<void>;\n pause(): void;\n resume(): void;\n activate(): void;\n destroy(): void;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210\u65F6 resolve\u3002 */\n readonly ready: Promise<void>;\n /** \u5E95\u5C42 SDK \u5B9E\u4F8B (\u670D\u52A1\u7AEF / \u672A\u6302\u8F7D\u65F6 null)\u3002 */\n readonly instance: XiaochunInstance | null;\n}\n\nexport interface XiaochunProps extends XiaochunHookOptions {\n className?: string;\n /** \u5916\u5C42 div \u7684\u6837\u5F0F; width/height \u7531 props \u51B3\u5B9A (\u56FA\u5B9A\u5C3A\u5BF8, \u9632 CLS), \u8FD9\u91CC\u7684\u540C\u540D\u5B57\u6BB5\u4F1A\u88AB\u8986\u76D6\u3002 */\n style?: CSSProperties;\n}\n\nconst css = (v: number | string | undefined, d: string) => (v === undefined ? d : typeof v === 'number' ? `${v}px` : v);\nconst NOT_MOUNTED = () => new Error('[project-xiaochun] <Xiaochun /> is not mounted');\n\nfunction XiaochunInner(props: XiaochunProps, ref: ForwardedRef<XiaochunHandle>): ReactElement {\n const { className, style, ...hookOptions } = props;\n const { containerRef, client } = useXiaochun(hookOptions);\n const clientRef = useRef<XiaochunInstance | null>(null);\n clientRef.current = client;\n\n useImperativeHandle(ref, () => {\n const c = () => clientRef.current;\n const reject = <T,>(): Promise<T> => Promise.reject(NOT_MOUNTED());\n return {\n say: (t, o) => c()?.say(t, o) ?? reject(),\n speakAudio: (s, o) => c()?.speakAudio(s, o) ?? reject(),\n speakAudioStream: (o) => { const x = c(); if (!x) throw NOT_MOUNTED(); return x.speakAudioStream(o); },\n motion: (m) => c()?.motion(m) ?? reject(),\n expression: (n) => c()?.expression(n) ?? reject(),\n lookAt: (x, y) => c()?.lookAt(x, y) ?? reject(),\n setOutfit: (id) => c()?.setOutfit(id) ?? reject(),\n setScene: (id) => c()?.setScene(id) ?? reject(),\n getOutfits: () => c()?.getOutfits() ?? reject(),\n getScenes: () => c()?.getScenes() ?? reject(),\n clearPersistedBox: (opts) => c()?.clearPersistedBox(opts),\n prefetch: (ids) => c()?.prefetch(ids) ?? reject(),\n setModel: (m) => c()?.setModel(m) ?? reject(),\n setConfig: (cfg) => c()?.setConfig(cfg) ?? reject(),\n startListening: () => c()?.startListening() ?? reject(),\n stopListening: () => c()?.stopListening() ?? reject(),\n mic: (e) => c()?.mic(e) ?? reject(),\n pause: () => c()?.pause(),\n resume: () => c()?.resume(),\n activate: () => c()?.activate(),\n destroy: () => c()?.destroy(),\n get ready() { return c()?.ready ?? reject<void>(); },\n get instance() { return c(); },\n };\n }, []);\n\n // \u670D\u52A1\u7AEF\u4E0E\u9996\u5E27\u5BA2\u6237\u7AEF\u6E32\u67D3\u5B8C\u5168\u4E00\u81F4 (hydration \u5B89\u5168): \u56FA\u5B9A\u5C3A\u5BF8\u7684\u7A7A div\n const box: CSSProperties = {\n ...style,\n width: css(props.width, defaultWidthCss()),\n height: css(props.height, defaultHeightCss()),\n maxWidth: '100%',\n position: style?.position ?? 'relative',\n };\n return createElement('div', { ref: containerRef, className, style: box, 'data-xiaochun-host': '' });\n}\n\n/** `<Xiaochun />`: \u5728\u5BA2\u6237\u7AEF\u521B\u5EFA\u5C0F\u8822 iframe; ref \u66B4\u9732 say / speakAudio / motion / \u2026 \u7B49\u547D\u4EE4\u5F0F\u65B9\u6CD5\u3002 */\nexport const Xiaochun = forwardRef<XiaochunHandle, XiaochunProps>(XiaochunInner);\nXiaochun.displayName = 'Xiaochun';\n\nexport type { XiaochunOptions, XiaochunInstance, XiaochunAudioOptions, XiaochunAudioSource, XiaochunAudioStream } from './client';\n", "/**\n * protocol.ts \u2014 Project XiaoChun `<iframe>` \u5D4C\u5165\u534F\u8BAE (\u5E38\u91CF + \u7C7B\u578B, \u96F6\u8FD0\u884C\u65F6\u4F9D\u8D56)\u3002\n *\n * \u5355\u4E00\u4E8B\u5B9E\u6E90: SDK (\u672C\u5305) \u4E0E `/embed` \u9875\u9762 (\u4E3B\u4ED3\u5E93 src/embed/) \u5171\u7528\u8FD9\u4E00\u4EFD\u3002\n * \u6240\u6709\u6D88\u606F\u540D\u7EDF\u4E00 `xc.` \u524D\u7F00; \u4FE1\u5C01 `{ type, v, id?, payload? }`\u3002\n *\n * \u901A\u9053:\n * 1. \u63E1\u624B: iframe \u2192 \u5BBF\u4E3B `xc.ready` (window.postMessage, targetOrigin = \u5BBF\u4E3B origin)\n * \u5BBF\u4E3B \u2192 iframe `xc.init` (window.postMessage, targetOrigin = iframe origin, \u8F6C\u79FB MessagePort)\n * 2. \u63E1\u624B\u540E\u5168\u90E8\u8D70 MessageChannel \u7AEF\u53E3 (\u7AEF\u53E3\u672C\u8EAB\u5373\u51ED\u8BC1, \u4E0D\u518D\u4F9D\u8D56 `*`)\n */\n\n/** \u534F\u8BAE\u7248\u672C; \u4E0D\u517C\u5BB9\u53D8\u66F4\u65F6 +1\u3002 */\nexport const XC_PROTOCOL_VERSION = 1 as const;\n\n/** \u5B98\u65B9\u90E8\u7F72\u7684 origin / embed \u5165\u53E3\u3002 */\nexport const XC_DEFAULT_ORIGIN = 'https://xiaochun.firetable.tech';\nexport const XC_DEFAULT_SRC = `${XC_DEFAULT_ORIGIN}/embed`;\n\n/** \u5BBF\u4E3B \u2192 iframe \u547D\u4EE4\u3002 */\nexport const XC_HOST_TO_FRAME = [\n 'xc.init',\n 'xc.say',\n 'xc.audio',\n 'xc.audio.chunk',\n 'xc.audio.end',\n 'xc.motion',\n 'xc.expression',\n 'xc.lookAt',\n 'xc.pointer',\n 'xc.setModel',\n 'xc.setOutfit',\n 'xc.setScene',\n 'xc.prefetch',\n 'xc.setConfig',\n 'xc.mic',\n 'xc.pause',\n 'xc.resume',\n 'xc.destroy',\n] as const;\n\n/** iframe \u2192 \u5BBF\u4E3B \u4E8B\u4EF6\u3002 */\nexport const XC_FRAME_TO_HOST = [\n 'xc.ready',\n 'xc.load.progress',\n 'xc.loaded',\n 'xc.outfit-changed',\n 'xc.scene-changed',\n 'xc.lang-changed',\n 'xc.prefetched',\n 'xc.state',\n 'xc.stt',\n 'xc.utterance',\n 'xc.hit-region',\n 'xc.gesture-move',\n 'xc.gesture-resize',\n 'xc.error',\n] as const;\n\nexport type XcHostMessageType = (typeof XC_HOST_TO_FRAME)[number];\nexport type XcFrameMessageType = (typeof XC_FRAME_TO_HOST)[number];\n\n/** \u5F53\u524D /embed \u5DF2\u5B9E\u73B0\u7684\u547D\u4EE4 (xc.init \u662F\u63E1\u624B, \u4E0D\u8BA1\u5165)\u3002 */\nexport const XC_IMPLEMENTED_COMMANDS = [\n 'xc.say',\n 'xc.audio',\n 'xc.audio.chunk',\n 'xc.audio.end',\n 'xc.motion',\n 'xc.expression',\n 'xc.pointer',\n 'xc.setModel',\n 'xc.setOutfit',\n 'xc.setScene',\n 'xc.prefetch',\n 'xc.setConfig',\n 'xc.mic',\n 'xc.pause',\n 'xc.resume',\n 'xc.destroy',\n] as const satisfies readonly XcHostMessageType[];\n\n/**\n * \u6682\u4E0D\u652F\u6301 (\u5E95\u5C42\u65E0\u5BF9\u5E94\u80FD\u529B), /embed \u56DE `xc.error{code:'unsupported'}`\u3002\n * TODO(xc.lookAt): \u89C6\u7EBF\u76EE\u524D\u7531\u76F8\u673A + \u968F\u673A\u626B\u89C6\u9A71\u52A8 (GazeController), \u6CA1\u6709\"\u5916\u90E8\u6307\u5B9A\u6CE8\u89C6\u70B9\"\u7684\u5165\u53E3;\n * \u9700\u8981\u5148\u5728 gaze \u5C42\u52A0 overrideTarget \u518D\u5F00\u653E\u3002\n */\nexport const XC_UNSUPPORTED_COMMANDS = ['xc.lookAt'] as const satisfies readonly XcHostMessageType[];\n\n/**\n * xc.* \u2194 xiaochun:// \u5BF9\u7167\u8868 (\u540C\u4E00\u8BED\u4E49\u7684\u4E24\u4E2A\u4F20\u8F93\u5C42, \u4E3B\u5E94\u7528\u5185\u8D70\u540C\u4E00\u4E2A handler: src/core/protocol/handler.ts)\u3002\n * - `action`: \u5185\u90E8 protocol action \u5BF9\u8C61 (src/core/protocol/types.ts); null = \u6CA1\u6709 deep link \u5BF9\u5E94\u7269\u3002\n * - `url`: \u5BF9\u5E94\u7684 deep link \u5F62\u5F0F (OS \u7EA7, \u53EA\u5728 Tauri \u58F3\u751F\u6548; iframe \u4E0D\u4F1A\u54CD\u5E94 xiaochun://)\u3002\n */\nexport const XC_PROTOCOL_MAPPING = [\n { xc: 'xc.say', note: 'mode:\"speak\" (\u9ED8\u8BA4)', action: 'speak', url: 'xiaochun://speak?text=\u2026' },\n { xc: 'xc.say', note: 'mode:\"chat\" (\u8D70 LLM)', action: null, url: null },\n { xc: 'xc.audio', note: 'source \u4E3A URL \u5B57\u7B26\u4E32', action: 'speak', url: 'xiaochun://speak?audioUrl=\u2026[&text=\u2026]' },\n { xc: 'xc.audio', note: 'source \u4E3A ArrayBuffer / Blob', action: 'audio', url: null },\n { xc: 'xc.audio.chunk / xc.audio.end', note: '\u6D41\u5F0F PCM', action: 'audio', url: null },\n] as const;\n\nexport type XcErrorCode =\n | 'unsupported' // \u547D\u4EE4/\u53C2\u6570\u5B58\u5728\u4F46\u5E95\u5C42\u6682\u65E0\u80FD\u529B\n | 'bad_request' // \u53C2\u6570\u7F3A\u5931/\u975E\u6CD5\n | 'not_ready' // \u6A21\u578B\u5C1A\u672A\u52A0\u8F7D\u5B8C\u6210\n | 'busy' // \u88AB\u540C\u7C7B\u66F4\u65B0\u7684\u8BF7\u6C42\u53D6\u4EE3 (\u6362\u88C5 last-wins: \u6392\u961F\u4E2D\u7684\u65E7\u8BF7\u6C42\u88AB\u65B0\u8BF7\u6C42\u9876\u6389); \u53EF\u5FFD\u7565, \u4EE5\u6700\u65B0\u4E00\u6B21\u4E3A\u51C6\n | 'unknown_id' // outfit / scene id \u4E0D\u5728 capabilities \u5217\u8868\u91CC (\u542B\u539F\u578B\u952E\u5982 constructor)\n | 'origin_denied' // \u63E1\u624B\u6765\u6E90\u4E0D\u5728\u767D\u540D\u5355\n | 'failed'; // \u6267\u884C\u671F\u5F02\u5E38\n\n/**\n * outfit / scene id \u7684\u7EDF\u4E00\u683C\u5F0F: \u5C0F\u5199\u5B57\u6BCD\u5F00\u5934, \u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u4E0B\u5212\u7EBF, \u6700\u957F 64\u3002\n * \u6240\u6709 id \u5165\u53E3 (xc.setOutfit / xc.setScene / ?outfit= / ?scene=) \u90FD\u5148\u8FC7\u8FD9\u6761\u6B63\u5219, \u518D\u7528 hasOwnProperty \u67E5\u8868,\n * \u8FD9\u6837 `__proto__` / `constructor` / `toString` \u8FD9\u7C7B\u539F\u578B\u952E\u6C38\u8FDC\u4E0D\u4F1A\u88AB\u5F53\u6210\u5408\u6CD5 id\u3002\n */\n/**\n * iframe \u5185\u7F6E\u754C\u9762\u90E8\u4EF6\u540D (`?ui=chat,outfit,scene,lang,github` / SDK `ui: [...]`)\u3002\n * chat \u5E95\u90E8\u804A\u5929\u680F (ChatBar, \u5BF9\u8BDD\u8D70 WebLLM)\n * bubble \u5934\u9876\u6C14\u6CE1 (\u8BF4\u8BDD\u6587\u672C / \u72B6\u6001)\n * outfit \u6362\u88C5\u6309\u94AE (\u4E0E\u4E3B\u7AD9 TopHeader \u540C\u6B3E)\n * scene \u6362\u573A\u666F(\u80CC\u666F)\u6309\u94AE (\u4E0E\u4E3B\u7AD9 TopHeader \u540C\u6B3E)\n * lang \u8BED\u8A00\u5207\u6362\u6309\u94AE (\u4E2D\u6587 / English / \u65E5\u672C\u8A9E; \u4E0E\u4E3B\u7AD9 TopHeader \u540C\u4E00\u4E2A\u7EC4\u4EF6)\n * github GitHub \u94FE\u63A5\u6309\u94AE (\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u9879\u76EE\u4ED3\u5E93; \u4E0E\u4E3B\u7AD9 TopHeader \u540C\u4E00\u4E2A\u7EC4\u4EF6)\n */\n/**\n * \u7A97\u53E3\u5706\u89D2\u534A\u5F84 (CSS px)\u3002Tauri \u684C\u5BA0\u7684\u65E0\u6846\u7A97\u53E3\u5706\u89D2 (src/styles/main.css \u7684 --xc-window-radius) \u4E0E /embed \u975E\u900F\u660E\u573A\u666F\u7684\u9ED8\u8BA4\u5916\u58F3\u5706\u89D2\u5171\u7528\u8FD9\u4E00\u4E2A\u503C,\n * \u6709\u5355\u6D4B\u4FDD\u8BC1\u4E24\u5904\u4E0D\u6F02\u79FB\u3002\u89D2\u843D\u5F27\u7EBF (components/CornerHandle) \u7684\u51E0\u4F55\u5C31\u662F\u6309\u8FD9\u4E2A\u534A\u5F84\u753B\u7684\u3002\n */\nexport const XC_WINDOW_CORNER_RADIUS = 20;\n\nexport const XC_UI_PARTS = ['chat', 'bubble', 'outfit', 'scene', 'lang', 'github'] as const;\nexport type XcUiPart = (typeof XC_UI_PARTS)[number];\nconst XC_UI_PART_SET: ReadonlySet<string> = new Set(XC_UI_PARTS);\n/** 0.1.14 \u91CC `ui=1` / `ui: true` \u7684\u542B\u4E49 = \u5F53\u65F6\u5B58\u5728\u7684\u5168\u90E8\u90E8\u4EF6\u3002 */\nexport const XC_UI_LEGACY_PARTS: readonly XcUiPart[] = ['chat', 'bubble'];\n\nexport interface XcUiParse {\n /** \u767D\u540D\u5355\u5185\u7684\u90E8\u4EF6 (\u53BB\u91CD, \u4FDD\u6301 XC_UI_PARTS \u987A\u5E8F)\u3002 */\n parts: XcUiPart[];\n /** \u88AB\u5FFD\u7565\u7684\u672A\u77E5\u9879 (\u8C03\u7528\u65B9\u8D1F\u8D23 warn)\u3002 */\n unknown: string[];\n /** \u7528\u4E86\u5DF2\u5F03\u7528\u7684 1 / true \u5199\u6CD5 (\u8C03\u7528\u65B9\u8D1F\u8D23 warn)\u3002 */\n legacy: boolean;\n}\n\n/** \u89C4\u6574\u90E8\u4EF6\u540D\u5217\u8868: \u975E\u5B57\u7B26\u4E32 / \u672A\u77E5\u540D\u5B57\u5FFD\u7565\u5E76\u8BB0\u5165 unknown, \u91CD\u590D\u53BB\u91CD\u3002 */\nexport function parseXcUiList(items: readonly unknown[]): XcUiParse {\n const seen = new Set<string>();\n const unknown: string[] = [];\n for (const it of items) {\n const name = typeof it === 'string' ? it.trim().toLowerCase() : '';\n if (XC_UI_PART_SET.has(name)) seen.add(name);\n else unknown.push(typeof it === 'string' ? it.slice(0, 40) : String(typeof it));\n }\n return { parts: XC_UI_PARTS.filter((p) => seen.has(p)), unknown, legacy: false };\n}\n\n/** `?ui=` \u53C2\u6570 / \u5143\u7D20\u5C5E\u6027: \u9017\u53F7\u5206\u9694\u7684\u90E8\u4EF6\u540D; \u7F3A\u7701 / \u7A7A / 0 / false = \u5168\u4E0D\u663E\u793A; 1 / true = \u65E7\u5199\u6CD5 (\u5F03\u7528, \u6620\u5C04\u4E3A chat + bubble)\u3002 */\nexport function parseXcUiParam(raw: string | null | undefined): XcUiParse {\n const v = (raw ?? '').trim().toLowerCase();\n if (v === '' || v === '0' || v === 'false') return { parts: [], unknown: [], legacy: false };\n if (v === '1' || v === 'true') return { parts: [...XC_UI_LEGACY_PARTS], unknown: [], legacy: true };\n return parseXcUiList(v.split(',').filter((x) => x.trim() !== ''));\n}\n\n/** SDK \u9009\u9879 `ui` (\u6570\u7EC4, \u6216\u5F03\u7528\u7684\u5E03\u5C14) \u2192 \u89C4\u6574\u7ED3\u679C\u3002 */\nexport function normalizeXcUiOption(v: unknown): XcUiParse {\n if (v === true) return { parts: [...XC_UI_LEGACY_PARTS], unknown: [], legacy: true };\n if (Array.isArray(v)) return parseXcUiList(v);\n return { parts: [], unknown: [], legacy: false };\n}\n\n/**\n * \u5185\u7F6E\u754C\u9762 (\u9876\u680F\u6309\u94AE outfit/scene/lang/github + \u804A\u5929\u680F chat) \u7684\u663E\u793A\u7B56\u7565, \u4E0E Tauri \u684C\u5BA0\u7684 \"\u70B9\u51FB\u89D2\u8272\u624D\u51FA\u73B0\" \u540C\u4E00\u5957\u72B6\u6001\u673A (src/hooks/usePetUiVisibility.ts):\n * 'transparent' (\u9ED8\u8BA4) \u4E0E Tauri \u5B8C\u5168\u4E00\u81F4: \u53EA\u6709\u900F\u660E\u573A\u666F\u9ED8\u8BA4\u9690\u85CF, \u5355\u51FB\u89D2\u8272\u51FA\u73B0 (\u6309\u4F4F\u62D6\u52A8 / \u957F\u6309\u62D6\u4E0D\u7B97), \u518D\u5355\u51FB\u89D2\u8272\u6536\u8D77, \u5355\u51FB\u7A7A\u767D\u6536\u8D77, 10 \u79D2\u65E0\u64CD\u4F5C\u81EA\u52A8\u6536\u8D77\n * (\u60AC\u505C\u5728\u6309\u94AE / \u804A\u5929\u680F\u4E0A\u3001\u83DC\u5355\u6216\u5BF9\u8BDD\u6846\u6253\u5F00\u3001\u8F93\u5165\u6846\u805A\u7126 / \u6709\u8F93\u5165 / \u53D1\u9001\u4E2D \u65F6\u4E0D\u6536); \u4EAE / \u6697\u573A\u666F\u5E38\u663E\u3002\n * true \u6240\u6709\u573A\u666F\u90FD\u6309\u4E0A\u9762\u7684\u70B9\u51FB\u51FA\u73B0\u89C4\u5219 (\u4EAE / \u6697\u573A\u666F\u4E5F\u9ED8\u8BA4\u9690\u85CF)\u3002\n * false \u4E00\u76F4\u663E\u793A (\u5FFD\u7565\u70B9\u51FB\u89C4\u5219)\u3002\n */\nexport type XcUiAutoHide = boolean | 'transparent';\n/** \u9ED8\u8BA4\u503C: 'transparent' (\u4E0E Tauri \u4E00\u81F4: \u53EA\u6709\u900F\u660E\u573A\u666F\u70B9\u51FB\u51FA\u73B0)\u3002 */\nexport const XC_UI_AUTOHIDE_DEFAULT: XcUiAutoHide = 'transparent';\n/** `?uiAutoHide=` \u53C2\u6570 / \u5143\u7D20\u5C5E\u6027: 1|true \u2192 true; 0|false \u2192 false; transparent \u2192 'transparent'; \u7F3A\u7701 / \u975E\u6CD5 \u2192 undefined (\u8C03\u7528\u65B9\u7528\u9ED8\u8BA4\u503C)\u3002 */\nexport function parseXcUiAutoHide(raw: unknown): XcUiAutoHide | undefined {\n if (raw === true || raw === false || raw === 'transparent') return raw;\n if (typeof raw !== 'string') return undefined;\n const v = raw.trim().toLowerCase();\n if (v === '1' || v === 'true') return true;\n if (v === '0' || v === 'false') return false;\n if (v === 'transparent') return 'transparent';\n return undefined;\n}\n/** \u67D0\u4E2A uiAutoHide \u53D6\u503C\u5728\u5F53\u524D\u573A\u666F\u4E0B\u662F\u5426\u751F\u6548 (\u9690\u85CF + \u70B9\u51FB\u51FA\u73B0)\u3002 */\nexport function xcUiAutoHideActive(mode: XcUiAutoHide, sceneTransparent: boolean): boolean {\n return mode === 'transparent' ? sceneTransparent : mode;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u76F8\u673A (camera) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * \u5BBF\u4E3B\u53EF\u8C03\u7684\u76F8\u673A\u9009\u9879 (SDK `camera` \u9009\u9879 / `?cameraFov=` \u7B49 URL \u53C2\u6570 / `xc.setConfig{camera}`)\u3002\n * fov \u89C6\u91CE\u89D2 (\u5EA6, \u9ED8\u8BA4 30): \u8D8A\u5C0F\u8D8A\u50CF\u957F\u7126 (\u900F\u89C6\u538B\u7F29\u3001\u80CC\u666F\u865A), \u8D8A\u5927\u8D8A\u5E7F\u89D2\u3002\u4E3B\u4F53\u53D6\u666F\u5927\u5C0F\u4F1A\u968F fov \u81EA\u52A8\u8865\u507F (\u8DDD\u79BB = \u53D6\u666F\u8303\u56F4 / (2\u00B7tan(fov/2))), \u6240\u4EE5\u53EA\u6539 fov \u65F6\u89D2\u8272\u5728\u753B\u9762\u91CC\u7684\u5927\u5C0F\u57FA\u672C\u4E0D\u53D8\n * distance \u76F8\u673A\u5230\u89D2\u8272\u7684\u89C6\u8DDD (\u7C73, \u9ED8\u8BA4\u7EA6 2.5): \u8D8A\u5C0F\u89D2\u8272\u8D8A\u5927\u3002\u663E\u5F0F\u8BBE\u7F6E\u540E, \u9996\u6B21\u53D6\u666F\u65F6\u5FFD\u7565 iframe \u91CC\u4FDD\u5B58\u7684\u89C6\u8DDD / \u4FEF\u4EF0 (\u7528\u6237\u4E4B\u540E\u6EDA\u8F6E\u7F29\u653E\u4ECD\u53EF\u8C03, \u4E14\u6362\u88C5 / \u6362\u573A\u666F\u4E0D\u4F1A\u88AB\u62FD\u56DE)\n * height \u53D6\u666F\u9AD8\u5EA6\u504F\u79FB (\u7C73, \u9ED8\u8BA4 0): \u6B63\u503C = \u76F8\u673A\u8FDE\u540C\u76EE\u6807\u4E00\u8D77\u4E0A\u62AC (\u89D2\u8272\u5728\u753B\u9762\u91CC\u4E0B\u79FB), \u8D1F\u503C\u76F8\u53CD\u3002\u663E\u5F0F\u503C\u4E0D\u5199\u5165 iframe \u7684\u4FDD\u5B58\u503C\n * intro \u662F\u5426\u64AD\u653E\u52A0\u8F7D\u5B8C\u6210\u540E\u7684\u63A8\u955C\u5934\u52A8\u753B (\u9ED8\u8BA4 true); false = \u76F4\u63A5\u653E\u5230\u7EC8\u70B9\n * \u7F3A\u7701 / undefined = \u4E0D\u8986\u76D6 (\u8D70 iframe \u4FDD\u5B58\u503C / \u9ED8\u8BA4\u503C); `xc.setConfig` \u91CC null = \u6E05\u9664\u8BE5\u9879\u8986\u76D6\u3002\n */\nexport interface XcCamera {\n fov?: number | null;\n distance?: number | null;\n height?: number | null;\n intro?: boolean | null;\n}\n/**\n * \u5404\u6570\u503C\u9879\u5141\u8BB8\u7684\u8303\u56F4 (\u8D8A\u754C\u503C\u4F1A\u88AB\u5939\u5230\u8FB9\u754C)\u3002\u4E0E\u4E3B\u4ED3\u5E93 APP_CONFIG.camera (minFov/maxFov\u3001defaultMin/MaxDistance\u3001hostMaxYOffset)\n * \u4E00\u81F4, \u4E3B\u4ED3\u5E93\u6709\u5355\u6D4B\u6838\u5BF9\u3002capabilities.camera \u4E5F\u4F1A\u4E0A\u62A5\u8FD9\u4EFD\u8303\u56F4\u3002\n */\nexport const XC_CAMERA_RANGES = {\n fov: [15, 60],\n distance: [1, 15],\n height: [-1, 1],\n} as const;\nconst XC_CAMERA_NUM_KEYS = ['fov', 'distance', 'height'] as const;\nconst XC_CAMERA_KEYS = ['fov', 'distance', 'height', 'intro'] as const;\n\nexport type XcCameraNormalized =\n | { ok: true; camera: XcCamera; /** \u88AB\u5939\u5230\u8303\u56F4\u8FB9\u754C\u7684\u9879 (\u4F9B\u544A\u8B66) */ clamped: string[] }\n | { ok: false; error: string };\n\n/**\n * \u6821\u9A8C + \u89C4\u6574\u4E00\u4E2A camera \u5BF9\u8C61 (xc.setConfig / SDK \u9009\u9879\u5171\u7528)\u3002\n * \u6570\u5B57\u9879\u5FC5\u987B\u662F\u6709\u9650 number (\u8D8A\u754C\u5939\u5230\u8303\u56F4\u5185); intro \u5FC5\u987B\u662F boolean; null = \u6E05\u9664; \u672A\u77E5\u952E / \u975E\u5BF9\u8C61 \u2192 \u9519\u8BEF\u3002\n */\nexport function normalizeXcCamera(raw: unknown): XcCameraNormalized {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return { ok: false, error: 'camera must be an object' };\n const src = raw as Record<string, unknown>;\n for (const k of Object.keys(src)) {\n if (!(XC_CAMERA_KEYS as readonly string[]).includes(k)) return { ok: false, error: `unknown camera key: ${k} (expected ${XC_CAMERA_KEYS.join(' | ')})` };\n }\n const out: XcCamera = {};\n const clamped: string[] = [];\n for (const k of XC_CAMERA_NUM_KEYS) {\n const v = src[k];\n if (v === undefined) continue;\n if (v === null) { out[k] = null; continue; }\n if (typeof v !== 'number' || !Number.isFinite(v)) return { ok: false, error: `camera.${k} must be a finite number or null` };\n const [lo, hi] = XC_CAMERA_RANGES[k];\n const c = Math.min(hi, Math.max(lo, v));\n if (c !== v) clamped.push(k);\n out[k] = c;\n }\n if (src.intro !== undefined) {\n if (src.intro !== null && typeof src.intro !== 'boolean') return { ok: false, error: 'camera.intro must be a boolean or null' };\n out.intro = src.intro;\n }\n return { ok: true, camera: out, clamped };\n}\n\n/**\n * \u89E3\u6790 URL \u53C2\u6570 cameraFov / cameraDistance / cameraHeight / cameraIntro (SDK \u751F\u6210 / \u624B\u5199 iframe \u5747\u53EF)\u3002\n * \u6570\u503C\u975E\u6CD5 \u2192 \u5FFD\u7565\u5E76\u8BB0 warning; \u8D8A\u754C \u2192 \u5939\u5230\u8303\u56F4\u5E76\u8BB0 warning; cameraIntro \u8BA4 0|1|true|false\u3002\n */\nexport function parseXcCameraParams(get: (name: string) => string | null): { camera: XcCamera; warnings: string[] } {\n const camera: XcCamera = {};\n const warnings: string[] = [];\n const names = { fov: 'cameraFov', distance: 'cameraDistance', height: 'cameraHeight' } as const;\n for (const k of XC_CAMERA_NUM_KEYS) {\n const raw = get(names[k]);\n if (raw === null) continue;\n const t = raw.trim();\n const n = t === '' ? NaN : Number(t);\n if (!Number.isFinite(n)) { warnings.push(`ignoring invalid ?${names[k]}=${raw}`); continue; }\n const [lo, hi] = XC_CAMERA_RANGES[k];\n const c = Math.min(hi, Math.max(lo, n));\n if (c !== n) warnings.push(`?${names[k]}=${raw} is out of range [${lo}, ${hi}], clamped to ${c}`);\n camera[k] = c;\n }\n const intro = get('cameraIntro');\n if (intro !== null) {\n const v = intro.trim().toLowerCase();\n if (v === '1' || v === 'true') camera.intro = true;\n else if (v === '0' || v === 'false') camera.intro = false;\n else warnings.push(`ignoring invalid ?cameraIntro=${intro}`);\n }\n return { camera, warnings };\n}\n\nexport const XC_ID_RE = /^[a-z][a-z0-9_]{0,63}$/;\nexport const isXcId = (v: unknown): v is string => typeof v === 'string' && XC_ID_RE.test(v);\n/** \u53EA\u8BA4\u5BF9\u8C61\u81EA\u5DF1\u7684\u5C5E\u6027 (\u4E0D\u8D70\u539F\u578B\u94FE); \u7B49\u4EF7\u4E8E Object.hasOwn, \u4F46\u517C\u5BB9 ES2020 \u76EE\u6807\u3002 */\nexport const xcHasOwn = (o: object, k: string): boolean => Object.prototype.hasOwnProperty.call(o, k);\n\n/** \u5185\u7F6E\u573A\u666F id (\u4EE5 xc.ready.capabilities.scenes \u4E3A\u51C6; \u76EE\u524D\u5C31\u8FD9\u4E09\u4E2A\u4E3B\u9898, \u4E0D\u542B\u771F\u5B9E\u573A\u666F\u8D44\u4EA7)\u3002 */\nexport type XcSceneId = 'light' | 'dark' | 'transparent';\nexport type XcLang = 'zh-CN' | 'en' | 'ja';\n/** iframe \u652F\u6301\u7684\u754C\u9762\u8BED\u8A00 (\u4E0E\u4E3B\u7AD9 SUPPORTED_LANGS \u540C\u4E00\u4EFD; capabilities.ui.langs)\u3002 */\nexport const XC_LANGS: readonly XcLang[] = ['zh-CN', 'en', 'ja'];\nexport type XcPhase = 'idle' | 'loading' | 'thinking' | 'speaking' | 'listening' | 'paused';\n/** lazy = \u4E0D\u9884\u70ED WebLLM / EMAGE, \u9996\u6B21\u4E92\u52A8\u518D\u52A0\u8F7D (\u9ED8\u8BA4); eager = \u7ACB\u5373\u9884\u70ED\u3002 */\nexport type XcHeavyMode = 'lazy' | 'eager';\n\nexport interface XcEnvelope<T extends string = string, P = unknown> {\n type: T;\n v: typeof XC_PROTOCOL_VERSION;\n /** \u5BBF\u4E3B\u547D\u4EE4\u53EF\u5E26 id; \u5BF9\u5E94\u7684 xc.error / xc.utterance \u4F1A\u56DE\u5E26\u540C\u4E00\u4E2A id\u3002 */\n id?: string;\n payload: P;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u5BBF\u4E3B \u2192 iframe payload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface XcConfig {\n lang?: XcLang;\n /** \u80CC\u666F\u900F\u660E (\u53E0\u5728\u5BBF\u4E3B\u9875\u9762\u4E0A)\u3002 */\n transparent?: boolean;\n /**\n * \u8981\u663E\u793A\u7684 iframe \u5185\u7F6E\u754C\u9762\u90E8\u4EF6 (\u89C1 XC_UI_PARTS), \u4F8B\u5982 ['outfit','scene']; \u7701\u7565 / \u7A7A\u6570\u7EC4 = \u4E0D\u663E\u793A\u3002\n * \u4F20 true/false \u662F 0.1.14 \u7684\u65E7\u5199\u6CD5 (true = chat + bubble), \u5DF2\u5F03\u7528, \u4EC5\u4E3A\u517C\u5BB9\u4FDD\u7559\u3002\n */\n ui?: XcUiPart[] | boolean;\n /**\n * \u5185\u7F6E\u754C\u9762\u7684\u663E\u793A\u7B56\u7565 (\u89C1 XcUiAutoHide): \u9ED8\u8BA4 'transparent' = \u4E0E Tauri \u4E00\u81F4 (\u53EA\u5728\u900F\u660E\u573A\u666F\u9690\u85CF\u3001\u5355\u51FB\u89D2\u8272\u51FA\u73B0, \u4EAE / \u6697\u573A\u666F\u5E38\u663E); true = \u6240\u6709\u573A\u666F\u90FD\u70B9\u51FB\u51FA\u73B0; false = \u4E00\u76F4\u663E\u793A\u3002\n * \u4EC5\u5F53 capabilities.ui \u5B58\u5728\u65F6\u624D\u6709\u610F\u4E49 (\u65E7\u7248 /embed \u5FFD\u7565, \u5E38\u663E)\u3002\n */\n uiAutoHide?: XcUiAutoHide;\n /** \u91CD\u8D44\u6E90\u52A0\u8F7D\u7B56\u7565, \u89C1 XcHeavyMode\u3002 */\n heavy?: XcHeavyMode;\n /**\n * \u5141\u8BB8 xc.setModel \u52A0\u8F7D\u4EFB\u610F https URL \u7684 .vrm/.vrmaddon/.vrmbase\u3002\u9ED8\u8BA4 false (\u5173\u95ED): \u53EA\u80FD\u7528 capabilities.outfits \u91CC\u7684\u5185\u7F6E\u670D\u88C5\u3002\n * \u7531\u5BBF\u4E3B SDK \u7684 `allowCustomModel` \u9009\u9879\u53D1\u51FA (\u653E\u5728 xc.init \u7684 config \u91CC)\u3002\n */\n allowCustomModel?: boolean;\n /**\n * \u624B\u52BF\u5F00\u5173 (\u5BBF\u4E3B SDK \u7684 `draggable` / `resizable` \u9009\u9879\u53D1\u51FA; \u653E\u5728 xc.init \u7684 config \u91CC, \u4E5F\u53EF\u7528 xc.setConfig \u8FD0\u884C\u65F6\u6539)\u3002\n * \u9ED8\u8BA4\u5168 false: iframe \u91CC**\u4E0D\u8BC6\u522B**\u5BF9\u5E94\u624B\u52BF\u3001\u4E5F\u4E0D\u62E6\u622A\u4EFB\u4F55\u6307\u9488\u4E8B\u4EF6\u3002\u4EC5\u5F53 capabilities.gestures \u5B58\u5728\u65F6\u624D\u6709\u610F\u4E49 (\u65E7\u7248 /embed \u5FFD\u7565)\u3002\n * move = \u5DE6\u952E\u5728\u89D2\u8272\u4E0A\u62D6\u52A8 \u2192 \u53D1 xc.gesture-move, \u7531\u5BBF\u4E3B\u79FB\u52A8 iframe\n * resize = \u5728 iframe \u56DB\u89D2\u70ED\u533A\u6309\u4E0B\u62D6\u52A8 \u2192 \u53D1 xc.gesture-resize, \u7531\u5BBF\u4E3B\u7F29\u653E iframe\n */\n gestures?: { move?: boolean; resize?: boolean };\n /**\n * \u76F8\u673A\u9009\u9879 (\u89C1 XcCamera); \u653E\u5728 xc.init \u7684 config \u91CC\u6216\u7528 xc.setConfig \u8FD0\u884C\u65F6\u6539 (\u7F3A\u7701\u952E = \u4E0D\u53D8, null = \u6062\u590D\u9ED8\u8BA4, \u975E\u6CD5\u503C \u2192 xc.error{bad_request})\u3002\n * \u8FD0\u884C\u65F6\u6539\u4F1A\u7ACB\u523B\u91CD\u65B0\u53D6\u666F\u5E76\u53D6\u6D88\u8FDB\u884C\u4E2D\u7684\u63A8\u955C\u5934\u3002\u4EC5\u5F53 capabilities.camera \u5B58\u5728\u65F6\u624D\u6709\u610F\u4E49 (\u65E7\u7248 /embed \u5FFD\u7565)\u3002\n */\n camera?: XcCamera;\n}\n\nexport interface XcInitPayload {\n /** \u5BBF\u4E3B\u58F0\u660E\u7684\u81EA\u8EAB origin (iframe \u4F1A\u4E0E event.origin \u4EA4\u53C9\u6821\u9A8C)\u3002 */\n hostOrigin: string;\n config?: XcConfig;\n}\n\nexport interface XcSayPayload {\n text: string;\n /**\n * 'speak' (\u9ED8\u8BA4): \u76F4\u63A5 TTS + \u52A8\u4F5C, \u4E0D\u7ECF\u8FC7 LLM\u3002\n * 'chat': \u5F53\u4F5C\u7528\u6237\u8F93\u5165\u8D70 WebLLM / \u81EA\u5B9A\u4E49 provider (\u4F1A\u89E6\u53D1\u5927\u6A21\u578B\u52A0\u8F7D)\u3002\n */\n mode?: 'speak' | 'chat';\n}\n\n/** \u5BBF\u4E3B\u97F3\u9891\u7684\u7F16\u7801: encoded = \u5BB9\u5668\u683C\u5F0F (mp3/wav/ogg/aac/webm\u2026 \u7531\u6D4F\u89C8\u5668 decodeAudioData \u51B3\u5B9A); pcm16 / float32 = \u65E0\u5934\u539F\u59CB PCM (\u5C0F\u7AEF, \u4EA4\u9519)\u3002 */\nexport type XcAudioFormat = 'encoded' | 'pcm16' | 'float32';\n\nexport interface XcAudioOptions {\n /** \u6C14\u6CE1\u91CC\u663E\u793A\u7684\u6587\u5B57 (\u53EF\u9009; \u4E0D\u5F71\u54CD\u97F3\u9891\u4E0E\u52A8\u4F5C)\u3002 */\n text?: string;\n /** \u662F\u5426\u7531 EMAGE \u6839\u636E\u8FD9\u6BB5\u97F3\u9891\u751F\u6210\u5168\u8EAB\u52A8\u4F5C, \u9ED8\u8BA4 true\u3002false = \u53EA\u64AD\u653E\u97F3\u9891 (\u6B64\u65F6\u5B8C\u5168\u4E0D\u52A0\u8F7D EMAGE)\u3002 */\n motion?: boolean;\n /** \u662F\u5426\u9A71\u52A8\u53E3\u578B (\u97F3\u91CF RMS \u2192 'aa'), \u9ED8\u8BA4 true\u3002 */\n lipsync?: boolean;\n}\n\n/**\n * xc.audio \u2014 \u6574\u6BB5\u97F3\u9891: iframe \u5185\u89E3\u7801 \u2192 16 kHz \u2192 EMAGE \u7A97\u53E3\u63A8\u7406 + \u540C\u4E00\u6BB5\u97F3\u9891\u64AD\u653E + \u53E3\u578B, \u64AD\u5B8C\u56DE xc.utterance{phase:'end'}\u3002\n * \u4FE1\u5C01 `id` \u7528\u4E8E\u5173\u8054 xc.utterance / xc.error\u3002\u5927 ArrayBuffer \u8BF7\u653E\u8FDB postMessage \u7684 transfer \u5217\u8868 (SDK \u9ED8\u8BA4\u8FD9\u4E48\u505A)\u3002\n */\nexport interface XcAudioPayload extends XcAudioOptions {\n /** ArrayBuffer / Blob (structured clone) \u6216 URL \u5B57\u7B26\u4E32 (iframe \u5185 fetch, \u4EC5 https \u6216\u540C\u6E90, \u9700 CORS)\u3002 */\n source: ArrayBuffer | Blob | string;\n /** MIME \u63D0\u793A, \u5982 'audio/mpeg'\u3002\u4EC5\u4F5C\u4FE1\u606F, \u89E3\u7801\u4EE5\u6D4F\u89C8\u5668\u55C5\u63A2\u4E3A\u51C6\u3002 */\n mimeType?: string;\n /** \u9ED8\u8BA4 'encoded'\u3002 */\n format?: XcAudioFormat;\n /** \u4EC5\u539F\u59CB PCM \u9700\u8981 (\u9ED8\u8BA4 16000); \u5BB9\u5668\u683C\u5F0F\u5FFD\u7565 (\u4EE5\u6587\u4EF6\u5185\u7684\u91C7\u6837\u7387\u4E3A\u51C6)\u3002\u8303\u56F4 8000~96000\u3002 */\n sampleRate?: number;\n /** \u539F\u59CB PCM \u7684\u58F0\u9053\u6570 (\u4EA4\u9519), 1 \u6216 2, \u9ED8\u8BA4 1; \u5185\u90E8\u4E0B\u6DF7\u4E3A\u5355\u58F0\u9053\u3002 */\n channels?: 1 | 2;\n}\n\n/**\n * xc.audio.chunk \u2014 \u6D41\u5F0F\u97F3\u9891\u5206\u5757 (\u539F\u59CB PCM)\u3002\u4FE1\u5C01 `id` = \u6D41 id: \u540C\u4E00\u4E2A id \u7684\u7B2C\u4E00\u4E2A chunk \u5F00\u542F\u4E00\u6B21\u8BF4\u8BDD (\u56DE xc.utterance start),\n * \u4E4B\u540E\u7684 chunk \u8FFD\u52A0; \u4EE5 xc.audio.end \u6536\u5C3E\u3002\u6BCF\u4E2A chunk \u7684 `data` \u5E94\u653E\u8FDB transfer \u5217\u8868\u3002\n * \u9009\u9879 (text/motion/lipsync) \u53EA\u5728\u7B2C\u4E00\u4E2A chunk \u91CC\u751F\u6548; sampleRate/format \u6574\u6761\u6D41\u5FC5\u987B\u4E00\u81F4\u3002\n */\nexport interface XcAudioChunkPayload extends XcAudioOptions {\n data: ArrayBuffer;\n format: Exclude<XcAudioFormat, 'encoded'>;\n /** 8000~96000\u3002 */\n sampleRate: number;\n channels?: 1 | 2;\n}\n\nexport interface XcAudioEndPayload {\n /** true = \u7ACB\u5373\u6253\u65AD (\u4E22\u5F03\u672A\u64AD\u653E\u7684\u97F3\u9891); \u9ED8\u8BA4 false = \u64AD\u5B8C\u5DF2\u6536\u5230\u7684\u97F3\u9891\u540E\u7ED3\u675F\u3002 */\n abort?: boolean;\n}\n\nexport interface XcMotionPayload {\n /** .vrma URL (https:// \u6216\u540C\u6E90\u8DEF\u5F84)\u3002\u4E0E stop \u4E8C\u9009\u4E00\u3002 */\n url?: string;\n /** \u5185\u7F6E\u52A8\u4F5C\u540D, \u76EE\u524D\u4EC5 'thinking'\u3002 */\n name?: 'thinking';\n stop?: boolean;\n loop?: boolean;\n /** \u6DE1\u5165\u6DE1\u51FA\u79D2\u6570, \u8303\u56F4 0.26~3, \u8C03\u5927\u66F4\u67D4\u548C\u4F46\u54CD\u5E94\u66F4\u6162\u3002 */\n fadeDuration?: number;\n /** \u64AD\u653E\u500D\u901F, \u8303\u56F4 0.25~3\u3002 */\n timeScale?: number;\n mask?: 'all' | 'upperBody';\n}\n\nexport interface XcExpressionPayload {\n name: 'neutral' | 'happy' | 'angry' | 'sad' | 'relaxed' | 'surprised';\n}\n\n/** xc.lookAt \u2014 TODO: \u6682\u4E0D\u652F\u6301, \u6536\u5230\u4F1A\u8FD4\u56DE unsupported\u3002 */\nexport interface XcLookAtPayload {\n /** \u5F52\u4E00\u5316 (-1..1), \u76F8\u5BF9 iframe \u4E2D\u5FC3\u3002 */\n x: number;\n y: number;\n}\n\nexport interface XcPointerPayload {\n /** iframe \u5185 client \u5750\u6807 (px)\u3002SDK \u4F1A\u628A\u5BBF\u4E3B pointer \u4E8B\u4EF6\u6362\u7B97\u597D\u518D\u53D1\u3002 */\n x: number;\n y: number;\n}\n\nexport interface XcSetModelPayload {\n /** \u5B8C\u6574 .vrm / .vrmaddon / .vrmbase URL (\u9700 CORS)\u3002**\u9ED8\u8BA4\u5173\u95ED**, \u9700\u8981 xc.init config.allowCustomModel=true, \u5426\u5219\u56DE unsupported\u3002 */\n url?: string;\n /** \u5185\u7F6E\u670D\u88C5 id (capabilities.outfits \u91CC\u7684 id, \u5982 'xiaochun_maid')\u3002\u88F8\u6A21 'base' \u4E0D\u5BF9\u5916\u5F00\u653E (\u56DE unknown_id)\u3002\u65B0\u4EE3\u7801\u8BF7\u7528 xc.setOutfit\u3002 */\n outfit?: string;\n name?: string;\n}\n\n/** xc.setOutfit \u2014 \u6362\u5185\u7F6E\u670D\u88C5 (id \u6765\u81EA xc.ready.capabilities.outfits)\u3002\u4E32\u884C + last-wins, \u89C1 docs/EMBED.md\u3002 */\nexport interface XcSetOutfitPayload {\n id: string;\n}\n\n/**\n * xc.prefetch \u2014 \u9884\u53D6\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB (\u4E4B\u540E xc.setOutfit \u76F4\u63A5\u547D\u4E2D\u7F13\u5B58, \u4E0D\u8D70\u7F51\u7EDC)\u3002\u9ED8\u8BA4\u4E0D\u4F1A\u81EA\u52A8\u53D1\u751F\u3002\n * \u5168\u5C40\u4E32\u884C (\u5E76\u53D1 1); \u5F00\u4E86 heavy:'eager' \u65F6\u6392\u5728 EMAGE \u52A0\u8F7D\u4E4B\u540E, \u4E5F\u4E0D\u4F1A\u548C\u8FDB\u884C\u4E2D\u7684\u6362\u88C5\u62A2\u5E26\u5BBD\u3002\n * ids \u7701\u7565 = \u5168\u90E8\u5185\u7F6E\u670D\u88C5, **\u9664\u4E86**\u4F53\u79EF\u5927\u7684\u5A5A\u7EB1 (xiaochun_wedding, 13.9MB); \u663E\u5F0F\u70B9\u540D\u5219\u7167\u505A\u3002\n * \u5E94\u7B54 xc.prefetched (\u5E26\u540C\u4E00\u4E2A\u4FE1\u5C01 id)\u3002\n */\nexport interface XcPrefetchPayload {\n ids?: string[];\n}\n\n/** xc.prefetched \u2014 \u9884\u53D6\u5B8C\u6210 (\u9010\u9879\u6210\u8D25\u4E0D\u5F71\u54CD\u6574\u4F53; failed \u91CC\u7684 id \u53EF\u7A0D\u540E\u91CD\u8BD5)\u3002 */\nexport interface XcPrefetchedPayload {\n downloaded: string[];\n cached: string[];\n failed: string[];\n /** 'save-data' = \u7528\u6237\u5F00\u4E86\u7701\u6D41\u91CF\u6A21\u5F0F, \u6574\u4E2A\u8BF7\u6C42\u88AB\u8DF3\u8FC7\u3002 */\n skipped?: 'save-data';\n}\n\n/** xc.setScene \u2014 \u8FD0\u884C\u65F6\u5207\u573A\u666F (id \u6765\u81EA xc.ready.capabilities.scenes: light / dark / transparent)\u3002 */\nexport interface XcSetScenePayload {\n id: string;\n}\n\nexport interface XcMicPayload {\n enabled: boolean;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 iframe \u2192 \u5BBF\u4E3B payload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface XcReadyPayload {\n version: string;\n protocol: typeof XC_PROTOCOL_VERSION;\n capabilities: {\n commands: string[];\n unsupported: string[];\n stt: boolean;\n transparent: boolean;\n /** \u5BBF\u4E3B\u97F3\u9891\u80FD\u529B (xc.audio / xc.audio.chunk)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n audio?: { formats: XcAudioFormat[]; streaming: boolean; maxSeconds: number };\n /** iframe \u5185 `self.crossOriginIsolated` (true = \u53EF\u7528 SharedArrayBuffer / \u591A\u7EBF\u7A0B wasm)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002\u4EC5\u8BCA\u65AD\u7528\u3002 */\n crossOriginIsolated?: boolean;\n /** \u53EF\u6362\u7684\u5185\u7F6E\u670D\u88C5 (\u4E0D\u542B\u88F8\u6A21)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u5BBF\u4E3B\u5E94\u89C6\u4E3A\"\u4E0D\u652F\u6301 xc.setOutfit\"\u3002 */\n outfits?: XcOutfitInfo[];\n /** \u53EF\u5207\u7684\u573A\u666F\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u89C6\u4E3A\"\u4E0D\u652F\u6301 xc.setScene\"\u3002 */\n scenes?: XcSceneInfo[];\n /** \u652F\u6301 xc.prefetch\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n prefetch?: boolean;\n /**\n * iframe \u5185\u624B\u52BF (\u62D6\u52A8 / \u89D2\u843D\u7F29\u653E) \u652F\u6301\u60C5\u51B5; \u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u5BBF\u4E3B\u89C6\u4E3A\"\u4E0D\u652F\u6301\", draggable / resizable \u65E0\u6548\u3002\n * cornerSize = \u56DB\u89D2\u70ED\u533A\u8FB9\u957F (CSS px, iframe \u89C6\u53E3\u5DE6\u4E0A/\u53F3\u4E0A/\u5DE6\u4E0B/\u53F3\u4E0B\u5404\u4E00\u4E2A\u6B63\u65B9\u5F62), \u5BBF\u4E3B UI \u53EF\u636E\u6B64\u63D0\u793A\u3002\n */\n gestures?: { move: boolean; resize: boolean; cornerSize: number };\n /**\n * \u5185\u7F6E\u754C\u9762\u80FD\u529B; \u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u5BBF\u4E3B\u89C6\u4E3A\"\u6CA1\u6709 lang / github \u90E8\u4EF6\u3001\u4E0D\u652F\u6301 uiAutoHide (\u754C\u9762\u5E38\u663E)\"\u3002\n * parts = \u53EF\u7528\u7684\u90E8\u4EF6\u540D; autoHide = \u652F\u6301 uiAutoHide (\u70B9\u51FB\u51FA\u73B0); langs = \u8BED\u8A00\u6309\u94AE / `lang` \u9009\u9879\u53EF\u7528\u7684\u53D6\u503C\u3002\n */\n ui?: { parts: XcUiPart[]; autoHide: boolean; langs: XcLang[] };\n /**\n * \u76F8\u673A\u9009\u9879\u80FD\u529B (\u89C1 XcCamera); \u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5 \u2192 \u5BBF\u4E3B\u89C6\u4E3A\"\u4E0D\u652F\u6301 camera \u9009\u9879\"\u3002\n * fov / distance / height = \u5404\u9879\u5141\u8BB8\u8303\u56F4 [min, max] (\u8D8A\u754C\u4F1A\u88AB\u5939\u5230\u8FB9\u754C); intro = \u652F\u6301\u5173\u95ED\u63A8\u955C\u5934\u3002\n */\n camera?: { fov: [number, number]; distance: [number, number]; height: [number, number]; intro: boolean };\n };\n}\n\nexport interface XcOutfitInfo {\n id: string;\n /** \u5C55\u793A\u540D (\u82F1\u6587, \u6765\u81EA\u4E3B\u4ED3\u5E93\u914D\u7F6E)\u3002 */\n name: string;\n /** \u670D\u88C5\u6587\u4EF6\u5927\u5C0F\u63D0\u793A (MB, \u5341\u8FDB\u5236, \u7EA6\u503C; \u516C\u5171\u7684\u88F8\u6A21 ~5.7MB \u4E0D\u8BA1)\u3002\u4EC5\u4F9B\u5BBF\u4E3B\u81EA\u5DF1\u7684 UI \u53C2\u8003 (\u5185\u7F6E\u6362\u88C5\u83DC\u5355\u4E0D\u663E\u793A\u4F53\u79EF); \u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n sizeMB?: number;\n}\n\nexport interface XcSceneInfo {\n id: string;\n /** true = \u80CC\u666F\u900F\u660E (\u53E0\u5728\u5BBF\u4E3B\u9875\u4E0A, \u53EF\u5F00\u7A7F\u900F)\u3002 */\n transparent: boolean;\n}\n\nexport interface XcLoadProgressPayload {\n /**\n * 'model' = \u9996\u6B21\u52A0\u8F7D; 'outfit' = \u8FD0\u884C\u4E2D\u6362\u88C5 (id = \u76EE\u6807\u670D\u88C5 id, \u81EA\u5B9A\u4E49 URL \u65F6\u7701\u7565);\n * 'prefetch' = \u5BBF\u4E3B\u53D1\u4E86 xc.prefetch \u540E\u7684\u540E\u53F0\u4E0B\u8F7D (id = \u6B63\u5728\u9884\u53D6\u7684\u670D\u88C5)\u3002\u5DF2\u6709\u7684\"model \u8FDB\u5EA6\u6761\"\u903B\u8F91\u8BF7\u5148\u5224\u65AD phase\u3002\n */\n phase: 'model' | 'outfit' | 'prefetch';\n /** 0~100 */\n progress: number;\n id?: string;\n}\n\nexport interface XcLoadedPayload {\n model: string;\n}\n\n/**\n * xc.outfit-changed \u2014 \u670D\u88C5\u5DF2\u751F\u6548\u3002\u4E09\u79CD\u6765\u6E90: \u9996\u6B21\u52A0\u8F7D (initial:true)\u3001xc.setOutfit / xc.setModel \u7684\u5E94\u7B54 (\u5E26\u540C\u4E00\u4E2A\u4FE1\u5C01 id)\u3002\n * noop:true = \u76EE\u6807\u5DF2\u7ECF\u662F\u5F53\u524D\u670D\u88C5 (\u6216\u4E0E\u53E6\u4E00\u4E2A\u540C\u76EE\u6807\u8BF7\u6C42\u5408\u5E76), \u6CA1\u6709\u91CD\u65B0\u52A0\u8F7D; SDK \u53EA\u7528\u5B83 resolve \u5BF9\u5E94\u7684 Promise, \u4E0D\u518D\u89E6\u53D1\u4E8B\u4EF6\u3002\n */\nexport interface XcOutfitChangedPayload {\n /** \u5185\u7F6E\u670D\u88C5 id; \u81EA\u5B9A\u4E49 URL \u6A21\u578B\u4E3A null\u3002 */\n id: string | null;\n name: string;\n previous?: string | null;\n initial?: boolean;\n noop?: boolean;\n}\n\n/** xc.scene-changed \u2014 \u573A\u666F\u5DF2\u751F\u6548 (\u9996\u6B21\u63E1\u624B\u540E\u7684\u5F53\u524D\u573A\u666F / xc.setScene \u5E94\u7B54 / xc.setConfig{transparent} \u5F15\u8D77\u7684\u5207\u6362)\u3002 */\nexport interface XcSceneChangedPayload {\n id: string;\n transparent: boolean;\n previous?: string | null;\n initial?: boolean;\n noop?: boolean;\n}\n\n/**\n * xc.lang-changed \u2014 iframe \u5F53\u524D\u754C\u9762\u8BED\u8A00 (\u63E1\u624B\u540E\u4E0A\u62A5\u4E00\u6B21 initial:true; \u4E4B\u540E\u7528\u6237\u70B9\u8BED\u8A00\u6309\u94AE / xc.setConfig{lang} \u5F15\u8D77\u7684\u53D8\u5316)\u3002\n * \u521D\u59CB\u8BED\u8A00\u4F18\u5148\u7EA7: `?lang=` (SDK `lang` \u9009\u9879) > iframe \u81EA\u5DF1 localStorage \u91CC\u8BB0\u4F4F\u7684\u7528\u6237\u9009\u62E9 > \u6D4F\u89C8\u5668\u8BED\u8A00 > zh-CN\u3002\n */\nexport interface XcLangChangedPayload {\n lang: XcLang;\n previous?: XcLang | null;\n initial?: boolean;\n}\n\nexport interface XcStatePayload {\n phase: XcPhase;\n paused: boolean;\n heavy: XcHeavyMode;\n}\n\nexport type XcSttPayload =\n | { kind: 'state'; state: 'idle' | 'loading' | 'listening' | 'recognizing' | 'error' }\n | { kind: 'progress'; percent: number }\n | { kind: 'text'; text: string };\n\nexport interface XcUtterancePayload {\n phase: 'start' | 'end';\n text: string;\n /** 'text' = xc.say (TTS); 'audio' = xc.audio / xc.audio.chunk (\u5BBF\u4E3B\u97F3\u9891, \u6CA1\u6709\u8D70 TTS)\u3002\u65E7\u7248 /embed \u6CA1\u6709\u8FD9\u4E2A\u5B57\u6BB5\u3002 */\n kind?: 'text' | 'audio';\n}\n\nexport interface XcHitRegionPayload {\n hit: boolean;\n x: number;\n y: number;\n}\n\n/** \u624B\u52BF\u9636\u6BB5: start = \u6309\u4E0B\u540E\u786E\u8BA4\u6210\u624B\u52BF; move = \u589E\u91CF; end = \u7ED3\u675F (\u677E\u624B / \u53D6\u6D88 / \u5931\u7126)\u3002 */\nexport type XcGesturePhase = 'start' | 'move' | 'end';\n\n/**\n * xc.gesture-move / xc.gesture-resize \u7684\u516C\u5171\u5B57\u6BB5\u3002\u5355\u4F4D CSS px (\u5C4F\u5E55\u5750\u6807\u5DEE, iframe \u88AB\u79FB\u52A8\u65F6\u4ECD\u7A33\u5B9A)\u3002\n * - gesture: \u624B\u52BF\u5E8F\u53F7, \u6BCF\u6B21\u65B0\u624B\u52BF +1 (\u4ECE 1 \u8D77); \u5BBF\u4E3B\u636E\u6B64\u533A\u5206\u624B\u52BF, \u4E22\u5F03\u8FC7\u671F\u624B\u52BF\u7684\u8FDF\u5230\u6D88\u606F\u3002\n * - seq: \u8BE5\u624B\u52BF\u5185\u7684\u6D88\u606F\u5E8F\u53F7, start = 0, \u4E4B\u540E\u4E25\u683C\u9012\u589E; \u5BBF\u4E3B\u4E22\u5F03 seq \u4E0D\u9012\u589E\u7684\u6D88\u606F\u3002\n * - dx / dy: \u76F8\u5BF9\u4E0A\u4E00\u6761\u6D88\u606F\u7684\u589E\u91CF; totalDx / totalDy: \u76F8\u5BF9 start \u7684\u7D2F\u8BA1 (\u5BBF\u4E3B\u4EE5\u5B83\u4E3A\u51C6\u8BA1\u7B97, \u589E\u91CF\u53EA\u662F\u53C2\u8003, \u4E22\u5305\u4E5F\u4E0D\u6F02\u79FB)\u3002\n * - reason: \u4EC5 phase='end' \u5E26: up = \u677E\u624B, cancel = \u6307\u9488\u88AB\u7CFB\u7EDF\u53D6\u6D88, blur = \u7A97\u53E3\u5931\u7126\u3002\n */\nexport interface XcGestureBase {\n gesture: number;\n seq: number;\n phase: XcGesturePhase;\n dx: number;\n dy: number;\n totalDx: number;\n totalDy: number;\n reason?: 'up' | 'cancel' | 'blur';\n}\nexport type XcGestureMovePayload = XcGestureBase;\nexport type XcGestureCorner = 'NW' | 'NE' | 'SW' | 'SE';\nexport interface XcGestureResizePayload extends XcGestureBase {\n /** \u88AB\u62D6\u7684\u89D2; \u5BF9\u89D2\u56FA\u5B9A\u4E0D\u52A8\u3002 */\n corner: XcGestureCorner;\n}\n\nexport interface XcErrorPayload {\n code: XcErrorCode;\n message: string;\n /** \u89E6\u53D1\u9519\u8BEF\u7684\u547D\u4EE4\u540D (\u5982 'xc.lookAt')\u3002 */\n command?: string;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u7C7B\u578B\u6620\u5C04 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface XcHostPayloadMap {\n 'xc.init': XcInitPayload;\n 'xc.say': XcSayPayload;\n 'xc.audio': XcAudioPayload;\n 'xc.audio.chunk': XcAudioChunkPayload;\n 'xc.audio.end': XcAudioEndPayload;\n 'xc.motion': XcMotionPayload;\n 'xc.expression': XcExpressionPayload;\n 'xc.lookAt': XcLookAtPayload;\n 'xc.pointer': XcPointerPayload;\n 'xc.setModel': XcSetModelPayload;\n 'xc.setOutfit': XcSetOutfitPayload;\n 'xc.setScene': XcSetScenePayload;\n 'xc.prefetch': XcPrefetchPayload;\n 'xc.setConfig': XcConfig;\n 'xc.mic': XcMicPayload;\n 'xc.pause': undefined;\n 'xc.resume': undefined;\n 'xc.destroy': undefined;\n}\n\nexport interface XcFramePayloadMap {\n 'xc.ready': XcReadyPayload;\n 'xc.load.progress': XcLoadProgressPayload;\n 'xc.loaded': XcLoadedPayload;\n 'xc.outfit-changed': XcOutfitChangedPayload;\n 'xc.scene-changed': XcSceneChangedPayload;\n 'xc.lang-changed': XcLangChangedPayload;\n 'xc.prefetched': XcPrefetchedPayload;\n 'xc.state': XcStatePayload;\n 'xc.stt': XcSttPayload;\n 'xc.utterance': XcUtterancePayload;\n 'xc.hit-region': XcHitRegionPayload;\n 'xc.gesture-move': XcGestureMovePayload;\n 'xc.gesture-resize': XcGestureResizePayload;\n 'xc.error': XcErrorPayload;\n}\n\nexport type XcHostMessage = {\n [K in XcHostMessageType]: XcEnvelope<K, XcHostPayloadMap[K]>;\n}[XcHostMessageType];\n\nexport type XcFrameMessage = {\n [K in XcFrameMessageType]: XcEnvelope<K, XcFramePayloadMap[K]>;\n}[XcFrameMessageType];\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u5C0F\u5DE5\u5177 (SDK \u4E0E /embed \u5171\u7528) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport function xcMessage<K extends XcHostMessageType | XcFrameMessageType>(\n type: K,\n payload?: unknown,\n id?: string,\n): XcEnvelope<K, any> {\n const m: XcEnvelope<K, any> = { type, v: XC_PROTOCOL_VERSION, payload };\n if (id !== undefined) m.id = id;\n return m;\n}\n\n/** \u662F\u5426\u4E3A\u5408\u6CD5 xc \u4FE1\u5C01 (\u53EA\u68C0\u67E5\u7ED3\u6784, \u4E0D\u68C0\u67E5 payload)\u3002 */\nexport function isXcEnvelope(data: unknown): data is XcEnvelope {\n if (!data || typeof data !== 'object') return false;\n const d = data as Record<string, unknown>;\n return typeof d.type === 'string' && d.type.startsWith('xc.') && d.v === XC_PROTOCOL_VERSION;\n}\n\n/**\n * \u628A\u7528\u6237\u7ED9\u7684 origin \u89C4\u6574\u6210\u4E25\u683C\u7684 `scheme://host[:port]`\u3002\n * \u62D2\u7EDD '*' / \u901A\u914D / \u975E http(s) / \u5E26\u8DEF\u5F84\u7684\u5B57\u7B26\u4E32 \u2192 \u8FD4\u56DE null\u3002\n */\nexport function normalizeOrigin(input: string | null | undefined): string | null {\n if (!input || input === '*' || input === 'null') return null;\n try {\n const u = new URL(input);\n if (u.protocol !== 'https:' && u.protocol !== 'http:') return null;\n return u.origin;\n } catch {\n return null;\n }\n}\n", "/**\n * gesture-box.ts \u2014 iframe \u624B\u52BF (xc.gesture-move / xc.gesture-resize) \u5728\u5BBF\u4E3B\u4FA7\u7684\u7EAF\u903B\u8F91: \u6821\u9A8C + \u51E0\u4F55\u9650\u5E45\u3002\u96F6 DOM \u4F9D\u8D56, \u53EF\u5355\u6D4B\u3002\n *\n * \u5BBF\u4E3B SDK \u5BF9 iframe \u53D1\u6765\u7684\u624B\u52BF**\u4E0D\u4FE1\u4EFB**: \u8F7D\u8377\u9010\u5B57\u6BB5\u6821\u9A8C (\u7C7B\u578B / \u6709\u9650\u6570 / \u91CF\u7EA7 / \u89D2\u540D), \u5E8F\u53F7\u5FC5\u987B\u6309\u89C4\u5219\u9012\u589E (GestureGate),\n * \u4F4D\u7F6E / \u5C3A\u5BF8\u5168\u90E8\u5728\u8FD9\u91CC\u6309\"\u5F53\u524D\u89C6\u53E3 + \u6700\u5C0F / \u6700\u5927\u5C3A\u5BF8\"\u5939\u7D27, iframe \u8BF4\u591A\u5C11\u5C31\u79FB\u591A\u5C11\u662F\u4E0D\u53EF\u80FD\u7684\u3002\n * \u8BA1\u7B97\u4E00\u5F8B\u7528 start \u65F6\u7684\u76D2\u5B50 + \u7D2F\u8BA1\u4F4D\u79FB (totalDx / totalDy), \u4E0D\u7D2F\u52A0\u589E\u91CF: \u4E22\u5305 / \u5939\u7D27\u90FD\u4E0D\u4F1A\u8BA9\u7ED3\u679C\u6F02\u79FB\u3002\n */\nimport type { XcGestureCorner } from './protocol';\n\nexport interface Box { left: number; top: number; width: number; height: number }\nexport interface Viewport { width: number; height: number }\nexport interface ResizeLimits { minWidth: number; minHeight: number; maxWidth: number; maxHeight: number }\n\n/** \u9ED8\u8BA4\u9650\u5E45: \u6700\u5C0F 120x180 (\u518D\u5C0F\u89D2\u8272\u57FA\u672C\u770B\u4E0D\u6E05), \u6700\u5927\u53EA\u53D7\u89C6\u53E3\u9650\u5236\u3002 */\nexport const DEFAULT_RESIZE_LIMITS: Readonly<ResizeLimits> = Object.freeze({\n minWidth: 120, minHeight: 180, maxWidth: Infinity, maxHeight: Infinity,\n});\n\nexport interface XiaochunResizeLimits {\n /** \u6700\u5C0F\u5BBD (px), \u9ED8\u8BA4 120\u3002 */\n minWidth?: number;\n /** \u6700\u5C0F\u9AD8 (px), \u9ED8\u8BA4 180\u3002 */\n minHeight?: number;\n /** \u6700\u5927\u5BBD (px), \u9ED8\u8BA4\u53EA\u53D7\u89C6\u53E3\u9650\u5236\u3002 */\n maxWidth?: number;\n /** \u6700\u5927\u9AD8 (px), \u9ED8\u8BA4\u53EA\u53D7\u89C6\u53E3\u9650\u5236\u3002 */\n maxHeight?: number;\n}\n\nconst finitePositive = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v > 0;\n\n/** `resizable` \u9009\u9879 \u2192 \u9650\u5E45; false / undefined \u2192 null (\u5173\u95ED); true \u2192 \u9ED8\u8BA4\u9650\u5E45; \u5BF9\u8C61 \u2192 \u9010\u9879\u8986\u76D6 (\u975E\u6CD5\u503C\u7528\u9ED8\u8BA4)\u3002min \u4E0D\u4F1A\u8D85\u8FC7 max\u3002 */\nexport function normalizeResizable(v: boolean | XiaochunResizeLimits | undefined): ResizeLimits | null {\n if (!v) return null;\n const o = v === true ? {} : v;\n const minWidth = finitePositive(o.minWidth) ? o.minWidth : DEFAULT_RESIZE_LIMITS.minWidth;\n const minHeight = finitePositive(o.minHeight) ? o.minHeight : DEFAULT_RESIZE_LIMITS.minHeight;\n const maxWidth = finitePositive(o.maxWidth) ? Math.max(o.maxWidth, minWidth) : Infinity;\n const maxHeight = finitePositive(o.maxHeight) ? Math.max(o.maxHeight, minHeight) : Infinity;\n return { minWidth, minHeight, maxWidth, maxHeight };\n}\n\nconst clamp = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), Math.max(lo, hi));\n\n/** \u79FB\u52A8: \u8D77\u70B9\u76D2\u5B50 + \u7D2F\u8BA1\u4F4D\u79FB, \u5939\u5728\u89C6\u53E3\u5185 (\u76D2\u5B50\u6BD4\u89C6\u53E3\u5927\u65F6\u8D34\u5DE6\u4E0A)\u3002 */\nexport function moveBox(start: Box, totalDx: number, totalDy: number, vp: Viewport): Box {\n return {\n left: clamp(start.left + totalDx, 0, vp.width - start.width),\n top: clamp(start.top + totalDy, 0, vp.height - start.height),\n width: start.width,\n height: start.height,\n };\n}\n\n/**\n * \u7F29\u653E: \u88AB\u62D6\u7684\u89D2\u8DDF\u624B, \u5BF9\u89D2\u56FA\u5B9A; \u5BBD\u9AD8\u5939\u5728 [min, min(max, \u89C6\u53E3\u5185\u8FD8\u80FD\u4F38\u5C55\u7684\u7A7A\u95F4)]\u3002\n * \u4F8B: \u62D6 SE \u89D2 \u2192 \u5DE6\u4E0A\u56FA\u5B9A, \u53F3 / \u4E0B\u8FB9\u754C\u4E0D\u80FD\u8D8A\u8FC7\u89C6\u53E3; \u62D6 NW \u89D2 \u2192 \u53F3\u4E0B\u56FA\u5B9A, \u5DE6 / \u4E0A\u8FB9\u754C\u4E0D\u80FD\u8D8A\u8FC7\u89C6\u53E3\u3002\n */\nexport function resizeBox(start: Box, corner: XcGestureCorner, totalDx: number, totalDy: number, limits: ResizeLimits, vp: Viewport): Box {\n const west = corner === 'NW' || corner === 'SW';\n const north = corner === 'NW' || corner === 'NE';\n const right = start.left + start.width, bottom = start.top + start.height;\n const wantW = west ? start.width - totalDx : start.width + totalDx;\n const wantH = north ? start.height - totalDy : start.height + totalDy;\n const roomW = west ? right : vp.width - start.left;\n const roomH = north ? bottom : vp.height - start.top;\n const width = clamp(wantW, limits.minWidth, Math.min(limits.maxWidth, roomW));\n const height = clamp(wantH, limits.minHeight, Math.min(limits.maxHeight, roomH));\n return { left: west ? right - width : start.left, top: north ? bottom - height : start.top, width, height };\n}\n\n/** \u7A97\u53E3 / \u89C6\u53E3\u53D8\u5C0F\u540E\u628A\u76D2\u5B50\u91CD\u65B0\u5939\u56DE\u89C6\u53E3 (\u5C3A\u5BF8\u4E5F\u4E0D\u8D85\u8FC7\u89C6\u53E3)\u3002 */\nexport function fitBox(b: Box, vp: Viewport): Box {\n const width = Math.min(b.width, Math.max(1, vp.width)), height = Math.min(b.height, Math.max(1, vp.height));\n return { left: clamp(b.left, 0, vp.width - width), top: clamp(b.top, 0, vp.height - height), width, height };\n}\n\n// \u2500\u2500 \u8F7D\u8377\u6821\u9A8C \u2500\u2500\nconst CORNERS = new Set(['NW', 'NE', 'SW', 'SE']);\nconst PHASES = new Set(['start', 'move', 'end']);\nconst REASONS = new Set(['up', 'cancel', 'blur']);\n/** \u5355\u6B21\u7D2F\u8BA1\u4F4D\u79FB\u7684\u5408\u7406\u4E0A\u9650 (CSS px)\u3002\u5C4F\u5E55\u518D\u5927\u4E5F\u5230\u4E0D\u4E86, \u8D85\u8FC7\u7684\u4E00\u5F8B\u5F53\u4F5C\u4F2A\u9020\u3002 */\nexport const MAX_GESTURE_DELTA = 20_000;\n\nexport interface ParsedGesture {\n gesture: number;\n seq: number;\n phase: 'start' | 'move' | 'end';\n totalDx: number;\n totalDy: number;\n corner?: XcGestureCorner;\n}\n\nconst delta = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && Math.abs(v) <= MAX_GESTURE_DELTA;\nconst counter = (v: unknown): v is number => typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;\n\n/** \u6821\u9A8C iframe \u53D1\u6765\u7684\u624B\u52BF\u8F7D\u8377; \u4E0D\u5408\u6CD5\u8FD4\u56DE null\u3002kind='resize' \u8FD8\u8981\u6C42\u5408\u6CD5\u7684 corner\u3002 */\nexport function parseGesturePayload(kind: 'move' | 'resize', raw: unknown): ParsedGesture | null {\n if (raw === null || typeof raw !== 'object') return null;\n const p = raw as Record<string, unknown>;\n if (!counter(p.gesture) || !counter(p.seq) || typeof p.phase !== 'string' || !PHASES.has(p.phase)) return null;\n if (!delta(p.dx) || !delta(p.dy) || !delta(p.totalDx) || !delta(p.totalDy)) return null;\n if (p.reason !== undefined && (typeof p.reason !== 'string' || !REASONS.has(p.reason))) return null;\n const out: ParsedGesture = { gesture: p.gesture, seq: p.seq, phase: p.phase as ParsedGesture['phase'], totalDx: p.totalDx, totalDy: p.totalDy };\n if (kind === 'resize') {\n if (typeof p.corner !== 'string' || !CORNERS.has(p.corner)) return null;\n out.corner = p.corner as XcGestureCorner;\n }\n return out;\n}\n\n/**\n * \u624B\u52BF\u5E8F\u53F7\u95F8\u95E8: \u53EA\u653E\u884C\"\u5408\u6CD5\u7684\u624B\u52BF\u5E8F\u5217\" \u2014\u2014 start(gesture \u6BD4\u4E0A\u4E00\u4E2A\u5927, seq=0) \u2192 move* (seq \u4E25\u683C\u9012\u589E) \u2192 end\u3002\n * \u8FDF\u5230 / \u91CD\u653E / \u4E71\u5E8F / \u6CA1\u6709 start \u7684\u6D88\u606F\u4E00\u5F8B\u62D2\u7EDD\u3002\u4E00\u4E2A\u95F8\u95E8\u5BF9\u5E94\u4E00\u79CD\u624B\u52BF (move \u6216 resize)\u3002\n */\nexport class GestureGate {\n private lastGesture = 0;\n private lastSeq = -1;\n private open = false;\n\n get active(): boolean { return this.open; }\n\n accept(p: Pick<ParsedGesture, 'gesture' | 'seq' | 'phase'>): boolean {\n if (p.phase === 'start') {\n if (p.gesture <= this.lastGesture || p.seq !== 0) return false;\n this.lastGesture = p.gesture;\n this.lastSeq = 0;\n this.open = true;\n return true;\n }\n if (!this.open || p.gesture !== this.lastGesture || p.seq <= this.lastSeq) return false;\n this.lastSeq = p.seq;\n if (p.phase === 'end') this.open = false;\n return true;\n }\n\n /** \u5BBF\u4E3B\u4E3B\u52A8\u7ED3\u675F (\u5173\u95ED\u624B\u52BF / \u9500\u6BC1): \u4E4B\u540E\u540C\u4E00\u624B\u52BF\u7684\u8FDF\u5230\u6D88\u606F\u88AB\u62D2\u7EDD\u3002 */\n close(): void { this.open = false; }\n}\n", "/**\n * client.ts \u2014 \u65E0\u6846\u67B6\u3001\u96F6\u8FD0\u884C\u65F6\u4F9D\u8D56\u7684 Project XiaoChun \u5D4C\u5165 SDK\u3002\n *\n * const xc = createXiaochun({ container: '#avatar', transparent: true });\n * await xc.ready; // \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210 (xc.loaded)\n * await xc.say('\u4F60\u597D\u5440'); // \u5FF5\u5B8C (xc.utterance end) \u624D resolve\n *\n * \u9ED8\u8BA4 lazy: \u5148\u653E\u56FA\u5B9A\u5C3A\u5BF8\u7684\u5360\u4F4D (\u4E0D\u4EA7\u751F CLS), \u6D4F\u89C8\u5668\u7A7A\u95F2 + \u8FDB\u5165\u89C6\u53E3 + (\u6216\u70B9\u51FB/\u8C03\u7528 API) \u4E4B\u540E\u624D\u521B\u5EFA iframe\u3002\n */\nimport {\n XC_DEFAULT_SRC,\n isXcEnvelope,\n isXcId,\n normalizeOrigin,\n normalizeXcUiOption,\n parseXcUiAutoHide,\n XC_UI_PARTS,\n XC_CAMERA_RANGES,\n normalizeXcCamera,\n XC_WINDOW_CORNER_RADIUS,\n xcMessage,\n type XcAudioFormat,\n type XcAudioOptions,\n type XcCamera,\n type XcConfig,\n type XcErrorCode,\n type XcExpressionPayload,\n type XcFrameMessage,\n type XcHeavyMode,\n type XcHitRegionPayload,\n type XcHostMessageType,\n type XcLang,\n type XcLangChangedPayload,\n type XcLoadProgressPayload,\n type XcMotionPayload,\n type XcOutfitChangedPayload,\n type XcOutfitInfo,\n type XcPrefetchedPayload,\n type XcReadyPayload,\n type XcSceneChangedPayload,\n type XcSceneId,\n type XcSceneInfo,\n type XcSttPayload,\n type XcStatePayload,\n type XcUiAutoHide,\n type XcUiPart,\n type XcUtterancePayload,\n} from './protocol';\nimport {\n DEFAULT_RESIZE_LIMITS, GestureGate, fitBox, moveBox, normalizeResizable, parseGesturePayload, resizeBox,\n type Box, type ResizeLimits, type Viewport, type XiaochunResizeLimits,\n} from './gesture-box';\n\nexport type { XiaochunResizeLimits } from './gesture-box';\nexport type XiaochunPosition = 'inline' | 'bottom-right' | 'bottom-left';\n/** lazy: false=\u7ACB\u5373\u521B\u5EFA; true/'idle'=\u8FDB\u5165\u89C6\u53E3\u4E14\u7A7A\u95F2\u540E\u521B\u5EFA; 'click'=\u4EC5\u70B9\u51FB\u5360\u4F4D\u6216\u8C03\u7528 API \u65F6\u521B\u5EFA\u3002 */\nexport type XiaochunLazy = boolean | 'idle' | 'click';\n\nexport interface XiaochunOptions {\n /** \u6302\u8F7D\u5BB9\u5668 (\u5143\u7D20\u6216\u9009\u62E9\u5668)\u3002 */\n container: HTMLElement | string;\n /** /embed \u9875\u9762\u5730\u5740, \u9ED8\u8BA4\u5B98\u65B9\u90E8\u7F72\u3002\u81EA\u5EFA/\u672C\u5730\u8C03\u8BD5\u65F6\u8986\u76D6\u3002 */\n src?: string;\n /** iframe \u7684 origin, \u9ED8\u8BA4\u7531 src \u63A8\u5BFC\u3002\u6240\u6709\u63E1\u624B/\u6D88\u606F\u6821\u9A8C\u90FD\u4EE5\u5B83\u4E3A\u51C6\u3002 */\n origin?: string;\n /** \u989D\u5916\u5141\u8BB8\u53D1 xc.ready \u7684 origin (\u5982 CDN \u91CD\u5B9A\u5411); \u9ED8\u8BA4\u53EA\u6709 origin\u3002\u4E0D\u652F\u6301 '*'\u3002 */\n allowedOrigins?: string[];\n lazy?: XiaochunLazy;\n /** \u8DDD\u89C6\u53E3\u591A\u5C11 px \u5185\u5C31\u5F00\u59CB\u52A0\u8F7D (IntersectionObserver rootMargin)\u3002\u8C03\u5927=\u66F4\u65E9\u52A0\u8F7D, \u66F4\u8017\u6D41\u91CF; \u8C03\u5C0F=\u66F4\u7701\u4F46\u6EDA\u5230\u65F6\u53EF\u80FD\u8FD8\u6CA1\u597D\u3002\u9ED8\u8BA4 200\u3002 */\n lazyMargin?: number;\n /** \u5360\u4F4D\u56FE URL / \u5143\u7D20; false = \u4E0D\u8981\u5360\u4F4D\u3002 */\n placeholder?: string | HTMLElement | false;\n /**\n * \u80CC\u666F\u900F\u660E (\u53E0\u5728\u5BBF\u4E3B\u9875\u4E0A)\u3002\u7B49\u4EF7\u4E8E `scene: 'transparent'`; \u540C\u65F6\u7ED9\u4E86 `scene` \u6216\u5DF2\u4FDD\u5B58\u7684\u504F\u597D\u65F6, \u4EE5\u5B83\u4EEC\u4E3A\u51C6\u3002\n * \u8FD0\u884C\u4E2D\u60F3\u5207\u6362\u8BF7\u7528 `setScene()`: SDK \u4F1A\u540C\u6B65\u5916\u58F3\u80CC\u666F\u548C\u7A7F\u900F\u3002\n */\n transparent?: boolean;\n /** \u521D\u59CB\u573A\u666F: 'light' | 'dark' | 'transparent' (\u4EE5 getScenes() \u4E3A\u51C6)\u3002\u7701\u7565 = \u8DDF\u968F transparent \u9009\u9879 / \u7CFB\u7EDF\u4EAE\u6697\u3002 */\n scene?: XcSceneId | (string & {});\n /**\n * \u56FA\u5B9A\u5C3A\u5BF8, \u6570\u5B57=px, \u5B57\u7B26\u4E32=CSS \u957F\u5EA6\u3002\u9ED8\u8BA4 600x1080 (\u5BBD\u9AD8\u6BD4 \u2248 0.556, \u4E0E\u684C\u9762\u7AEF\u7A97\u53E3\u7684\u7AD6\u7248\u6BD4\u4F8B\u540C\u4E00\u91CF\u7EA7)\u3002\n * **\u9ED8\u8BA4\u503C\u53D7\u89C6\u53E3\u9650\u5236**: \u5BBD = min(600px, \u89C6\u53E3\u5BBD) \u4E14\u5916\u58F3 max-width:100% (\u4E0D\u8D85\u8FC7\u5BB9\u5668\u5BBD), \u9AD8 = min(1080px, \u89C6\u53E3\u9AD8), \u7A84\u5C4F / \u5C0F\u7A97\u53E3\u4E0D\u4F1A\u6EA2\u51FA; \u663E\u5F0F\u7ED9\u7684\u503C\u539F\u6837\u4F7F\u7528 (\u5BBD\u4ECD\u6709 max-width:100%)\u3002\n * \u52A1\u5FC5\u7ED9\u5B9A\u6216\u63A5\u53D7\u9ED8\u8BA4\u503C, \u5426\u5219\u65E0\u6CD5\u9884\u7559\u7A7A\u95F4 (CLS)\u3002\u8FD0\u884C\u65F6\u7528 setSize() \u6539\u3002\n */\n width?: number | string;\n height?: number | string;\n position?: XiaochunPosition;\n /**\n * \u5141\u8BB8\u7528\u6237\u62D6\u52A8\u5934\u50CF, \u9ED8\u8BA4 false\u3002**\u624B\u52BF\u62D6\u52A8**: \u5728\u89D2\u8272\u4E0A\u6309\u4F4F\u5DE6\u952E\u62D6 (\u89E6\u5C4F: \u624B\u6307\u62D6) = \u79FB\u52A8\u6574\u4E2A\u5934\u50CF (\u8BC6\u522B\u5728 iframe \u91CC, \u590D\u7528 Tauri \u684C\u5BA0\u7684\u624B\u52BF\u72B6\u6001\u673A,\n * \u5BBF\u4E3B\u6267\u884C\u79FB\u52A8\u5E76\u9650\u5E45\u5728\u89C6\u53E3\u5185); \u900F\u660E + \u7A7F\u900F\u573A\u666F\u4E0B\u53EA\u6709\u70B9\u5728\u89D2\u8272\u4E0A\u624D\u63A5\u7BA1, \u5176\u4F59\u4F4D\u7F6E\u4ECD\u7A7F\u900F\u7ED9\u5BBF\u4E3B\u9875\u3002\u5185\u8054 (position: 'inline') \u7528 CSS translate \u4F4D\u79FB, \u4E0D\u6539\u53D8\u5E03\u5C40\u6D41\u3002\n * \u60AC\u6D6E\u6A21\u5F0F (bottom-right / bottom-left) \u540C\u6837\u8D70\u624B\u52BF (\u6539 left/top)\u3002\u8FD0\u884C\u4E2D\u53EF\u7528 `setDraggable()` \u5F00\u5173, \u4E0D\u91CD\u5EFA iframe\u3002\n * \u9700\u8981 /embed \u7684 capabilities.gestures (\u65E7\u7248\u6CA1\u6709 \u2192 \u624B\u52BF\u65E0\u6548, \u5E76\u89E6\u53D1\u4E00\u6B21 error{code:'unsupported'})\u3002\n */\n draggable?: boolean;\n /**\n * \u5916\u58F3\u5706\u89D2 (iframe / \u5360\u4F4D\u56FE / \u5916\u58F3\u4E00\u8D77\u88C1), \u6570\u5B57 = px, \u6216\u4EFB\u610F CSS \u957F\u5EA6\u3002\u9ED8\u8BA4: **\u975E\u900F\u660E\u573A\u666F (light / dark) = 20px** (\u4E0E Tauri \u684C\u5BA0\u7A97\u53E3\u7684\u5706\u89D2\u540C\u503C,\n * \u89C1 XC_WINDOW_CORNER_RADIUS), \u900F\u660E\u573A\u666F = 0 (\u6CA1\u6709\u5E95\u8272\u53EF\u88C1, \u89D2\u8272\u4E0D\u88AB\u88C1\u89D2)\u3002`--xc-radius` CSS \u53D8\u91CF\u4F18\u5148\u7EA7\u66F4\u9AD8\u3002\u8FD0\u884C\u4E2D\u53EF\u7528 `setBorderRadius()` \u6539, \u4E0D\u91CD\u5EFA iframe\u3002\n * \u5706\u89D2\u534A\u5F84\u662F\u56FA\u5B9A px, \u7F29\u653E (resizable) \u65F6\u4E0D\u968F\u5C3A\u5BF8\u53D8\u5F62\u3002\u4F20 0 \u6062\u590D\u65B9\u89D2\u3002\n */\n borderRadius?: number | string;\n /**\n * \u5141\u8BB8\u7528\u6237\u7F29\u653E\u5934\u50CF, \u9ED8\u8BA4 false\u3002**\u89D2\u843D\u7F29\u653E**: iframe \u56DB\u4E2A\u89D2\u5404\u6709\u4E00\u4E2A 40px \u70ED\u533A (\u60AC\u505C\u51FA\u73B0\u5706\u5F27\u63D0\u793A, \u5149\u6807\u53D8\u6210\u7F29\u653E\u7BAD\u5934), \u6309\u4F4F\u62D6\u52A8 = \u7F29\u653E, \u5BF9\u89D2\u56FA\u5B9A\u3002\n * true = \u9ED8\u8BA4\u9650\u5E45 (\u6700\u5C0F 120x180, \u6700\u5927\u53EA\u53D7\u89C6\u53E3\u9650\u5236); \u5BF9\u8C61\u53EF\u81EA\u5B9A\u4E49 minWidth / minHeight / maxWidth / maxHeight (px)\u3002\n * \u7F29\u653E\u53EA\u6539\u5916\u58F3\u5C3A\u5BF8, **\u4E0D\u91CD\u5EFA iframe**: \u6A21\u578B / \u52A8\u753B / \u5BF9\u8BDD\u72B6\u6001\u90FD\u4FDD\u6301\u3002\u901A\u8FC7 `resize` \u4E8B\u4EF6\u62FF\u5230\u65B0\u5C3A\u5BF8, `getBox()` \u968F\u65F6\u8BFB\u53D6\u3002\u8FD0\u884C\u4E2D\u53EF\u7528 `setResizable()` \u5F00\u5173\u3002\n * \u9700\u8981 capabilities.gestures (\u65E7\u7248 /embed \u65E0\u6548, \u89E6\u53D1\u4E00\u6B21 error{code:'unsupported'})\u3002\n */\n resizable?: boolean | XiaochunResizeLimits;\n /**\n * iframe \u754C\u9762\u8BED\u8A00 ('zh-CN' | 'en' | 'ja')\u3002\u663E\u5F0F\u6307\u5B9A\u65F6\u4F18\u5148\u4E8E iframe \u81EA\u5DF1\u8BB0\u4F4F\u7684\u7528\u6237\u9009\u62E9; \u4E0D\u5199 = \u7528 iframe localStorage \u91CC\u7528\u6237\u4E0A\u6B21\u5728\u8BED\u8A00\u6309\u94AE\u91CC\u9009\u7684, \u518D\u6CA1\u6709\u5C31\u8DDF\u968F\u6D4F\u89C8\u5668\u8BED\u8A00 (\u9ED8\u8BA4 zh-CN)\u3002\n * \u8FD0\u884C\u4E2D\u53EF\u7528 `setConfig({ lang })` \u6539 (\u4E0D\u6301\u4E45\u5316); \u7528\u6237\u70B9\u5185\u7F6E\u8BED\u8A00\u6309\u94AE (`ui` \u91CC\u7684 'lang') \u4F1A\u5B58\u8FDB iframe \u81EA\u5DF1\u7684 localStorage, \u5E76\u53D1 `lang-changed` \u4E8B\u4EF6\u3002\n */\n lang?: XcLang;\n /** \u521D\u59CB\u670D\u88C5: \u5185\u7F6E\u670D\u88C5 id (\u5982 'xiaochun_maid', \u89C1 getOutfits())\u3002\u672A\u77E5 id \u56DE\u9000\u9ED8\u8BA4\u670D\u88C5, \u5E76\u89E6\u53D1 error{code:'unknown_id'}\u3002 */\n outfit?: string;\n /**\n * @deprecated \u8BF7\u6539\u7528 `outfit`\u3002\u503C\u662F\u5185\u7F6E\u670D\u88C5 id \u65F6\u7B49\u4EF7\u4E8E `outfit`; https URL \u4E0D\u80FD\u518D\u901A\u8FC7\u521B\u5EFA\u9009\u9879\u4F20\u5165\n * (\u4EFB\u610F URL \u9700\u8981 `allowCustomModel: true`, \u4E4B\u540E\u7528 `setModel({ url })`)\u3002\n */\n model?: string;\n /**\n * \u5141\u8BB8 `setModel({ url })` \u52A0\u8F7D\u4EFB\u610F https .vrm/.vrmaddon/.vrmbase, \u9ED8\u8BA4 false (\u5173\u95ED)\u3002\n * \u6A21\u578B\u662F\u7B2C\u4E09\u65B9\u6587\u4EF6, \u4F1A\u5728 iframe \u91CC\u88AB\u89E3\u6790, \u53EA\u5728\u4F60\u4FE1\u4EFB\u8BE5 URL \u65F6\u6253\u5F00\u3002\u5185\u7F6E\u670D\u88C5 (`setOutfit`) \u4E0D\u53D7\u5F71\u54CD\u3002\n */\n allowCustomModel?: boolean;\n /**\n * \u504F\u597D (\u670D\u88C5 + \u573A\u666F) \u5728\u5BBF\u4E3B\u9875\u7684\u989D\u5916\u4FDD\u5B58 (\u53EF\u9009), \u9ED8\u8BA4 false\u3002\u4FDD\u5B58\u4F4D\u7F6E\u662F**\u5BBF\u4E3B\u9875**\u7684 localStorage; \u8BFB\u51FA\u6765\u540E\u4F5C\u4E3A\u663E\u5F0F\u503C\u4F20\u7ED9 iframe, \u6240\u4EE5\u4F1A\u76D6\u8FC7 iframe \u81EA\u5DF1 localStorage \u91CC\u5B58\u7684 (iframe \u672C\u6765\u5C31\u4F1A\u8BB0\u4F4F\u7528\u6237\u7684\u9009\u62E9, \u4F46\u5B83\u7684\u5B58\u50A8\u53EF\u80FD\u88AB\u6D4F\u89C8\u5668\u5206\u533A)\u3002\n * false \u4E0D\u4FDD\u5B58\n * 'host' \u4FDD\u5B58\u5230 localStorage['xiaochun:prefs']\n * \u5176\u5B83\u5B57\u7B26\u4E32 \u4FDD\u5B58\u5230 localStorage[\u8BE5\u5B57\u7B26\u4E32] (\u540C\u9875\u591A\u4E2A\u5B9E\u4F8B\u4E92\u4E0D\u8986\u76D6\u65F6\u7528)\n * \u4F18\u5148\u7EA7: \u663E\u5F0F\u7684 outfit / scene \u9009\u9879 > \u5DF2\u4FDD\u5B58\u7684\u504F\u597D > \u9ED8\u8BA4\u3002\u53EA\u6709 setOutfit / setScene \u5F15\u8D77\u7684\u53D8\u5316\u4F1A\u5199\u5165\u3002\n */\n persist?: false | 'host' | (string & {});\n /**\n * \u8BB0\u4F4F\u7528\u6237\u62D6\u52A8 / \u7F29\u653E\u540E\u7684**\u4F4D\u7F6E\u548C\u5927\u5C0F**\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4 false = \u4E0D\u8BB0\uFF09\u3002\u4FDD\u5B58\u5230**\u5BBF\u4E3B\u9875**\u7684 localStorage\uFF08\u8BFB\u5199\u90FD\u5305\u4E86 try/catch\uFF0C\u88AB\u7981\u7528 / \u914D\u989D\u6EE1\u53EA\u662F\u4E0D\u8BB0\u5FC6\uFF09\uFF0C\n * \u5728 draggable / resizable \u624B\u52BF**\u7ED3\u675F**\u65F6\u5199\u5165\uFF0C\u4E0B\u6B21\u521B\u5EFA\u65F6\u6062\u590D\u3002\n * false / \u4E0D\u5199 \u4E0D\u8BB0\n * true \u5B58\u5230 localStorage['xiaochun:box']\n * '<\u540D\u5B57>' \u5B58\u5230 localStorage['xiaochun:box:<\u540D\u5B57>']\uFF08\u540C\u4E00\u7AD9\u70B9\u591A\u4E2A\u5B9E\u4F8B / \u591A\u4E2A\u9875\u9762\u4E92\u4E0D\u8986\u76D6\u65F6\u7528\uFF1B\u4E5F\u53EF\u5F53\u7248\u672C\u53F7\uFF0C\u6539\u540D\u5373\u4E22\u5F03\u65E7\u503C\uFF09\n * \u4F18\u5148\u7EA7\uFF1A\u663E\u5F0F\u7684 width / height \u9009\u9879 > \u5DF2\u4FDD\u5B58\u7684 > \u9ED8\u8BA4\uFF08600x1080\uFF09\u3002\u4F4D\u7F6E\u6CA1\u6709\u5BF9\u5E94\u7684\u663E\u5F0F\u9009\u9879\uFF08`position` \u53EA\u662F\u9884\u8BBE\u951A\u70B9\uFF09\uFF0C\u5DF2\u4FDD\u5B58\u7684\u4F4D\u7F6E\u59CB\u7EC8\u751F\u6548\u3002\n * \u6240\u4EE5\u60F3\u8BA9\"\u7528\u6237\u7F29\u653E\u8FC7\u7684\u5927\u5C0F\"\u88AB\u6062\u590D\uFF0C\u5C31**\u4E0D\u8981**\u4F20 width / height\uFF08\u7528\u9ED8\u8BA4\u503C\uFF09\u3002\n * \u53EA\u5728\u5BF9\u5E94\u624B\u52BF\u6253\u5F00\u65F6\u6062\u590D\uFF08\u9700\u8981 draggable \u6216 resizable\uFF1B\u6CA1\u5F00\u624B\u52BF\u7684\u5B9E\u4F8B\u4E0D\u4F1A\u88AB\u65E7\u503C\u6539\u4F4D\u7F6E\uFF09\uFF1B\u4FDD\u5B58\u7684 `position` \u6A21\u5F0F\uFF08inline / bottom-right / bottom-left\uFF09\u4E0E\u5F53\u524D\u4E0D\u540C\u5219\u5FFD\u7565\u3002\n * \u6062\u590D\u65F6\u94B3\u5236\u5230**\u5F53\u524D\u89C6\u53E3**\uFF1A\u5927\u5C0F\u5939\u5728 [\u6700\u5C0F, \u89C6\u53E3]\uFF08\u6700\u5C0F = resizable \u7684 minWidth/minHeight\uFF0C\u9ED8\u8BA4 120x180\uFF09\uFF0C\u60AC\u6D6E\u6A21\u5F0F\u7684\u4F4D\u7F6E\u5939\u8FDB\u89C6\u53E3\uFF1B\n * \u5185\u8054\u6A21\u5F0F\u6A2A\u5411\u5939\u8FDB\u89C6\u53E3\u3001\u7EB5\u5411\u53EA\u4FDD\u8BC1\u4E0D\u8D8A\u8FC7\u6587\u6863\u9876\u90E8\uFF08\u5185\u8054\u76D2\u5B50\u53EF\u4EE5\u5728\u6EDA\u52A8\u7684\u9875\u9762\u91CC\uFF09\u3002\u7A97\u53E3\u4E4B\u540E\u53D8\u5C0F\u65F6\uFF0C\u65E2\u6709\u7684 resize \u76D1\u542C\u4E5F\u4F1A\u7EE7\u7EED\u628A\u5B83\u5939\u56DE\u89C6\u53E3\u3002\n * \u6E05\u9664\uFF1A`clearPersistedBox()`\uFF08\u53EA\u5220\u5B58\u50A8\uFF09\u6216 `clearPersistedBox({ reset: true })`\uFF08\u540C\u65F6\u56DE\u5230\u521D\u59CB\u4F4D\u7F6E / \u5927\u5C0F\uFF09\u3002\n */\n persistBox?: boolean | (string & {});\n /**\n * \u8981\u663E\u793A\u7684 iframe \u5185\u7F6E\u754C\u9762\u90E8\u4EF6 (\u6570\u7EC4, \u9ED8\u8BA4\u4E0D\u5199 = \u5168\u4E0D\u663E\u793A):\n * 'chat' \u5E95\u90E8\u804A\u5929\u680F (\u5BF9\u8BDD\u8D70 WebLLM, \u4F1A\u591A\u4E0B\u8F7D\u4E00\u90E8\u5206\u4EE3\u7801)\n * 'bubble' \u5934\u9876\u6C14\u6CE1 (\u8BF4\u8BDD\u6587\u672C / \u72B6\u6001)\n * 'outfit' \u6362\u88C5\u6309\u94AE } \u5916\u89C2/\u6587\u6848/\u4EA4\u4E92\u4E0E\u4E3B\u7AD9 TopHeader \u4E00\u81F4; \u70B9\u6309\u94AE\u8D70\u548C setOutfit() / setScene() \u540C\u4E00\u6761\u767D\u540D\u5355 + \u4E32\u884C (last-wins) \u8DEF\u5F84,\n * 'lang' \u8BED\u8A00\u5207\u6362\u6309\u94AE (\u4E2D\u6587 / English / \u65E5\u672C\u8A9E; \u4E0E\u4E3B\u7AD9 TopHeader \u540C\u4E00\u4E2A\u7EC4\u4EF6, \u7528\u6237\u7684\u9009\u62E9\u8BB0\u5728 iframe \u81EA\u5DF1\u7684 localStorage, \u53D1 lang-changed \u4E8B\u4EF6)\n * 'github' GitHub \u6309\u94AE (\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u9879\u76EE\u4ED3\u5E93)\n * 'scene' \u6362\u573A\u666F\u6309\u94AE } \u7167\u5E38\u89E6\u53D1 outfit-changed / scene-changed, \u5BBF\u4E3B\u7528 SDK \u6362\u88C5\u65F6\u6309\u94AE\u72B6\u6001\u540C\u6B65\u3002\u504F\u597D\u7531 iframe \u81EA\u5DF1\u7684 localStorage \u8BB0\u4F4F (\u663E\u5F0F outfit/scene \u4F18\u5148); \u60F3\u81EA\u5DF1\u5B58\u4E5F\u53EF\u7528 persist \u6216\u76D1\u542C\u4E8B\u4EF6\u3002\n * \u4F8B: `ui: ['outfit', 'scene']`\u3002\u672A\u77E5\u540D\u5B57\u5FFD\u7565\u5E76 console.warn\u3002\u521B\u5EFA\u671F\u9009\u9879: \u53D8\u5316\u4F1A\u91CD\u5EFA iframe\u3002\n * 'outfit' / 'scene' / 'lang' / 'github' \u53EA\u5BF9\u65B0\u7248 /embed \u6709\u6548 (\u65E7\u7248\u5FFD\u7565\u672A\u77E5\u90E8\u4EF6\u540D)\u3002\n * @deprecated \u5E03\u5C14\u5199\u6CD5: `ui: true` (0.1.14 \u7684\u65E7\u5199\u6CD5) \u7B49\u4EF7\u4E8E `['chat', 'bubble']` \u5E76 console.warn; \u4E0D\u8981\u518D\u7528\u3002\n */\n ui?: XcUiPart[] | boolean;\n /**\n * \u5185\u7F6E\u754C\u9762 (ui \u91CC\u7684\u6309\u94AE + \u804A\u5929\u680F chat) \u7684\u663E\u793A\u7B56\u7565, \u9ED8\u8BA4 **'transparent'**, \u4E0E Tauri \u684C\u9762\u7AEF\u9010\u5B57\u4E00\u81F4: \u53EA\u6709\u900F\u660E\u573A\u666F\u9ED8\u8BA4\u9690\u85CF, \u5355\u51FB\u89D2\u8272\u51FA\u73B0\n * (\u6309\u4F4F\u62D6\u52A8 / \u957F\u6309\u62D6\u4E0D\u7B97\u70B9\u51FB, \u6240\u4EE5\u4E0D\u4E0E `draggable` \u51B2\u7A81), \u518D\u5355\u51FB\u89D2\u8272\u6216\u5355\u51FB\u7A7A\u767D\u6536\u8D77, 10 \u79D2\u65E0\u64CD\u4F5C\u81EA\u52A8\u6536\u8D77 (\u60AC\u505C\u5728\u6309\u94AE / \u804A\u5929\u680F\u4E0A\u3001\u83DC\u5355\u6253\u5F00\u3001\u8F93\u5165\u4E2D\u4E0D\u6536); \u89E6\u5C4F\u540C\u6837\u662F\u8F7B\u70B9\u89D2\u8272\u3002\u4EAE / \u6697\u573A\u666F\u5E38\u663E\u3002\n * 'transparent' \u9ED8\u8BA4: \u53EA\u6709\u900F\u660E\u573A\u666F\u70B9\u51FB\u51FA\u73B0\n * true \u6240\u6709\u573A\u666F\u90FD\u70B9\u51FB\u51FA\u73B0 (\u4EAE / \u6697\u573A\u666F\u4E5F\u9ED8\u8BA4\u9690\u85CF)\n * false \u4E00\u76F4\u663E\u793A (0.1.15 \u53CA\u4EE5\u524D\u7684\u884C\u4E3A)\n * \u521B\u5EFA\u671F\u9009\u9879 (\u53D8\u5316\u4F1A\u91CD\u5EFA iframe); \u8FD0\u884C\u4E2D\u53EF\u7528 `setConfig({ uiAutoHide })`\u3002\u65E7\u7248 /embed (\u63E1\u624B\u91CC\u6CA1\u6709 capabilities.ui) \u5FFD\u7565\u5B83, \u754C\u9762\u5E38\u663E\u3002\n * \u6CE8\u610F: \u900F\u660E\u573A\u666F\u4E0B\u70B9\u51FB\u5BBF\u4E3B\u9875\u7684\u7A7A\u767D\u5904\u5230\u4E0D\u4E86 iframe (\u7A7F\u900F), \u6240\u4EE5\u90A3\u91CC\u53EA\u80FD\u9760 10 \u79D2\u8D85\u65F6 / \u518D\u70B9\u89D2\u8272\u6536\u8D77\u3002\n */\n uiAutoHide?: XcUiAutoHide;\n /**\n * \u76F8\u673A: `{ fov, distance, height, intro }` (\u89C1 XcCamera; \u8303\u56F4\u89C1 XC_CAMERA_RANGES: fov 15\u201360\u00B0\u3001distance 1\u201315m\u3001height \u00B11m, \u8D8A\u754C\u5939\u5230\u8FB9\u754C), \u7F3A\u7701 = \u4E0D\u8986\u76D6\u3002\n * \u521B\u5EFA\u671F\u901A\u8FC7 URL \u4F20\u7ED9 iframe (\u6A21\u578B\u52A0\u8F7D\u524D\u751F\u6548, \u9996\u6B21\u53D6\u666F / \u63A8\u955C\u5934\u76F4\u63A5\u6309\u5B83\u6765); \u8FD0\u884C\u4E2D\u7528 `setConfig({ camera })` \u6539\n * (\u7F3A\u7701\u952E\u4E0D\u53D8, null = \u6062\u590D\u9ED8\u8BA4; \u4F1A\u7ACB\u523B\u91CD\u65B0\u53D6\u666F\u5E76\u53D6\u6D88\u8FDB\u884C\u4E2D\u7684\u63A8\u955C\u5934)\u3002\u65E7\u7248 /embed (\u63E1\u624B\u91CC\u6CA1\u6709 capabilities.camera) \u5FFD\u7565\u5B83\u3002\n */\n camera?: XcCamera;\n heavy?: XcHeavyMode;\n /**\n * \u81EA\u52A8\u9884\u53D6\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB (\u4E4B\u540E setOutfit \u4E0D\u8D70\u7F51\u7EDC), \u9ED8\u8BA4 false\u3002\n * true = \u5168\u90E8\u5185\u7F6E\u670D\u88C5 **\u9664\u4E86**\u5A5A\u7EB1 (13.9MB); string[] = \u53EA\u9884\u53D6\u8FD9\u4E9B id\u3002\n * \u53EA\u5728 `heavy: 'eager'` \u65F6\u81EA\u52A8\u89E6\u53D1 (\u6A21\u578B\u9996\u6B21\u52A0\u8F7D\u5B8C\u6210\u540E\u53D1\u4E00\u6B21 xc.prefetch): \u5E76\u53D1 1, \u6392\u5728 EMAGE \u52A0\u8F7D\u4E4B\u540E, \u4E0D\u4F1A\u548C\u6362\u88C5\u62A2\u5E26\u5BBD\u3002\n * heavy \u4E3A\u9ED8\u8BA4 'lazy' \u65F6\u672C\u9009\u9879\u4E0D\u751F\u6548 \u2014\u2014 \u60F3\u6309\u9700\u9884\u53D6\u8BF7\u76F4\u63A5\u8C03\u7528 `prefetch()`\u3002\n */\n prefetch?: boolean | string[];\n /**\n * iframe \u5185\u6EDA\u8F6E\u7F29\u653E, \u9ED8\u8BA4 true (\u4E0E\u4E3B\u7AD9\u4E00\u81F4)\u3002\u900F\u660E\u573A\u666F\u53EA\u5728\u6307\u9488\u843D\u5728\u89D2\u8272\u4E0A\u65F6\u7F29\u653E, \u5176\u4F59\u4F4D\u7F6E\u6EDA\u8F6E\u7A7F\u900F\u7ED9\u5BBF\u4E3B\u9875;\n * \u4E0D\u900F\u660E\u573A\u666F\u6574\u4E2A iframe \u533A\u57DF\u7684\u6EDA\u8F6E = \u7F29\u653E (\u4F1A\u541E\u6389\u8BE5\u533A\u57DF\u7684\u9875\u9762\u6EDA\u52A8)\u3002\u4F20 false \u9501\u5B9A (URL controls=0)\u3002\n */\n controls?: boolean;\n /** \u89C6\u53E3\u5916\u81EA\u52A8 xc.pause / \u56DE\u6765 xc.resume, \u9ED8\u8BA4 true\u3002 */\n autoPause?: boolean;\n /** \u900F\u660E\u6A21\u5F0F\u4E0B\u6309\"\u662F\u5426\u70B9\u5728\u89D2\u8272\u4E0A\"\u5207\u6362 iframe \u7684 pointer-events, \u9ED8\u8BA4 = transparent\u3002 */\n passthrough?: boolean;\n /** iframe sandbox \u5C5E\u6027; false = \u4E0D\u52A0\u3002\u9ED8\u8BA4\u5141\u8BB8 scripts/same-origin/popups\u3002 */\n sandbox?: string | false;\n /** \u63E1\u624B\u8D85\u65F6 (ms), \u8D85\u65F6 emit error{code:'timeout'}\u3002\u8C03\u5927\u9002\u5408\u6162\u7F51\u7EDC, \u8C03\u5C0F\u53CD\u9988\u66F4\u5FEB\u3002\u9ED8\u8BA4 20000\u3002 */\n handshakeTimeout?: number;\n /**\n * \u7ED9 iframe \u7684 `allow` \u8FFD\u52A0 `cross-origin-isolated` (\u9ED8\u8BA4 false: allow \u4ECD\u662F 'microphone; autoplay')\u3002\n * \u4EC5\u5F53\u5BBF\u4E3B\u9875\u81EA\u5DF1\u5DF2\u8DE8\u6E90\u9694\u79BB (\u54CD\u5E94\u5934 COOP: same-origin + COEP: credentialless / require-corp) \u65F6\u624D\u751F\u6548;\n * \u5F00\u542F\u540E iframe \u5185 crossOriginIsolated=true \u2192 EMAGE \u7684 onnxruntime-web \u53EF\u7528\u591A\u7EBF\u7A0B wasm (SharedArrayBuffer)\u3002\n * \u526F\u4F5C\u7528: \u5BBF\u4E3B\u9875\u4E0A\u7684\u7B2C\u4E09\u65B9\u8D44\u6E90/iframe \u4E5F\u5FC5\u987B\u6EE1\u8DB3 COEP, \u89C1 docs/EMBED.md\u3002\u5BBF\u4E3B\u672A\u9694\u79BB\u65F6\u5F00\u4E86\u4E5F\u65E0\u5BB3 (\u6D4F\u89C8\u5668\u5FFD\u7565)\u3002\n */\n crossOriginIsolated?: boolean;\n zIndex?: number;\n}\n\n/** speakAudio / speakAudioStream \u7684\u9009\u9879\u3002 */\nexport interface XiaochunAudioOptions extends XcAudioOptions {\n /** \u7F16\u7801; \u7701\u7565 = 'encoded' (\u5BB9\u5668\u683C\u5F0F)\u3002\u4F20 ArrayBuffer \u7684\u539F\u59CB PCM \u65F6\u5FC5\u987B\u5199 'pcm16' | 'float32'\u3002 */\n format?: XcAudioFormat;\n /** MIME \u63D0\u793A (\u5982 'audio/mpeg'); Blob \u4F1A\u81EA\u52A8\u53D6 blob.type\u3002 */\n mimeType?: string;\n /** \u539F\u59CB PCM \u7684\u91C7\u6837\u7387 (8000~96000, \u6574\u6BB5\u9ED8\u8BA4 16000, \u6D41\u5F0F\u5FC5\u586B); \u5BB9\u5668\u683C\u5F0F\u5FFD\u7565\u3002 */\n sampleRate?: number;\n /** \u539F\u59CB PCM \u58F0\u9053\u6570 (\u4EA4\u9519), 1 \u6216 2\u3002 */\n channels?: 1 | 2;\n /**\n * ArrayBuffer \u662F\u5426\u7528 transferable \u96F6\u62F7\u8D1D\u53D1\u9001 (\u9ED8\u8BA4 true)\u3002\n * true: \u53D1\u51FA\u540E\u4F20\u5165\u7684\u90A3\u4E2A ArrayBuffer \u4F1A\u88AB detach (byteLength \u53D8 0), \u9002\u5408\u5927\u97F3\u9891;\n * false: \u7ED3\u6784\u5316\u514B\u9686\u4E00\u4EFD, \u539F buffer \u4ECD\u53EF\u7528, \u4F46\u591A\u4E00\u6B21\u62F7\u8D1D\u3002TypedArray \u89C6\u56FE\u603B\u662F\u62F7\u8D1D\u5176\u8303\u56F4\u540E\u518D\u8F6C\u79FB\u3002\n */\n transfer?: boolean;\n /** URL \u5B57\u7B26\u4E32\u7684\u83B7\u53D6\u4F4D\u7F6E: 'host' (\u9ED8\u8BA4) = \u5BBF\u4E3B\u9875 fetch \u540E\u8F6C\u79FB\u7ED9 iframe, \u4E0D\u9700\u8981 iframe \u80FD\u8BBF\u95EE\u8BE5 URL; 'frame' = \u628A URL \u4EA4\u7ED9 iframe fetch (\u9700 https + CORS)\u3002 */\n fetch?: 'host' | 'frame';\n /** \u89E6\u53D1\u540E\u7ACB\u5373\u6253\u65AD\u8FD9\u6B21\u8BF4\u8BDD (\u53D1 xc.audio.end{abort:true})\u3002 */\n signal?: AbortSignal;\n}\n\nexport type XiaochunAudioSource = ArrayBuffer | ArrayBufferView | Blob | string;\n\n/** \u6D41\u5F0F\u97F3\u9891\u53E5\u67C4: write \u539F\u59CB PCM \u5757, end \u6536\u5C3E, abort \u7ACB\u5373\u6253\u65AD; done \u5728\u8BF4\u8BDD\u7ED3\u675F (\u6216\u88AB\u62A2\u5360) \u65F6 resolve\u3002 */\nexport interface XiaochunAudioStream {\n write(data: Int16Array | Float32Array | ArrayBuffer): void;\n end(): void;\n abort(): void;\n readonly done: Promise<void>;\n}\n\nexport type XiaochunErrorCode = XcErrorCode | 'timeout';\nexport interface XiaochunError { code: XiaochunErrorCode; message: string; command?: string }\n\n/** `move` / `resize` \u4E8B\u4EF6\u8F7D\u8377: \u624B\u52BF\u5404\u9636\u6BB5\u5916\u58F3\u5728\u89C6\u53E3\u4E2D\u7684\u4F4D\u7F6E\u4E0E\u5C3A\u5BF8 (CSS px)\u3002 */\nexport interface XiaochunBoxEvent { phase: 'start' | 'move' | 'end'; left: number; top: number; width: number; height: number }\n\nexport interface XiaochunEvents {\n /** xc.ready \u63E1\u624B\u6210\u529F (\u534F\u8BAE\u5C42)\u3002 */\n handshake: XcReadyPayload;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210 (= xc.loaded)\u3002 */\n ready: { model: string };\n progress: XcLoadProgressPayload;\n state: XcStatePayload;\n stt: XcSttPayload;\n utterance: XcUtterancePayload;\n 'hit-region': XcHitRegionPayload;\n /** \u670D\u88C5\u5DF2\u751F\u6548 (\u542B\u9996\u6B21\u52A0\u8F7D, initial:true)\u3002\u540C\u76EE\u6807\u7684\u91CD\u590D\u8BF7\u6C42\u4E0D\u4F1A\u518D\u89E6\u53D1\u3002 */\n 'outfit-changed': XcOutfitChangedPayload;\n /** \u573A\u666F\u5DF2\u751F\u6548 (\u542B\u63E1\u624B\u540E\u4E0A\u62A5\u7684\u5F53\u524D\u573A\u666F, initial:true)\u3002 */\n 'scene-changed': XcSceneChangedPayload;\n /** iframe \u754C\u9762\u8BED\u8A00\u5DF2\u751F\u6548 (\u542B\u63E1\u624B\u540E\u4E0A\u62A5\u7684\u5F53\u524D\u8BED\u8A00, initial:true; \u7528\u6237\u70B9\u8BED\u8A00\u6309\u94AE / setConfig({ lang }) \u5F15\u8D77\u7684\u53D8\u5316)\u3002 */\n 'lang-changed': XcLangChangedPayload;\n /** \u7528\u6237\u62D6\u52A8\u5934\u50CF (draggable): start / move / end \u5404\u53D1\u4E00\u6B21, \u4F4D\u7F6E\u5DF2\u9650\u5E45\u3002 */\n move: XiaochunBoxEvent;\n /** \u7528\u6237\u7F29\u653E\u5934\u50CF (resizable): start / move / end \u5404\u53D1\u4E00\u6B21, \u5C3A\u5BF8\u5DF2\u9650\u5E45\u3002 */\n resize: XiaochunBoxEvent;\n error: XiaochunError;\n destroy: undefined;\n}\n\nexport interface XiaochunInstance {\n readonly element: HTMLElement;\n readonly iframe: HTMLIFrameElement | null;\n /** \u6A21\u578B\u52A0\u8F7D\u5B8C\u6210\u65F6 resolve; destroy \u65F6 reject\u3002 */\n readonly ready: Promise<void>;\n /** \u624B\u52A8\u521B\u5EFA iframe (lazy \u6A21\u5F0F\u4E0B\u7B49\u4EF7\u4E8E\"\u7528\u6237\u70B9\u51FB\")\u3002 */\n activate(): void;\n say(text: string, opts?: { mode?: 'speak' | 'chat' }): Promise<void>;\n /**\n * \u76F4\u63A5\u64AD\u653E\u5BBF\u4E3B\u7ED9\u7684\u97F3\u9891 (\u4E0D\u7ECF\u8FC7 TTS): iframe \u5185\u89E3\u7801 \u2192 EMAGE \u751F\u6210\u52A8\u4F5C + \u53E3\u578B, \u5FF5\u5B8C (xc.utterance end) \u624D resolve\u3002\n * \u9996\u6B21\u8C03\u7528\u624D\u52A0\u8F7D EMAGE \u6A21\u578B (\u9996\u6B21\u4F1A\u6162); opts.motion=false \u5219\u53EA\u64AD\u653E\u4E0D\u52A0\u8F7D\u3002\n */\n speakAudio(source: XiaochunAudioSource, opts?: XiaochunAudioOptions): Promise<void>;\n /** \u6D41\u5F0F\u97F3\u9891 (\u539F\u59CB PCM \u5206\u5757)\u3002sampleRate \u5FC5\u586B; \u9996\u4E2A write \u5F00\u542F\u8BF4\u8BDD\u3002 */\n speakAudioStream(opts: XiaochunAudioOptions & { sampleRate: number }): XiaochunAudioStream;\n motion(m: XcMotionPayload | string): Promise<void>;\n expression(name: XcExpressionPayload['name']): Promise<void>;\n /** TODO: \u534F\u8BAE\u5DF2\u9884\u7559, /embed \u6682\u672A\u5B9E\u73B0 \u2192 \u4F1A\u6536\u5230 error{code:'unsupported'}\u3002 */\n lookAt(x: number, y: number): Promise<void>;\n /**\n * \u6362\u5185\u7F6E\u670D\u88C5 (id \u89C1 getOutfits())\u3002Promise \u5728\u670D\u88C5**\u751F\u6548\u540E** resolve (xc.outfit-changed)\u3002\n * \u5E76\u53D1\u89C4\u5219: \u4E32\u884C + last-wins \u2014\u2014 \u52A0\u8F7D\u4E2D\u518D\u6B21\u8C03\u7528\u4F1A\u6392\u961F, \u6392\u961F\u7684\u65E7\u8BF7\u6C42\u88AB\u66F4\u65B0\u7684\u9876\u6389\u65F6 reject `[busy]` (\u53EF\u5FFD\u7565, \u4EE5\u6700\u65B0\u4E00\u6B21\u4E3A\u51C6);\n * \u8BF4\u8BDD\u4E0D\u4F1A\u88AB\u6253\u65AD, \u6362\u88C5\u5728\u540E\u53F0\u5B8C\u6210\u540E\u624D\u751F\u6548\u3002\u76EE\u6807\u5DF2\u662F\u5F53\u524D\u670D\u88C5\u5219\u76F4\u63A5 resolve\u3002\n * \u65E7\u7248 /embed (\u63E1\u624B\u91CC\u6CA1\u6709 capabilities.outfits) \u4F1A reject `[unsupported]`\u3002\n */\n setOutfit(id: string): Promise<void>;\n /** \u5207\u573A\u666F ('light' | 'dark' | 'transparent', \u89C1 getScenes())\u3002SDK \u540C\u6B65\u5916\u58F3\u80CC\u666F\u3001\u7A7F\u900F\u5F00\u5173\u4E0E pointer-events\u3002 */\n setScene(id: XcSceneId | (string & {})): Promise<void>;\n /**\n * \u9884\u53D6\u5185\u7F6E\u670D\u88C5\u8D44\u6E90\u5230 iframe \u7684 IndexedDB (\u53EA\u4E0B\u8F7D, \u4E0D\u89E3\u538B\u4E0D\u5408\u6210)\u3002ids \u7701\u7565 = \u5168\u90E8\u5185\u7F6E\u670D\u88C5, \u5A5A\u7EB1 (13.9MB) \u9664\u5916; \u663E\u5F0F\u70B9\u540D\u5219\u7167\u505A\u3002\n * \u5168\u5C40\u4E32\u884C (\u5E76\u53D1 1); resolve \u7684\u7ED3\u679C\u91CC failed \u975E\u7A7A\u65F6\u53EF\u7A0D\u540E\u91CD\u8BD5\u3002\u8FDB\u5EA6\u89C1 progress \u4E8B\u4EF6 (payload.phase === 'prefetch')\u3002\n * \u65E7\u7248 /embed reject `[unsupported]`; \u7528\u6237\u5F00\u4E86\u7701\u6D41\u91CF\u6A21\u5F0F\u65F6 resolve \u4E14 skipped:'save-data'\u3002\n */\n prefetch(ids?: string[]): Promise<XcPrefetchedPayload>;\n /** \u63E1\u624B\u540E\u8FD4\u56DE\u53EF\u6362\u7684\u5185\u7F6E\u670D\u88C5 (\u4E0D\u542B\u88F8\u6A21); \u65E7\u7248 /embed \u8FD4\u56DE []\u3002\u4F1A\u89E6\u53D1 iframe \u521B\u5EFA (lazy \u6A21\u5F0F)\u3002 */\n getOutfits(): Promise<XcOutfitInfo[]>;\n /** \u63E1\u624B\u540E\u8FD4\u56DE\u53EF\u5207\u7684\u573A\u666F; \u65E7\u7248 /embed \u8FD4\u56DE []\u3002 */\n getScenes(): Promise<XcSceneInfo[]>;\n /** \u6700\u8FD1\u4E00\u6B21 xc.outfit-changed \u7684\u670D\u88C5 id (\u81EA\u5B9A\u4E49 URL \u6A21\u578B / \u5C1A\u672A\u52A0\u8F7D = null)\u3002 */\n readonly outfit: string | null;\n /** \u6700\u8FD1\u4E00\u6B21 xc.scene-changed \u7684\u573A\u666F id (\u63E1\u624B\u524D = null)\u3002 */\n readonly scene: string | null;\n /**\n * \u65E7\u547D\u4EE4, \u4FDD\u7559\u517C\u5BB9\u3002\u5185\u7F6E\u670D\u88C5\u8BF7\u6539\u7528 `setOutfit` (\u5E76\u53D1\u66F4\u7A33\u3001\u80FD\u62FF\u5230\u5B8C\u6210\u901A\u77E5)\u3002\n * `{ url }` \u9ED8\u8BA4\u88AB\u62D2\u7EDD (reject `[unsupported]`), \u9700\u521B\u5EFA\u9009\u9879 `allowCustomModel: true`\u3002\n */\n setModel(m: string | { url?: string; outfit?: string; name?: string }): Promise<void>;\n setConfig(cfg: XcConfig): Promise<void>;\n /** \u8FD0\u884C\u65F6\u8BBE\u7F6E\u5916\u58F3\u5C3A\u5BF8 (\u6570\u5B57 = px, \u5B57\u7B26\u4E32 = CSS \u957F\u5EA6, undefined = \u6062\u590D\u9ED8\u8BA4 600x1080 (\u53D7\u89C6\u53E3\u9650\u5236)); \u4E0D\u91CD\u5EFA iframe\u3002\u7528\u6237\u7F29\u653E\u540E\u5BBF\u4E3B\u8981\u540C\u6B65\u81EA\u5DF1\u7684\u72B6\u6001\u65F6\u7528 `resize` \u4E8B\u4EF6\u3002 */\n setSize(width: number | string | undefined, height: number | string | undefined): void;\n /** \u5916\u58F3\u5F53\u524D\u5728\u89C6\u53E3\u4E2D\u7684\u4F4D\u7F6E\u4E0E\u5C3A\u5BF8 (CSS px)\u3002 */\n getBox(): { left: number; top: number; width: number; height: number };\n /** \u6E05\u9664 `persistBox` \u4FDD\u5B58\u7684\u4F4D\u7F6E / \u5927\u5C0F\uFF08\u6CA1\u5F00 persistBox \u65F6\u662F\u7A7A\u64CD\u4F5C\uFF09\u3002`reset: true` \u53E6\u5916\u628A\u5F53\u524D\u76D2\u5B50\u8FD8\u539F\u5230\u521D\u59CB\u4F4D\u7F6E\u548C\u5927\u5C0F\uFF08\u6309 width / height \u9009\u9879\u6216\u9ED8\u8BA4\u503C\uFF0C\u4E0D\u91CD\u5EFA iframe\uFF09\u3002 */\n clearPersistedBox(opts?: { reset?: boolean }): void;\n /** \u8FD0\u884C\u65F6\u5F00\u5173\u624B\u52BF\u62D6\u52A8 (\u7B49\u4EF7\u4E8E `draggable` \u9009\u9879), \u4E0D\u91CD\u5EFA iframe\u3002 */\n /** \u6539\u5916\u58F3\u5706\u89D2 (\u6570\u5B57 px / CSS \u957F\u5EA6); \u4F20 undefined \u6062\u590D\u9ED8\u8BA4 (\u975E\u900F\u660E 20px / \u900F\u660E 0)\u3002 */\n setBorderRadius(radius: number | string | undefined): void;\n setDraggable(on: boolean): void;\n /** \u8FD0\u884C\u65F6\u5F00\u5173 / \u8C03\u6574\u89D2\u843D\u7F29\u653E (\u7B49\u4EF7\u4E8E `resizable` \u9009\u9879), \u4E0D\u91CD\u5EFA iframe\u3002false = \u5173\u3002 */\n setResizable(on: boolean | XiaochunResizeLimits): void;\n startListening(): Promise<void>;\n stopListening(): Promise<void>;\n mic(enabled: boolean): Promise<void>;\n pause(): void;\n resume(): void;\n destroy(): void;\n on<K extends keyof XiaochunEvents>(event: K, cb: (payload: XiaochunEvents[K]) => void): () => void;\n}\n\nconst FALLBACK_PLACEHOLDER =\n 'data:image/svg+xml;utf8,' +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 120 180\"><defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#f6b8ae\"/><stop offset=\"1\" stop-color=\"#ea8377\"/></linearGradient></defs><ellipse cx=\"60\" cy=\"170\" rx=\"34\" ry=\"6\" fill=\"#000\" opacity=\".12\"/><circle cx=\"60\" cy=\"48\" r=\"26\" fill=\"url(#g)\" opacity=\".75\"/><path d=\"M26 160c2-40 18-62 34-62s32 22 34 62z\" fill=\"url(#g)\" opacity=\".6\"/></svg>',\n );\n\n/**\n * \u4E0D\u8BA9\u5934\u50CF\u88AB\u5BBF\u4E3B\u9875\u7684\u6587\u5B57\u9009\u533A\u9009\u4E2D: Chrome \u5728\u9009\u533A\u8DE8\u8FC7 iframe (\u62D6\u9009\u5212\u8FC7 / Cmd\u00B7Ctrl+A / \u5168\u9009) \u65F6\u4F1A\u7ED9\u6574\u5757 iframe \u76D6\u4E00\u5C42\u84DD\u8272\u9AD8\u4EAE\n * (\u5B9E\u6D4B Chrome \u7684 iframe \u4F1A\u88AB\u67D3\u8272; \u7ED9 iframe \u81EA\u8EAB\u8BBE user-select:none \u5373\u53EF\u6D88\u9664, \u5BBF\u4E3B\u9875\u81EA\u5DF1\u7684\u6587\u5B57\u4ECD\u7167\u5E38\u88AB\u9009\u4E2D)\u3002\n * \u53EA\u7528 CSSOM \u5185\u8054\u6837\u5F0F (\u4E0D\u6CE8\u5165 <style>), \u4E0D\u53D7\u5BBF\u4E3B CSP style-src \u5F71\u54CD, \u4E5F\u4E0D\u5F71\u54CD pointer-events / \u900F\u660E\u7A7F\u900F\u3002\n */\nconst noSelect = (st: CSSStyleDeclaration) => {\n st.setProperty('user-select', 'none');\n st.setProperty('-webkit-user-select', 'none');\n st.setProperty('-webkit-touch-callout', 'none');\n st.setProperty('-webkit-tap-highlight-color', 'transparent');\n};\n\nconst css = (v: number | string | undefined, d: string) =>\n v === undefined ? d : typeof v === 'number' ? `${v}px` : v;\n\n/** \u9ED8\u8BA4\u5C3A\u5BF8 (px): 600x1080\u3002\u53EA\u5728\u6CA1\u663E\u5F0F\u4F20 width / height \u65F6\u4F7F\u7528, \u5E76\u53D7\u89C6\u53E3\u9650\u5236 (\u89C1 defaultWidthCss / defaultHeightCss)\u3002 */\nexport const XC_DEFAULT_WIDTH = 600;\nexport const XC_DEFAULT_HEIGHT = 1080;\n/**\n * \u9ED8\u8BA4\u5BBD: 600px \u4F46\u4E0D\u8D85\u8FC7\u89C6\u53E3\u5BBD (min(600px, 100vw))\u3002\u4E0D\u7528 min(600px, 100%): \u767E\u5206\u6BD4\u5728 \"\u6309\u5185\u5BB9\u6536\u7F29\" \u7684\u5BB9\u5668 (inline-block / \u7EDD\u5BF9\u5B9A\u4F4D / <xiaochun-avatar> \u7684 :host)\n * \u91CC\u4F1A\u5FAA\u73AF\u4F9D\u8D56\u800C\u584C\u6210 0\u3002\u6BD4\u89C6\u53E3\u66F4\u7A84\u7684\u5BB9\u5668 (\u5982 300px \u7684\u4FA7\u680F) \u7531\u5916\u58F3\u7684 max-width:100% \u518D\u94B3\u4E00\u6B21, \u6240\u4EE5\u7A84\u5C4F / \u7A84\u5BB9\u5668\u90FD\u4E0D\u4F1A\u6EA2\u51FA\u3002\n */\nexport const defaultWidthCss = (floating = false): string =>\n floating ? `min(${XC_DEFAULT_WIDTH}px, calc(100vw - 2 * var(--xc-offset-x, 16px)))` : `min(${XC_DEFAULT_WIDTH}px, 100vw)`;\n/**\n * \u9ED8\u8BA4\u9AD8: 1080px \u4F46\u4E0D\u8D85\u8FC7\u89C6\u53E3\u9AD8 (\u5C0F\u7A97\u53E3 / \u624B\u673A\u6A2A\u5C4F\u94B3\u5236)\u3002\u6D4F\u89C8\u5668\u652F\u6301\u65F6\u7528 svh (\u79FB\u52A8\u7AEF\u5730\u5740\u680F\u4F38\u7F29\u65F6\u4E5F\u4E0D\u6EA2\u51FA), \u5426\u5219 vh\u3002\n * SSR \u4E0B (\u6CA1\u6709 CSS.supports) \u4E00\u5F8B vh, \u4E0E React \u670D\u52A1\u7AEF\u6E32\u67D3\u7684\u9996\u5E27\u4FDD\u6301\u4E00\u81F4\u3002\n */\nexport const defaultHeightCss = (floating = false): string => {\n const unit = typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('height', '1svh') ? 'svh' : 'vh';\n // \u60AC\u6D6E (position\u2260inline) \u8D34\u7740\u5C4F\u5E55\u8FB9 + \u8FB9\u8DDD (--xc-offset-*), \u9ED8\u8BA4\u503C\u8981\u628A\u4E24\u4FA7\u8FB9\u8DDD\u6263\u6389, \u5426\u5219\u6574\u5757\u4F1A\u9876\u51FA\u5C4F\u5E55\n return floating ? `min(${XC_DEFAULT_HEIGHT}px, calc(100${unit} - 2 * var(--xc-offset-y, 16px)))` : `min(${XC_DEFAULT_HEIGHT}px, 100${unit})`;\n};\n\nexport function createXiaochun(options: XiaochunOptions): XiaochunInstance {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n throw new Error('[project-xiaochun] createXiaochun must run in a browser');\n }\n const container =\n typeof options.container === 'string' ? document.querySelector<HTMLElement>(options.container) : options.container;\n if (!container) throw new Error(`[project-xiaochun] container not found: ${String(options.container)}`);\n\n // \u2500\u2500 \u5730\u5740 / origin \u2500\u2500\n const src = options.src ?? XC_DEFAULT_SRC;\n let srcUrl: URL;\n try { srcUrl = new URL(src, window.location.href); } catch { throw new Error(`[project-xiaochun] invalid src: ${src}`); }\n const frameOrigin = normalizeOrigin(options.origin ?? srcUrl.origin);\n if (!frameOrigin) throw new Error('[project-xiaochun] invalid origin (wildcards are not allowed)');\n const trusted = new Set<string>([frameOrigin]);\n for (const o of options.allowedOrigins ?? []) {\n const n = normalizeOrigin(o);\n if (!n) throw new Error(`[project-xiaochun] invalid allowedOrigins entry: ${o} (wildcards are not allowed)`);\n trusted.add(n);\n }\n\n // \u2500\u2500 \u504F\u597D (persist, \u53EF\u9009): \u5BBF\u4E3B localStorage; iframe \u53E6\u6709\u81EA\u5DF1\u7684\u5B58\u50A8 \u2500\u2500\n const prefsKey = options.persist === 'host' ? 'xiaochun:prefs' : typeof options.persist === 'string' && options.persist ? options.persist : null;\n type Prefs = { outfit?: string; scene?: string };\n const readPrefs = (): Prefs => {\n if (!prefsKey) return {};\n try {\n const raw = JSON.parse(window.localStorage.getItem(prefsKey) ?? 'null') as Record<string, unknown> | null;\n const out: Prefs = {};\n if (raw && typeof raw === 'object') {\n if (isXcId(raw.outfit)) out.outfit = raw.outfit;\n if (isXcId(raw.scene)) out.scene = raw.scene;\n }\n return out;\n } catch { return {}; }\n };\n const writePrefs = (patch: { [K in keyof Prefs]?: string | null }) => {\n if (!prefsKey) return;\n try {\n const next: Record<string, string> = { ...readPrefs() };\n for (const [k, v] of Object.entries(patch)) { if (v) next[k] = v; else delete next[k]; }\n window.localStorage.setItem(prefsKey, JSON.stringify(next));\n } catch { /* localStorage \u4E0D\u53EF\u7528 (\u9690\u79C1\u6A21\u5F0F / \u914D\u989D): \u9759\u9ED8\u653E\u5F03\u4FDD\u5B58 */ }\n };\n const prefs = readPrefs();\n\n if (options.model !== undefined && options.outfit === undefined) {\n console.warn('[project-xiaochun] option \"model\" is deprecated, use \"outfit\" (built-in outfit id).');\n }\n // ui: \u90E8\u4EF6\u540D\u6570\u7EC4 (\u767D\u540D\u5355); \u5E03\u5C14 true \u662F\u5F03\u7528\u7684\u65E7\u5199\u6CD5 (= chat + bubble)\n const uiParse = normalizeXcUiOption(options.ui);\n const uiParts = uiParse.parts;\n // uiAutoHide: \u7F3A\u7701 = \u4E0D\u5199\u8FDB URL (iframe \u7528\u81EA\u5DF1\u7684\u9ED8\u8BA4 true); \u975E\u6CD5\u503C console.warn \u5E76\u5FFD\u7565\n const uiAutoHide = parseXcUiAutoHide(options.uiAutoHide);\n if (options.uiAutoHide !== undefined && uiAutoHide === undefined) console.warn(`[project-xiaochun] ignoring invalid uiAutoHide: ${String(options.uiAutoHide)} (use true | false | 'transparent')`);\n // camera: \u975E\u6CD5 \u2192 console.warn \u5E76\u6574\u4F53\u5FFD\u7565; \u8D8A\u754C \u2192 \u5939\u5230\u8303\u56F4\u5E76 warn; null / undefined \u9879\u4E0D\u5199\u8FDB URL\n let camera: XcCamera = {};\n if (options.camera !== undefined) {\n const r = normalizeXcCamera(options.camera);\n if (r.ok) {\n camera = r.camera;\n if (r.clamped.length) console.warn(`[project-xiaochun] camera.${r.clamped.join(', camera.')} out of range, clamped (fov ${XC_CAMERA_RANGES.fov.join('\u2013')}, distance ${XC_CAMERA_RANGES.distance.join('\u2013')}, height ${XC_CAMERA_RANGES.height.join('\u2013')})`);\n } else console.warn(`[project-xiaochun] ignoring invalid camera option: ${r.error}`);\n }\n if (uiParse.legacy) console.warn('[project-xiaochun] option \"ui: true\" is deprecated, use an array of parts, e.g. ui: [\\'chat\\', \\'bubble\\', \\'outfit\\', \\'scene\\'].');\n if (uiParse.unknown.length) console.warn(`[project-xiaochun] ignoring unknown ui part(s): ${uiParse.unknown.join(', ')} (known: ${XC_UI_PARTS.join(', ')})`);\n const outfitOpt = options.outfit ?? (isXcId(options.model) ? options.model : undefined);\n const initialOutfit = outfitOpt ?? prefs.outfit;\n const initialScene = options.scene ?? prefs.scene ?? (options.transparent ? 'transparent' : undefined);\n // \u573A\u666F\u540D\u672A\u77E5 (\u65E7\u7248/\u81EA\u5B9A\u4E49\u90E8\u7F72) \u65F6\u9000\u56DE transparent \u9009\u9879; \u63E1\u624B\u540E\u7684 xc.scene-changed \u4F1A\u6821\u6B63\n let transparent = initialScene === 'transparent' || (initialScene !== 'light' && initialScene !== 'dark' && (options.transparent ?? false));\n let passthrough = options.passthrough ?? transparent;\n const lazy: XiaochunLazy = options.lazy ?? true;\n const position = options.position ?? 'inline';\n const handshakeTimeout = options.handshakeTimeout ?? 20_000;\n\n // \u2500\u2500 DOM: wrapper (\u56FA\u5B9A\u5C3A\u5BF8, \u9632 CLS) \u2500\u2500\n const wrapper = document.createElement('div');\n wrapper.setAttribute('data-xiaochun', '');\n const ws = wrapper.style;\n ws.position = position === 'inline' ? 'relative' : 'fixed';\n ws.width = css(options.width, defaultWidthCss(position !== 'inline'));\n ws.height = css(options.height, defaultHeightCss(position !== 'inline'));\n ws.maxWidth = '100%';\n ws.overflow = 'visible';\n ws.contain = 'layout style';\n noSelect(ws); // \u5BBF\u4E3B\u9875\u7684\u6587\u5B57\u9009\u533A (\u62D6\u9009\u5212\u8FC7 / Cmd+A) \u4E0D\u4F1A\u628A\u5934\u50CF\u67D3\u6210\u84DD\u8272, \u89C1 noSelect\n // \u2500\u2500 \u6837\u5F0F hook: \u5BBF\u4E3B\u7528 CSS \u81EA\u5B9A\u4E49\u5C5E\u6027\u63A7\u5236\u5916\u89C2 (\u81EA\u5B9A\u4E49\u5C5E\u6027\u4F1A\u7A7F\u900F Shadow DOM, \u5728\u5BB9\u5668\u6216\u4EFB\u610F\u7956\u5148\u4E0A\u8BBE\u7F6E\u5373\u53EF) \u2500\u2500\n // \u6CE8\u610F: \u53EA\u80FD\u5F71\u54CD iframe \u7684\u300C\u5916\u58F3\u300D(\u5706\u89D2/\u9634\u5F71/\u4F4D\u7F6E/\u5C42\u7EA7/\u80CC\u666F); iframe \u5185\u90E8 (\u89D2\u8272\u6E32\u67D3\u3001\u6C14\u6CE1) \u662F\u8DE8\u57DF\u6587\u6863, \u5BBF\u4E3B CSS \u78B0\u4E0D\u5230\u3002\n // --xc-radius \u5706\u89D2, CSS \u957F\u5EA6, \u9ED8\u8BA4 0\u3002\u8303\u56F4 0 ~ \u5BBD\u5EA6\u7684\u4E00\u534A (50% = \u5706\u5F62\u5934\u50CF\u6846)\u3002\u8C03\u5927 = \u66F4\u5706; \u8FC7\u5927\u4F1A\u88C1\u6389\u89D2\u8272\u7684\u5934/\u811A\u3002\n // --xc-shadow box-shadow \u7B80\u5199, \u9ED8\u8BA4 none\u3002\u900F\u660E\u60AC\u6D6E\u5934\u50CF\u5EFA\u8BAE\u4FDD\u6301 none (\u5426\u5219\u4F1A\u51FA\u73B0\u4E00\u4E2A\u65B9\u5757\u9634\u5F71); \u5361\u7247\u5F0F\u5D4C\u5165\u53EF\u7528 '0 8px 24px rgba(0,0,0,.18)'\u3002\n // --xc-z-index \u4EC5\u60AC\u6D6E (position\u2260inline) \u751F\u6548, \u9ED8\u8BA4 2147483000 (\u63A5\u8FD1 int \u4E0A\u9650, \u76D6\u4F4F\u7EDD\u5927\u591A\u6570\u9875\u9762\u5143\u7D20)\u3002\u8C03\u5C0F = \u8BA9\u5BBF\u4E3B\u7684\u5F39\u7A97/\u5BFC\u822A\u76D6\u5728\u5934\u50CF\u4E0A\u9762\u3002\n // --xc-offset-x \u4EC5\u60AC\u6D6E: \u8DDD\u5C4F\u5E55\u5DE6/\u53F3\u8FB9\u7684\u8FB9\u8DDD, \u9ED8\u8BA4 16px\u3002\u8C03\u5927 = \u79BB\u8FB9\u7F18\u66F4\u8FDC (\u79FB\u52A8\u7AEF\u6CE8\u610F\u907F\u5F00\u7CFB\u7EDF\u624B\u52BF\u533A, \u5EFA\u8BAE \u2265 12px)\u3002\n // --xc-offset-y \u4EC5\u60AC\u6D6E: \u8DDD\u5C4F\u5E55\u5E95\u8FB9\u7684\u8FB9\u8DDD, \u9ED8\u8BA4 16px\u3002\u8C03\u5927 = \u62AC\u9AD8 (\u907F\u5F00\u5E95\u90E8\u5BFC\u822A\u680F/Cookie \u6A2A\u5E45)\u3002\n // --xc-bg \u975E\u900F\u660E\u6A21\u5F0F\u4E0B iframe \u52A0\u8F7D\u524D/\u5706\u89D2\u5916\u7684\u5E95\u8272, \u9ED8\u8BA4 transparent\u3002transparent: true \u65F6\u5FFD\u7565\u3002\n ws.boxShadow = 'var(--xc-shadow, none)';\n const applyWrapperBg = () => { ws.background = transparent ? '' : 'var(--xc-bg, transparent)'; };\n applyWrapperBg();\n // \u5706\u89D2: \u9009\u9879 > (\u975E\u900F\u660E 20px / \u900F\u660E 0); \u5BBF\u4E3B\u7684 --xc-radius CSS \u53D8\u91CF\u59CB\u7EC8\u4F18\u5148\n let radiusOpt: number | string | undefined = options.borderRadius;\n const radiusValue = () => (radiusOpt !== undefined ? css(radiusOpt, '0px') : transparent ? '0px' : `${XC_WINDOW_CORNER_RADIUS}px`);\n const applyRadius = () => {\n const v = `var(--xc-radius, ${radiusValue()})`;\n ws.borderRadius = v;\n if (placeholderEl) placeholderEl.style.borderRadius = v;\n if (iframe) iframe.style.borderRadius = v;\n };\n ws.borderRadius = `var(--xc-radius, ${radiusValue()})`;\n if (position === 'bottom-right') { ws.right = 'var(--xc-offset-x, 16px)'; ws.bottom = 'var(--xc-offset-y, 16px)'; }\n if (position === 'bottom-left') { ws.left = 'var(--xc-offset-x, 16px)'; ws.bottom = 'var(--xc-offset-y, 16px)'; }\n if (position !== 'inline') ws.zIndex = `var(--xc-z-index, ${options.zIndex ?? 2147483000})`;\n ws.pointerEvents = 'none'; // \u5BB9\u5668\u672C\u8EAB\u4E0D\u5403\u4E8B\u4EF6; \u5360\u4F4D/iframe \u5404\u81EA\u5F00\n wrapper.setAttribute('part', 'wrapper'); // ::part(wrapper) (\u4EC5 <xiaochun-avatar> \u7684 Shadow DOM \u5185\u6709\u610F\u4E49)\n container.appendChild(wrapper);\n\n let placeholderEl: HTMLElement | null = null;\n if (options.placeholder !== false) {\n if (options.placeholder instanceof HTMLElement) placeholderEl = options.placeholder;\n else {\n const img = document.createElement('img');\n img.src = options.placeholder || FALLBACK_PLACEHOLDER;\n img.alt = 'Project XiaoChun';\n img.decoding = 'async';\n img.width = XC_DEFAULT_WIDTH; img.height = XC_DEFAULT_HEIGHT; // \u6709 width/height \u5C5E\u6027 + \u4E0B\u9762\u7684 100% \u6837\u5F0F, \u89E3\u7801\u524D\u4E5F\u4E0D\u6296\u52A8\n placeholderEl = img;\n }\n const ps = placeholderEl.style;\n placeholderEl.setAttribute('part', 'placeholder');\n ps.borderRadius = `var(--xc-radius, ${radiusValue()})`;\n ps.position = 'absolute'; ps.inset = '0'; ps.width = '100%'; ps.height = '100%';\n ps.objectFit = 'contain'; ps.transition = 'opacity .25s ease'; ps.pointerEvents = 'auto';\n ps.cursor = lazy === false ? 'default' : 'pointer';\n noSelect(ps); // \u5360\u4F4D\u56FE (<img>) \u540C\u6837\u4F1A\u88AB\u9009\u533A\u67D3\u84DD\n placeholderEl.addEventListener('click', () => activate());\n wrapper.appendChild(placeholderEl);\n }\n\n // \u2500\u2500 \u4E8B\u4EF6 \u2500\u2500\n const listeners = new Map<string, Set<(p: any) => void>>();\n const emit = <K extends keyof XiaochunEvents>(ev: K, payload: XiaochunEvents[K]) => {\n listeners.get(ev)?.forEach((cb) => { try { cb(payload); } catch (e) { console.error('[project-xiaochun] listener error', e); } });\n };\n\n // \u2500\u2500 ready promise \u2500\u2500\n let resolveReady!: () => void;\n let rejectReady!: (e: Error) => void;\n const ready = new Promise<void>((res, rej) => { resolveReady = res; rejectReady = rej; });\n ready.catch(() => {}); // \u907F\u514D\u6CA1\u4EBA await \u65F6\u7684 unhandled rejection\n\n // \u2500\u2500 \u72B6\u6001 \u2500\u2500\n let iframe: HTMLIFrameElement | null = null;\n let port: MessagePort | null = null;\n let destroyed = false;\n let userPaused = false;\n let autoPaused = false;\n let loaded = false;\n let lastHit = false;\n let caps: XcReadyPayload['capabilities'] | null = null;\n let currentOutfit: string | null = null;\n let currentScene: string | null = null;\n /** \u547D\u4EE4\u4F9D\u8D56\u7684 capabilities \u5B57\u6BB5; \u63E1\u624B\u540E\u82E5 iframe \u6CA1\u6709 (\u65E7\u7248 /embed) \u5C31\u672C\u5730 reject, \u4E0D\u53D1\u51FA\u53BB\u3002 */\n type CapKey = 'outfits' | 'scenes' | 'prefetch';\n const queue: Array<{ type: XcHostMessageType; payload?: unknown; id?: string; transfer?: Transferable[]; requires?: CapKey }> = [];\n const pending = new Map<string, { resolve: (v?: unknown) => void; reject: (e: Error) => void; sawEnd: boolean }>();\n let idSeq = 0;\n let handshakeTimer: ReturnType<typeof setTimeout> | null = null;\n let io: IntersectionObserver | null = null;\n let idleHandle: number | null = null;\n let resolveHandshake!: () => void;\n const handshaked = new Promise<void>((res) => { resolveHandshake = res; });\n\n /** \u672C\u5730\u62D2\u7EDD\u4E00\u6761\u547D\u4EE4 (iframe \u4E0D\u652F\u6301): reject \u5BF9\u5E94 Promise + \u89E6\u53D1 error \u4E8B\u4EF6\u3002 */\n const failLocal = (type: XcHostMessageType, id: string | undefined, code: XiaochunErrorCode, message: string) => {\n emit('error', { code, message, command: type });\n const p = id ? pending.get(id) : undefined;\n if (p && id) { pending.delete(id); p.reject(new Error(`[${code}] ${message}`)); }\n };\n const unsupportedByFrame = (type: XcHostMessageType, id: string | undefined) =>\n failLocal(type, id, 'unsupported', `${type} is not supported by this /embed deployment (older version; its xc.ready has no capabilities for it)`);\n\n const postToFrame = (type: XcHostMessageType, payload?: unknown, id?: string, transfer?: Transferable[], requires?: CapKey) => {\n if (!port) { queue.push({ type, payload, id, transfer, requires }); return; }\n if (requires && !caps?.[requires]) { unsupportedByFrame(type, id); return; }\n port.postMessage(xcMessage(type, payload, id), transfer ?? []);\n };\n\n const send = (type: XcHostMessageType, payload?: unknown, wait = false, transfer?: Transferable[], fixedId?: string, requires?: CapKey): Promise<any> => {\n if (destroyed) return Promise.reject(new Error('[project-xiaochun] instance destroyed'));\n if (!iframe) activate(); // \u4EFB\u4F55\u4EA4\u4E92 API \u90FD\u89C6\u4E3A\"\u7528\u6237\u610F\u56FE\", \u7ACB\u5373\u521B\u5EFA\n const id = fixedId ?? `c${++idSeq}`;\n // \u547D\u4EE4\u5E94\u7B54\u53EF\u4EE5\u5E26\u4E00\u4E2A\u503C (\u5982 xc.prefetched \u7684\u7ED3\u679C); \u5176\u5B83\u547D\u4EE4 resolve(undefined)\n const p: Promise<any> = wait\n ? new Promise<any>((resolve, reject) => pending.set(id, { resolve, reject, sawEnd: false }))\n : Promise.resolve();\n postToFrame(type, payload, id, transfer, requires);\n return p;\n };\n\n // \u2500\u2500 \u5BBF\u4E3B\u97F3\u9891 \u2500\u2500\n /** TypedArray \u89C6\u56FE \u2192 \u53EA\u542B\u5176\u8303\u56F4\u7684\u72EC\u7ACB ArrayBuffer (\u62F7\u8D1D); ArrayBuffer \u539F\u6837\u8FD4\u56DE\u3002 */\n const toBuffer = (d: ArrayBuffer | ArrayBufferView): ArrayBuffer =>\n d instanceof ArrayBuffer ? d : (d.buffer as ArrayBuffer).slice(d.byteOffset, d.byteOffset + d.byteLength);\n const bindAbort = (signal: AbortSignal | undefined, id: string) => {\n if (!signal) return;\n const abort = () => { if (!destroyed) postToFrame('xc.audio.end', { abort: true }, id); };\n if (signal.aborted) abort(); else signal.addEventListener('abort', abort, { once: true });\n };\n const speakAudio = async (source: XiaochunAudioSource, opts: XiaochunAudioOptions = {}): Promise<void> => {\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n if (!iframe) activate(); // \u5148\u521B\u5EFA iframe (lazy \u6A21\u5F0F\u4E0B\u4E0E fetch \u5E76\u884C, \u7701\u4E00\u70B9\u9996\u6B21\u5EF6\u8FDF)\n const { signal, transfer, fetch: fetchWhere, ...rest } = opts;\n const payload: Record<string, unknown> = { ...rest };\n const list: Transferable[] = [];\n if (typeof source === 'string') {\n if (fetchWhere === 'frame') payload.source = source;\n else {\n const res = await fetch(source);\n if (!res.ok) throw new Error(`[project-xiaochun] audio fetch failed: HTTP ${res.status}`);\n const buf = await res.arrayBuffer();\n payload.source = buf; list.push(buf);\n payload.mimeType ??= res.headers.get('content-type') ?? undefined;\n }\n } else if (typeof Blob !== 'undefined' && source instanceof Blob) {\n payload.source = source; // Blob \u8D70\u7ED3\u6784\u5316\u514B\u9686 (\u6D4F\u89C8\u5668\u5185\u90E8\u5F15\u7528\u540C\u4E00\u4EFD\u6570\u636E, \u4E0D\u6574\u6BB5\u590D\u5236)\n payload.mimeType ??= source.type || undefined;\n } else {\n const buf = toBuffer(source as ArrayBuffer | ArrayBufferView);\n payload.source = buf;\n // \u89C6\u56FE\u603B\u662F\u62F7\u8D1D\u540E\u7684\u65B0 buffer \u2192 \u8F6C\u79FB; \u7528\u6237\u4F20\u5165\u7684 ArrayBuffer \u4EC5\u5728 transfer !== false \u65F6\u8F6C\u79FB (\u4F1A\u88AB detach)\n if (!(source instanceof ArrayBuffer) || transfer !== false) list.push(buf);\n }\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n const id = `c${++idSeq}`;\n const done = send('xc.audio', payload, true, list, id);\n bindAbort(signal, id); // \u5FC5\u987B\u5728 send \u4E4B\u540E (\u4FE1\u53F7\u5DF2 aborted \u65F6, abort \u6D88\u606F\u8981\u6392\u5728 xc.audio \u540E\u9762)\n return done;\n };\n const speakAudioStream = (opts: XiaochunAudioOptions & { sampleRate: number }): XiaochunAudioStream => {\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n const { signal, transfer, fetch: _f, mimeType: _m, ...rest } = opts;\n const id = `c${++idSeq}`;\n let started = false;\n let ended = false;\n let fmt: 'pcm16' | 'float32' | null = rest.format === 'pcm16' || rest.format === 'float32' ? rest.format : null;\n let done: Promise<void> = Promise.resolve();\n const handle: XiaochunAudioStream = {\n write(data) {\n if (ended) throw new Error('[project-xiaochun] audio stream already ended');\n if (destroyed) throw new Error('[project-xiaochun] instance destroyed');\n if (data instanceof Int16Array) fmt ??= 'pcm16';\n else if (data instanceof Float32Array) fmt ??= 'float32';\n if (!fmt) throw new Error('[project-xiaochun] speakAudioStream: set opts.format when writing raw ArrayBuffers');\n const buf = toBuffer(data);\n const body: Record<string, unknown> = { data: buf, format: fmt, sampleRate: rest.sampleRate, channels: rest.channels };\n if (!started) {\n started = true;\n body.text = rest.text; body.motion = rest.motion; body.lipsync = rest.lipsync;\n done = send('xc.audio.chunk', body, true, [buf], id);\n bindAbort(signal, id);\n } else {\n postToFrame('xc.audio.chunk', body, id, !(data instanceof ArrayBuffer) || transfer !== false ? [buf] : []);\n }\n },\n end() {\n if (ended) return;\n ended = true;\n if (started) postToFrame('xc.audio.end', {}, id);\n },\n abort() {\n if (ended && !started) return;\n ended = true;\n if (started) postToFrame('xc.audio.end', { abort: true }, id);\n },\n get done() { return done; },\n };\n return handle;\n };\n\n // \u2500\u2500 iframe \u521B\u5EFA \u2500\u2500\n function buildUrl(): string {\n const u = new URL(srcUrl.href);\n u.searchParams.set('host', window.location.origin); // iframe \u7AEF\u7528\u5B83\u505A\u63E1\u624B\u767D\u540D\u5355\n if (transparent) u.searchParams.set('transparent', '1');\n if (uiParts.length) u.searchParams.set('ui', uiParts.join(','));\n if (options.lang) u.searchParams.set('lang', options.lang);\n if (uiAutoHide !== undefined) u.searchParams.set('uiAutoHide', String(uiAutoHide));\n if (typeof camera.fov === 'number') u.searchParams.set('cameraFov', String(camera.fov));\n if (typeof camera.distance === 'number') u.searchParams.set('cameraDistance', String(camera.distance));\n if (typeof camera.height === 'number') u.searchParams.set('cameraHeight', String(camera.height));\n if (typeof camera.intro === 'boolean') u.searchParams.set('cameraIntro', camera.intro ? '1' : '0');\n if (options.heavy) u.searchParams.set('heavy', options.heavy);\n if (options.controls === false) u.searchParams.set('controls', '0');\n if (initialScene && isXcId(initialScene)) u.searchParams.set('scene', initialScene);\n if (initialOutfit) u.searchParams.set('outfit', initialOutfit);\n return u.href;\n }\n\n function activate(): void {\n if (destroyed || iframe) return;\n cancelIdle();\n io?.disconnect(); io = null;\n const f = document.createElement('iframe');\n f.title = 'Project XiaoChun';\n f.loading = 'lazy';\n f.allow = options.crossOriginIsolated === true\n ? 'microphone; autoplay; cross-origin-isolated' // \u5BBF\u4E3B\u5DF2 COOP/COEP \u9694\u79BB\u65F6, \u989D\u5916\u59D4\u6D3E\u8DE8\u6E90\u9694\u79BB \u2192 iframe \u5185 SharedArrayBuffer / \u591A\u7EBF\u7A0B wasm\n : 'microphone; autoplay'; // \u5BBF\u4E3B\u5FC5\u987B\u59D4\u6D3E: \u9EA6\u514B\u98CE (STT) + \u81EA\u52A8\u64AD\u653E (TTS \u97F3\u9891; \u7F3A\u5B83\u5219\u70B9\u51FB\u5BBF\u4E3B\u9875\u540E iframe \u5185 AudioContext \u4ECD\u88AB\u62E6)\n f.referrerPolicy = 'strict-origin-when-cross-origin';\n if (options.sandbox !== false) {\n f.setAttribute('sandbox', options.sandbox ?? 'allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox');\n }\n f.setAttribute('allowtransparency', 'true');\n f.setAttribute('scrolling', 'no');\n const s = f.style;\n s.position = 'absolute'; s.inset = '0'; s.width = '100%'; s.height = '100%';\n s.border = '0'; s.background = 'transparent'; s.colorScheme = 'normal';\n s.borderRadius = `var(--xc-radius, ${radiusValue()})`; // \u5706\u89D2\u88C1\u526A iframe \u5185\u5BB9 (\u5BBF\u4E3B CSS \u53EA\u80FD\u6539\u8FD9\u5C42\u5916\u58F3, \u6539\u4E0D\u5230 iframe \u5185\u90E8)\n f.setAttribute('part', 'iframe');\n noSelect(s);\n s.opacity = '0'; s.transition = 'opacity .25s ease';\n s.pointerEvents = passthrough ? 'none' : 'auto';\n f.src = buildUrl();\n iframe = f;\n wrapper.appendChild(f);\n if (placeholderEl) placeholderEl.style.cursor = 'default';\n handshakeTimer = setTimeout(() => {\n if (!port) emit('error', { code: 'timeout', message: `no xc.ready from ${frameOrigin} within ${handshakeTimeout}ms` });\n }, handshakeTimeout);\n setupAutoPause();\n if (passthrough) enablePassthrough();\n }\n\n // \u2500\u2500 \u6765\u81EA iframe \u7684\u63E1\u624B (window message) \u2500\u2500\n const onWindowMessage = (ev: MessageEvent) => {\n if (destroyed || !iframe || ev.source !== iframe.contentWindow) return; // \u53EA\u8BA4\u6211\u4EEC\u8FD9\u4E2A iframe\n if (!trusted.has(ev.origin)) {\n emit('error', { code: 'origin_denied', message: `ignored message from untrusted origin ${ev.origin}` });\n return;\n }\n const data = ev.data;\n if (!isXcEnvelope(data) || data.type !== 'xc.ready' || port) return; // \u63E1\u624B\u53EA\u505A\u4E00\u6B21\n const ch = new MessageChannel();\n port = ch.port1;\n port.onmessage = onPortMessage;\n caps = (data.payload as XcReadyPayload | undefined)?.capabilities ?? null;\n // targetOrigin = \u5DF2\u6821\u9A8C\u7684 ev.origin, \u7EDD\u4E0D\u7528 '*'\u3002allowCustomModel \u8D70 xc.init \u7684 config (\u4E0D\u8FDB URL), \u65E7 iframe \u4F1A\u5FFD\u7565\u672A\u77E5\u5B57\u6BB5\n // \u624B\u52BF\u5F00\u5173\u968F xc.init \u4E00\u8D77\u4EA4\u7ED9 iframe (iframe \u9ED8\u8BA4\u4E0D\u8BC6\u522B\u4EFB\u4F55\u624B\u52BF); \u65E7\u7248 /embed \u6CA1\u6709 capabilities.gestures \u2192 \u4E0D\u53D1\n const gWant = wantGestures();\n sentGestures = gWant;\n const initConfig: XcConfig = {\n ...(options.allowCustomModel ? { allowCustomModel: true } : {}),\n ...(gWant.move || gWant.resize ? { gestures: gWant } : {}),\n };\n iframe.contentWindow!.postMessage(\n xcMessage('xc.init', { hostOrigin: window.location.origin, ...(Object.keys(initConfig).length ? { config: initConfig } : {}) }),\n ev.origin,\n [ch.port2],\n );\n warnGestureUnsupported();\n if (handshakeTimer) { clearTimeout(handshakeTimer); handshakeTimer = null; }\n emit('handshake', data.payload as XcReadyPayload);\n resolveHandshake();\n for (const m of queue.splice(0)) {\n if (m.requires && !caps?.[m.requires]) unsupportedByFrame(m.type, m.id);\n else port.postMessage(xcMessage(m.type, m.payload, m.id), m.transfer ?? []);\n }\n syncPause();\n };\n window.addEventListener('message', onWindowMessage);\n\n /** \u547D\u4EE4\u5E94\u7B54: \u7528\u540C\u4E00\u4E2A\u4FE1\u5C01 id resolve \u5BF9\u5E94\u7684 Promise (xc.outfit-changed / xc.scene-changed)\u3002 */\n function ack(id: string | undefined, value?: unknown) {\n const p = id ? pending.get(id) : undefined;\n if (p && id) { pending.delete(id); p.resolve(value); }\n }\n\n // \u2500\u2500 \u6765\u81EA iframe \u7684\u7AEF\u53E3\u6D88\u606F \u2500\u2500\n function onPortMessage(ev: MessageEvent) {\n const data = ev.data as XcFrameMessage;\n if (!isXcEnvelope(data)) return;\n switch (data.type) {\n case 'xc.load.progress': emit('progress', data.payload); break;\n case 'xc.loaded':\n if (!loaded) {\n loaded = true;\n // \u81EA\u52A8\u9884\u53D6: \u53EA\u5728 heavy:'eager' \u4E14 iframe \u58F0\u660E\u652F\u6301\u65F6; \u5931\u8D25 / \u90E8\u5206\u5931\u8D25\u90FD\u4E0D\u6253\u6270\u5BBF\u4E3B (\u663E\u5F0F prefetch() \u624D\u8FD4\u56DE\u7ED3\u679C)\n if (options.prefetch && options.heavy === 'eager' && caps?.prefetch) {\n const ids = Array.isArray(options.prefetch) ? options.prefetch : undefined;\n void api.prefetch(ids).catch(() => {});\n }\n if (iframe) iframe.style.opacity = '1';\n if (placeholderEl) {\n const el = placeholderEl;\n el.style.opacity = '0'; el.style.pointerEvents = 'none';\n setTimeout(() => el.remove(), 300);\n placeholderEl = null;\n }\n resolveReady();\n }\n emit('ready', data.payload);\n break;\n case 'xc.outfit-changed': {\n const pl = data.payload;\n if (!pl.noop) {\n currentOutfit = pl.id;\n emit('outfit-changed', pl);\n if (!pl.initial && pl.id) writePrefs({ outfit: pl.id }); // \u53EA\u8BB0\u7528\u6237/\u5BBF\u4E3B\u4E3B\u52A8\u6362\u7684, \u4E0D\u8BB0\u9ED8\u8BA4\u670D\u88C5\n }\n ack(data.id);\n break;\n }\n case 'xc.scene-changed': {\n const pl = data.payload;\n currentScene = pl.id;\n if (pl.transparent !== transparent) applyTransparency(pl.transparent); // iframe \u662F\u4E8B\u5B9E\u6E90: \u540C\u6B65\u5916\u58F3\u80CC\u666F / \u7A7F\u900F / pointer-events\n if (!pl.noop) {\n emit('scene-changed', pl);\n if (!pl.initial) writePrefs({ scene: pl.id });\n }\n ack(data.id);\n break;\n }\n case 'xc.lang-changed': emit('lang-changed', data.payload); break;\n case 'xc.prefetched': ack(data.id, data.payload); break;\n case 'xc.state': emit('state', data.payload); break;\n case 'xc.stt': emit('stt', data.payload); break;\n case 'xc.utterance': {\n emit('utterance', data.payload);\n const p = data.id ? pending.get(data.id) : undefined;\n if (p && data.payload.phase === 'end') { pending.delete(data.id!); p.resolve(); }\n break;\n }\n case 'xc.hit-region': {\n const { hit } = data.payload;\n emit('hit-region', data.payload);\n if (passthrough && iframe && hit !== lastHit) {\n lastHit = hit;\n iframe.style.pointerEvents = hit ? 'auto' : 'none';\n }\n break;\n }\n case 'xc.gesture-move': onGesture('move', data.payload); break;\n case 'xc.gesture-resize': onGesture('resize', data.payload); break;\n case 'xc.error': {\n const { code, message, command } = data.payload;\n emit('error', { code, message, command });\n // \u521D\u59CB ?outfit= / ?scene= \u88AB iframe \u5224\u4E3A\u975E\u6CD5: \u5DF2\u4FDD\u5B58\u7684\u504F\u597D\u662F\u574F\u7684, \u6E05\u6389\u514D\u5F97\u6BCF\u6B21\u90FD\u62A5\n if (code === 'unknown_id' && (command === 'outfit' || command === 'scene')) writePrefs({ [command]: null });\n const p = data.id ? pending.get(data.id) : undefined;\n if (p && data.id) { pending.delete(data.id); p.reject(new Error(`[${code}] ${message}`)); }\n break;\n }\n default: break;\n }\n }\n\n // \u2500\u2500 \u5BBF\u4E3B pointer \u2192 iframe (\u900F\u660E\u7A7F\u900F\u6A21\u5F0F) \u2500\u2500\n // iframe \u5904\u4E8E pointer-events:none \u65F6, \u5BBF\u4E3B\u9875\u7684 pointermove \u624D\u662F\u552F\u4E00\u7EBF\u7D22:\n // - \u6307\u9488\u4E0D\u5728 iframe \u8303\u56F4\u5185\u65F6\u53EA\u505A\u4E00\u6B21\u5EC9\u4EF7\u7684\u77E9\u5F62\u6BD4\u8F83 (\u77E9\u5F62\u7F13\u5B58, \u4E0D\u5728\u6BCF\u5E27 getBoundingClientRect \u4EE5\u514D\u5F3A\u5236\u56DE\u6D41);\n // - \u6307\u9488\u5728\u8303\u56F4\u5185\u65F6\u6BCF\u5E27\u6700\u591A\u53D1\u4E00\u6B21 xc.pointer, \u4E14\u79FB\u52A8\u4E0D\u8DB3 2px \u6216\u8DDD\u4E0A\u6B21\u4E0D\u8DB3 32ms \u5219\u8DF3\u8FC7, \u907F\u514D iframe \u91CC\u6BCF\u5E27\u4E00\u6B21\u5C04\u7EBF\u68C0\u6D4B\u3002\n const POINTER_MIN_INTERVAL_MS = 32;\n const POINTER_MIN_MOVE_PX = 2;\n let pointerRaf = 0;\n let lastPtr: { x: number; y: number } | null = null;\n let lastPosted: { x: number; y: number; t: number } | null = null;\n let rectCache: DOMRect | null = null;\n let rectRo: ResizeObserver | null = null;\n let rectAt = 0;\n const invalidateRect = () => { rectCache = null; };\n const getRect = (): DOMRect | null => {\n if (!iframe) return null;\n const now = performance.now();\n // \u515C\u5E95 TTL: \u5185\u8054\u5E03\u5C40\u88AB\u9875\u9762\u5176\u5B83\u5185\u5BB9\u63A8\u52A8 (\u4E0D\u89E6\u53D1 resize/scroll) \u65F6, \u6700\u591A 400ms \u540E\u81EA\u6108\n if (!rectCache || now - rectAt > 400) { rectCache = iframe.getBoundingClientRect(); rectAt = now; }\n return rectCache;\n };\n const onHostPointer = (e: PointerEvent) => {\n if (!iframe || !port || iframe.style.pointerEvents === 'auto') return; // iframe \u81EA\u5DF1\u62FF\u5230\u4E8B\u4EF6\u65F6\u7531\u5B83\u4E0A\u62A5\n lastPtr = { x: e.clientX, y: e.clientY };\n if (pointerRaf) return;\n pointerRaf = requestAnimationFrame(() => {\n pointerRaf = 0;\n if (!iframe || !port || !lastPtr) return;\n const r = getRect();\n if (!r) return;\n const x = lastPtr.x - r.left, y = lastPtr.y - r.top;\n if (x < 0 || y < 0 || x > r.width || y > r.height) {\n lastPosted = null;\n if (lastHit) { lastHit = false; iframe.style.pointerEvents = 'none'; }\n return;\n }\n const now = performance.now();\n if (lastPosted && now - lastPosted.t < POINTER_MIN_INTERVAL_MS) return;\n if (lastPosted && Math.abs(x - lastPosted.x) < POINTER_MIN_MOVE_PX && Math.abs(y - lastPosted.y) < POINTER_MIN_MOVE_PX) return;\n lastPosted = { x, y, t: now };\n port.postMessage(xcMessage('xc.pointer', { x, y }));\n });\n };\n // \u7A7F\u900F\u76D1\u542C\u53EF\u542F\u505C (\u8FD0\u884C\u4E2D\u5207 scene \u65F6\u9700\u8981): enable / disable \u90FD\u5E42\u7B49\u3002\n let passthroughActive = false;\n function enablePassthrough() {\n if (passthroughActive || !iframe) return;\n passthroughActive = true;\n window.addEventListener('pointermove', onHostPointer, { passive: true });\n // \u89E6\u5C4F\u6CA1\u6709 hover: \u70B9\u4E00\u4E0B (pointerdown) \u4E5F\u63A2\u6D4B\u4E00\u6B21\u547D\u4E2D, \u547D\u4E2D\u540E iframe \u8F6C auto, \u4E0B\u4E00\u6B21\u70B9\u51FB\u5373\u53EF\u843D\u5230\u89D2\u8272 / \u5185\u7F6E\u6309\u94AE\u4E0A\n window.addEventListener('pointerdown', onHostPointer, { passive: true });\n window.addEventListener('scroll', invalidateRect, { passive: true, capture: true });\n window.addEventListener('resize', invalidateRect, { passive: true });\n if (typeof ResizeObserver !== 'undefined') {\n rectRo = new ResizeObserver(invalidateRect);\n rectRo.observe(iframe);\n }\n }\n function disablePassthrough() {\n if (!passthroughActive) return;\n passthroughActive = false;\n window.removeEventListener('pointermove', onHostPointer);\n window.removeEventListener('pointerdown', onHostPointer);\n window.removeEventListener('scroll', invalidateRect, true);\n window.removeEventListener('resize', invalidateRect);\n rectRo?.disconnect(); rectRo = null;\n if (pointerRaf) { cancelAnimationFrame(pointerRaf); pointerRaf = 0; }\n lastPtr = null;\n }\n /**\n * \u8FD0\u884C\u4E2D\u5207\u6362\u900F\u660E \u2194 \u975E\u900F\u660E (xc.scene-changed \u9A71\u52A8): \u540C\u6B65\u5916\u58F3\u80CC\u666F\u3001\u5F00\u5173\u7A7F\u900F\u76D1\u542C\u3001\u91CD\u7F6E\u547D\u4E2D\u72B6\u6001\u3002\n * - \u5207\u5230\u975E\u900F\u660E: \u5F3A\u5236 iframe pointer-events:auto (\u6574\u5757\u753B\u5E03\u90FD\u662F\u89D2\u8272\u80CC\u666F, \u4E0D\u8BE5\u7A7F\u900F), \u5173\u6389\u7A7F\u900F\u76D1\u542C;\n * - \u5207\u5230\u900F\u660E: passthrough \u9009\u9879\u663E\u5F0F\u7ED9\u4E86\u5C31\u6309\u5B83, \u5426\u5219\u6253\u5F00; iframe \u5148 none, \u7B49 xc.pointer / xc.hit-region \u518D\u5207 auto;\n * - \u4E24\u79CD\u60C5\u51B5\u90FD\u6E05\u6389 lastHit / lastPosted / \u77E9\u5F62\u7F13\u5B58, \u5426\u5219 iframe \u4FA7\u5DF2\u91CD\u7F6E\u7684\u53BB\u91CD\u72B6\u6001\u4F1A\u548C\u8FD9\u91CC\u5BF9\u4E0D\u4E0A, \u5BFC\u81F4\u6307\u9488\u4E0D\u52A8\u65F6\u7B2C\u4E00\u6B21\u547D\u4E2D\u88AB\u541E\u3002\n */\n function applyTransparency(next: boolean) {\n transparent = next;\n applyWrapperBg();\n applyRadius();\n passthrough = next ? (options.passthrough ?? true) : false;\n lastHit = false; lastPosted = null; rectCache = null;\n if (passthrough) enablePassthrough(); else disablePassthrough();\n if (iframe) iframe.style.pointerEvents = passthrough ? 'none' : 'auto';\n }\n\n // \u2500\u2500 \u89C6\u53E3\u5916\u81EA\u52A8\u6682\u505C \u2500\u2500\n let pauseIo: IntersectionObserver | null = null;\n function setupAutoPause() {\n if (options.autoPause === false || typeof IntersectionObserver === 'undefined') return;\n pauseIo = new IntersectionObserver((entries) => {\n const visible = entries[entries.length - 1]?.isIntersecting ?? true;\n autoPaused = !visible;\n syncPause();\n });\n pauseIo.observe(wrapper);\n }\n let sentPaused = false;\n function syncPause() {\n if (!port) return;\n const want = userPaused || autoPaused;\n if (want === sentPaused) return;\n sentPaused = want;\n port.postMessage(xcMessage(want ? 'xc.pause' : 'xc.resume'));\n }\n\n // \u2500\u2500 lazy \u8C03\u5EA6 \u2500\u2500\n function cancelIdle() {\n if (idleHandle === null) return;\n const w = window as Window & { cancelIdleCallback?: (h: number) => void };\n if (w.cancelIdleCallback) w.cancelIdleCallback(idleHandle); else clearTimeout(idleHandle);\n idleHandle = null;\n }\n function scheduleLazy() {\n if (lazy === false) { activate(); return; }\n if (lazy === 'click') return;\n const go = () => {\n const w = window as Window & { requestIdleCallback?: (cb: () => void, o?: { timeout: number }) => number };\n // \u7A7A\u95F2\u56DE\u8C03 timeout 3s: \u4E3B\u7EBF\u7A0B\u4E00\u76F4\u5FD9\u4E5F\u6700\u8FDF 3s \u540E\u521B\u5EFA, \u8C03\u5927\u66F4\u4E0D\u5F71\u54CD\u9996\u5C4F, \u8C03\u5C0F\u66F4\u5FEB\u51FA\u73B0\n idleHandle = w.requestIdleCallback ? w.requestIdleCallback(() => { idleHandle = null; activate(); }, { timeout: 3000 }) : (setTimeout(activate, 1200) as unknown as number);\n };\n if (typeof IntersectionObserver === 'undefined') { go(); return; }\n io = new IntersectionObserver((entries) => {\n if (entries.some((e) => e.isIntersecting)) { io?.disconnect(); io = null; go(); }\n }, { rootMargin: `${options.lazyMargin ?? 200}px` });\n io.observe(wrapper);\n }\n\n // \u2500\u2500 \u624B\u52BF: \u62D6\u52A8 / \u7F29\u653E (iframe \u91CC\u8BC6\u522B, \u5BBF\u4E3B\u8FD9\u91CC\u6267\u884C + \u9650\u5E45) \u2500\u2500\n // \u534F\u8BAE: xc.gesture-move / xc.gesture-resize (\u89C1 protocol.ts \u7684 XcGestureBase)\u3002\u5BBF\u4E3B\u4E0D\u4FE1\u4EFB iframe \u53D1\u6765\u7684\u4EFB\u4F55\u6570:\n // \u6821\u9A8C\u8F7D\u8377 (parseGesturePayload) \u2192 \u5E8F\u53F7\u95F8\u95E8 (GestureGate) \u2192 \u4EE5\"\u624B\u52BF\u5F00\u59CB\u65F6\u7684\u76D2\u5B50 + \u7D2F\u8BA1\u4F4D\u79FB\"\u5939\u5728\u89C6\u53E3 / \u6700\u5C0F\u6700\u5927\u5C3A\u5BF8\u5185 (gesture-box.ts)\u3002\n // \u5BBF\u4E3B\u6CA1\u5F00 draggable / resizable \u65F6, \u5BF9\u5E94\u6D88\u606F\u4E00\u5F8B\u5FFD\u7565; \u540C\u4E00\u65F6\u523B\u53EA\u5141\u8BB8\u4E00\u4E2A\u624B\u52BF\u3002\n let draggableOn = options.draggable === true;\n let resizeLimits: ResizeLimits | null = normalizeResizable(options.resizable);\n const gates = { move: new GestureGate(), resize: new GestureGate() };\n let activeGesture: { kind: 'move' | 'resize'; start: Box; inlineBase: { left: number; top: number } | null; corner?: 'NW' | 'NE' | 'SW' | 'SE' } | null = null;\n /** \u5185\u8054\u6A21\u5F0F\u9760 CSS translate \u4F4D\u79FB (\u4E0D\u6539\u5E03\u5C40\u6D41); \u8BB0\u4E0B\u5F53\u524D\u4F4D\u79FB, \u624D\u80FD\u8FD8\u539F\u51FA\"\u6D41\u5185\u539F\u70B9\"\u3002 */\n let inlineShift = { x: 0, y: 0 };\n let userMoved = false;\n let sentGestures: { move: boolean; resize: boolean } | null = null;\n let warnedGesture = false;\n const viewport = (): Viewport => ({\n width: document.documentElement.clientWidth || window.innerWidth,\n height: document.documentElement.clientHeight || window.innerHeight,\n });\n const readBox = (): Box => { const r = wrapper.getBoundingClientRect(); return { left: r.left, top: r.top, width: r.width, height: r.height }; };\n const wantGestures = () => ({ move: draggableOn && caps?.gestures?.move === true, resize: resizeLimits !== null && caps?.gestures?.resize === true });\n\n function applyBox(b: Box, inlineBase: { left: number; top: number } | null, withSize: boolean): void {\n if (withSize) { ws.width = `${b.width}px`; ws.height = `${b.height}px`; ws.maxWidth = 'none'; } // maxWidth:100% \u4F1A\u628A\u7528\u6237\u62C9\u5927\u7684\u5BBD\u5EA6\u538B\u56DE\u5BB9\u5668\u5BBD\n if (position === 'inline') {\n const base = inlineBase ?? { left: b.left - inlineShift.x, top: b.top - inlineShift.y };\n inlineShift = { x: b.left - base.left, y: b.top - base.top };\n ws.setProperty('translate', `${inlineShift.x}px ${inlineShift.y}px`);\n } else {\n ws.left = `${b.left}px`; ws.top = `${b.top}px`; ws.right = 'auto'; ws.bottom = 'auto';\n }\n userMoved = true;\n invalidateRect();\n }\n\n // \u62D6\u52A8\u671F\u95F4\u4E0D\u51FA\u73B0\u9009\u4E2D\u84DD\u6846: \u5BBF\u4E3B\u9875\u4E34\u65F6 user-select:none \u5E76\u6E05\u6389\u5DF2\u6709\u9009\u533A (iframe \u5185\u90E8\u53E6\u6709\u5904\u7406)\n let selectionLock: { us: string; wus: string } | null = null;\n function lockSelection(on: boolean): void {\n const de = document.documentElement;\n if (on && !selectionLock) {\n selectionLock = { us: de.style.getPropertyValue('user-select'), wus: de.style.getPropertyValue('-webkit-user-select') };\n de.style.setProperty('user-select', 'none'); de.style.setProperty('-webkit-user-select', 'none');\n try { window.getSelection()?.removeAllRanges(); } catch { /* ignore */ }\n } else if (!on && selectionLock) {\n de.style.setProperty('user-select', selectionLock.us); de.style.setProperty('-webkit-user-select', selectionLock.wus);\n selectionLock = null;\n }\n }\n function endActiveGesture(kind?: 'move' | 'resize'): void {\n if (!activeGesture || (kind && activeGesture.kind !== kind)) return;\n gates[activeGesture.kind].close();\n const b = readBox();\n emit(activeGesture.kind, { phase: 'end', ...b });\n activeGesture = null;\n lockSelection(false);\n saveBox();\n }\n\n function onGesture(kind: 'move' | 'resize', raw: unknown): void {\n if (destroyed || !caps?.gestures) return;\n if (kind === 'move' ? !draggableOn : resizeLimits === null) return; // \u5BBF\u4E3B\u6CA1\u5F00: \u5FFD\u7565\n const p = parseGesturePayload(kind, raw);\n if (!p) return;\n if (p.phase === 'start' ? activeGesture !== null : activeGesture?.kind !== kind) return; // \u540C\u4E00\u65F6\u523B\u53EA\u5141\u8BB8\u4E00\u4E2A\u624B\u52BF\n if (!gates[kind].accept(p)) return;\n if (p.phase === 'start') {\n const start = readBox();\n activeGesture = {\n kind, start, corner: p.corner,\n inlineBase: position === 'inline' ? { left: start.left - inlineShift.x, top: start.top - inlineShift.y } : null,\n };\n lockSelection(true);\n emit(kind, { phase: 'start', ...start });\n return;\n }\n const a = activeGesture!;\n const vp = viewport();\n const next = kind === 'move'\n ? moveBox(a.start, p.totalDx, p.totalDy, vp)\n : resizeBox(a.start, a.corner!, p.totalDx, p.totalDy, resizeLimits!, vp);\n applyBox(next, a.inlineBase, kind === 'resize');\n emit(kind, { phase: p.phase, ...next });\n if (p.phase === 'end') { activeGesture = null; lockSelection(false); saveBox(); }\n }\n\n /** \u628A draggable / resizable \u7684\u5F53\u524D\u503C\u540C\u6B65\u7ED9 iframe (\u53EA\u5728\u53D8\u5316\u65F6\u53D1 xc.setConfig{gestures}); \u63E1\u624B\u65F6\u5DF2\u968F xc.init \u53D1\u8FC7\u4E00\u6B21\u3002 */\n function syncGestures(): void {\n if (destroyed) return;\n const want = wantGestures();\n if (!want.move) endActiveGesture('move');\n if (!want.resize) endActiveGesture('resize');\n if (!port || !caps) return;\n warnGestureUnsupported();\n if (sentGestures && sentGestures.move === want.move && sentGestures.resize === want.resize) return;\n sentGestures = want;\n if (caps.gestures) port.postMessage(xcMessage('xc.setConfig', { gestures: want }));\n }\n /** \u65E7\u7248 /embed (\u63E1\u624B\u91CC\u6CA1\u6709 capabilities.gestures) \u5374\u5F00\u4E86\u624B\u52BF: \u544A\u77E5\u4E00\u6B21\u3002 */\n function warnGestureUnsupported(): void {\n if (warnedGesture || !caps || caps.gestures) return;\n const needMove = draggableOn;\n if (!needMove && resizeLimits === null) return;\n warnedGesture = true;\n const what = [needMove ? 'draggable' : '', resizeLimits !== null ? 'resizable' : ''].filter(Boolean).join(' / ');\n emit('error', { code: 'unsupported', message: `${what} needs gesture support (capabilities.gestures), which this /embed deployment does not advertise (older version)`, command: 'gestures' });\n }\n\n // \u7A97\u53E3\u53D8\u5C0F\u540E\u628A\u7528\u6237\u62D6\u8FC7 / \u7F29\u8FC7\u7684\u5934\u50CF\u5939\u56DE\u89C6\u53E3 (\u6CA1\u52A8\u8FC7\u5C31\u4E0D\u7BA1, \u4EA4\u7ED9\u9875\u9762\u81EA\u5DF1\u7684\u5E03\u5C40)\n const onWindowResize = () => {\n if (!userMoved || activeGesture || destroyed) return;\n const cur = readBox();\n const vp = viewport();\n // \u5185\u8054\u76D2\u5B50\u53EF\u4EE5\u5728\u6EDA\u52A8\u7684\u9875\u9762\u4E0B\u65B9: \u7EB5\u5411\u4E0D\u6309\u89C6\u53E3\u5939 (\u5426\u5219\u4F1A\u628A\u89C6\u53E3\u5916\u7684\u76D2\u5B50\u62FD\u8FDB\u89C6\u53E3), \u53EA\u4FDD\u8BC1\u4E0D\u8D8A\u8FC7\u6587\u6863\u9876\u90E8; \u6A2A\u5411 / \u5C3A\u5BF8\u7167\u5E38\u5939\u8FDB\u89C6\u53E3\n const fit = position === 'inline'\n ? { ...fitBox({ ...cur, top: 0 }, { width: vp.width, height: Number.MAX_SAFE_INTEGER }), top: Math.max(cur.top, -window.scrollY) }\n : fitBox(cur, vp);\n if (fit.left === cur.left && fit.top === cur.top && fit.width === cur.width && fit.height === cur.height) return;\n applyBox(fit, position === 'inline' ? { left: cur.left - inlineShift.x, top: cur.top - inlineShift.y } : null, fit.width !== cur.width || fit.height !== cur.height);\n };\n window.addEventListener('resize', onWindowResize, { passive: true });\n\n // \u2500\u2500 \u4F4D\u7F6E / \u5927\u5C0F\u8BB0\u5FC6 (persistBox) \u2500\u2500\n // \u5B58\u7684\u662F { v, mode, x, y, width, height }: \u60AC\u6D6E\u6A21\u5F0F x/y = \u89C6\u53E3 left/top; \u5185\u8054\u6A21\u5F0F x/y = \u76F8\u5BF9\"\u6D41\u5185\u539F\u70B9\"\u7684\u4F4D\u79FB (translate), \u4E0E\u6EDA\u52A8\u65E0\u5173\u3002\n const boxKey = options.persistBox === true ? 'xiaochun:box' : typeof options.persistBox === 'string' && options.persistBox ? `xiaochun:box:${options.persistBox}` : null;\n const saveBox = (): void => {\n if (!boxKey) return;\n try {\n const b = readBox();\n const at = position === 'inline' ? inlineShift : { x: b.left, y: b.top };\n window.localStorage.setItem(boxKey, JSON.stringify({ v: 1, mode: position, x: Math.round(at.x), y: Math.round(at.y), width: Math.round(b.width), height: Math.round(b.height) }));\n } catch { /* \u9690\u79C1\u6A21\u5F0F / \u914D\u989D / \u88AB\u7981\u7528: \u53EA\u662F\u4E0D\u8BB0\u5FC6 */ }\n };\n const loadBox = (): { x: number; y: number; width: number; height: number } | null => {\n if (!boxKey) return null;\n try {\n const raw = window.localStorage.getItem(boxKey);\n if (raw === null) return null;\n let o: Record<string, unknown> | null = null;\n try { o = JSON.parse(raw) as Record<string, unknown> | null; } catch { /* \u574F JSON: \u4E0B\u9762\u4E00\u5E76\u6E05\u6389 */ }\n const ok = (v: unknown, lo: number, hi: number): v is number => typeof v === 'number' && Number.isFinite(v) && v >= lo && v <= hi;\n if (o && o.v === 1 && o.mode === position && ok(o.x, -1e5, 1e5) && ok(o.y, -1e5, 1e5) && ok(o.width, 1, 1e5) && ok(o.height, 1, 1e5)) {\n return { x: o.x, y: o.y, width: o.width, height: o.height };\n }\n window.localStorage.removeItem(boxKey); // \u574F\u6570\u636E / \u522B\u7684\u7248\u672C / \u522B\u7684\u5B9A\u4F4D\u6A21\u5F0F: \u6E05\u6389\n } catch { /* ignore */ }\n return null;\n };\n /** \u521B\u5EFA\u65F6\u6062\u590D: \u9700\u8981\u624B\u52BF\u5F00\u7740; \u663E\u5F0F width / height \u9009\u9879\u4F18\u5148\u4E8E\u5DF2\u4FDD\u5B58\u7684\u5927\u5C0F; \u5168\u90E8\u94B3\u5230\u5F53\u524D\u89C6\u53E3\u3002 */\n function restoreBox(): void {\n if (!boxKey || (!draggableOn && resizeLimits === null)) return;\n const st = loadBox();\n if (!st) return;\n const vp = viewport();\n const lim = resizeLimits ?? DEFAULT_RESIZE_LIMITS;\n const cur = readBox();\n const useW = resizeLimits !== null && options.width === undefined;\n const useH = resizeLimits !== null && options.height === undefined;\n const clampN = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), Math.max(lo, hi));\n const width = useW ? clampN(st.width, lim.minWidth, Math.min(lim.maxWidth, vp.width)) : cur.width;\n const height = useH ? clampN(st.height, lim.minHeight, Math.min(lim.maxHeight, vp.height)) : cur.height;\n if (position === 'inline') {\n const base = { left: cur.left - inlineShift.x, top: cur.top - inlineShift.y };\n const left = clampN(base.left + st.x, 0, vp.width - width);\n const top = Math.max(base.top + st.y, -window.scrollY); // \u7EB5\u5411: \u4E0D\u8D8A\u8FC7\u6587\u6863\u9876\u90E8 (\u5185\u8054\u76D2\u5B50\u53EF\u4EE5\u5728\u6EDA\u52A8\u7684\u9875\u9762\u4E0B\u65B9, \u4E0D\u6309\u89C6\u53E3\u5939)\n applyBox({ left, top, width, height }, base, useW || useH);\n } else {\n applyBox(fitBox({ left: st.x, top: st.y, width, height }, vp), null, useW || useH);\n }\n }\n restoreBox();\n\n scheduleLazy();\n\n const api: XiaochunInstance = {\n element: wrapper,\n get iframe() { return iframe; },\n ready,\n activate,\n say: (text, opts) => send('xc.say', { text, mode: opts?.mode }, true),\n speakAudio,\n speakAudioStream,\n motion: (m) => send('xc.motion', typeof m === 'string' ? (m.startsWith('http') || m.startsWith('/') ? { url: m } : { name: m }) : m),\n expression: (name) => send('xc.expression', { name }),\n lookAt: (x, y) => send('xc.lookAt', { x, y }),\n setOutfit: (id) => {\n if (!isXcId(id)) return Promise.reject(new Error('[bad_request] invalid outfit id'));\n return send('xc.setOutfit', { id }, true, undefined, undefined, 'outfits');\n },\n setScene: (id) => {\n if (!isXcId(id)) return Promise.reject(new Error('[bad_request] invalid scene id'));\n return send('xc.setScene', { id }, true, undefined, undefined, 'scenes');\n },\n prefetch: (ids) => {\n if (ids !== undefined && (!Array.isArray(ids) || ids.some((x) => !isXcId(x)))) {\n return Promise.reject(new Error('[bad_request] prefetch ids must be an array of outfit ids'));\n }\n return send('xc.prefetch', ids ? { ids } : {}, true, undefined, undefined, 'prefetch');\n },\n getOutfits: async () => { if (!iframe) activate(); await handshaked; return caps?.outfits ? caps.outfits.slice() : []; },\n getScenes: async () => { if (!iframe) activate(); await handshaked; return caps?.scenes ? caps.scenes.slice() : []; },\n get outfit() { return currentOutfit; },\n get scene() { return currentScene; },\n setModel: (m) => {\n const msg = typeof m === 'string' ? (/^(https?:)?\\/|\\.vrm/i.test(m) ? { url: m } : { outfit: m }) : m;\n if (msg.url !== undefined && msg.outfit === undefined && !options.allowCustomModel) {\n const message = 'custom model URLs are disabled; pass allowCustomModel: true to createXiaochun() (only for URLs you trust) or use setOutfit() with a built-in id';\n emit('error', { code: 'unsupported', message, command: 'xc.setModel' });\n return Promise.reject(new Error(`[unsupported] ${message}`));\n }\n return send('xc.setModel', msg);\n },\n setConfig: (cfg) => send('xc.setConfig', cfg),\n setSize(width, height) {\n if (destroyed) return;\n ws.width = css(width, defaultWidthCss(position !== 'inline')); ws.height = css(height, defaultHeightCss(position !== 'inline'));\n if (ws.maxWidth === 'none') ws.maxWidth = '100%'; // \u7528\u6237\u62C9\u5927\u8FC7 (applyBox \u4F1A\u6E05\u6389 max-width): \u5BBF\u4E3B\u91CD\u65B0\u7ED9\u5C3A\u5BF8\u540E\u6062\u590D\u4E0D\u6EA2\u51FA\u5BB9\u5668\u7684\u7EA6\u675F\n invalidateRect();\n },\n getBox: () => readBox(),\n clearPersistedBox(opts) {\n if (boxKey) { try { window.localStorage.removeItem(boxKey); } catch { /* ignore */ } }\n if (destroyed || opts?.reset !== true) return;\n endActiveGesture();\n ws.width = css(options.width, defaultWidthCss(position !== 'inline')); ws.height = css(options.height, defaultHeightCss(position !== 'inline')); ws.maxWidth = '100%';\n if (position === 'inline') { inlineShift = { x: 0, y: 0 }; ws.removeProperty('translate'); }\n else {\n ws.left = ''; ws.top = ''; ws.right = ''; ws.bottom = '';\n if (position === 'bottom-right') { ws.right = 'var(--xc-offset-x, 16px)'; ws.bottom = 'var(--xc-offset-y, 16px)'; }\n if (position === 'bottom-left') { ws.left = 'var(--xc-offset-x, 16px)'; ws.bottom = 'var(--xc-offset-y, 16px)'; }\n }\n userMoved = false;\n invalidateRect();\n },\n setBorderRadius(radius) {\n radiusOpt = radius;\n applyRadius();\n },\n setDraggable(on) {\n draggableOn = on === true;\n syncGestures();\n },\n setResizable(on) {\n resizeLimits = normalizeResizable(on);\n syncGestures();\n },\n startListening: () => send('xc.mic', { enabled: true }),\n stopListening: () => send('xc.mic', { enabled: false }),\n mic: (enabled) => send('xc.mic', { enabled }),\n pause() { userPaused = true; syncPause(); },\n resume() { userPaused = false; syncPause(); },\n destroy() {\n if (destroyed) return;\n try { port?.postMessage(xcMessage('xc.destroy')); } catch { /* ignore */ }\n destroyed = true;\n cancelIdle();\n io?.disconnect(); pauseIo?.disconnect();\n if (handshakeTimer) clearTimeout(handshakeTimer);\n if (pointerRaf) cancelAnimationFrame(pointerRaf);\n window.removeEventListener('message', onWindowMessage);\n window.removeEventListener('resize', onWindowResize);\n lockSelection(false);\n disablePassthrough();\n resolveHandshake(); // \u8FD8\u5728\u7B49 getOutfits() / getScenes() \u7684\u8C03\u7528\u65B9\u62FF\u5230 [] \u800C\u4E0D\u662F\u6C38\u8FDC\u6302\u8D77\n try { port?.close(); } catch { /* ignore */ }\n port = null;\n for (const p of pending.values()) p.reject(new Error('[project-xiaochun] instance destroyed'));\n pending.clear();\n queue.length = 0;\n if (!loaded) rejectReady(new Error('[project-xiaochun] destroyed before ready'));\n wrapper.remove(); // \u540C\u65F6\u79FB\u9664 iframe \u2192 \u6D4F\u89C8\u5668\u91CA\u653E WebGL \u4E0A\u4E0B\u6587\n iframe = null;\n emit('destroy', undefined);\n listeners.clear();\n },\n on(event, cb) {\n let set = listeners.get(event);\n if (!set) { set = new Set(); listeners.set(event, set); }\n set.add(cb as (p: any) => void);\n return () => { set!.delete(cb as (p: any) => void); };\n },\n };\n return api;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css"]
|
|
7
7
|
}
|