@firetable/project-xiaochun 0.1.12 → 0.1.14
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 +375 -0
- package/README.md +292 -118
- package/dist/avatar-element.d.ts +1 -1
- package/dist/chunks/{chunk-4VETYSWF.js → chunk-DUU5PTKT.js} +2 -2
- package/dist/chunks/{chunk-4VETYSWF.js.map → chunk-DUU5PTKT.js.map} +2 -2
- package/dist/chunks/{chunk-XKLOFX52.js → chunk-HLVD6HQM.js} +8 -6
- package/dist/chunks/chunk-HLVD6HQM.js.map +7 -0
- package/dist/chunks/{chunk-UAIDX54S.js → chunk-OLVSOJML.js} +41 -6
- package/dist/chunks/chunk-OLVSOJML.js.map +7 -0
- package/dist/client.d.ts +7 -0
- package/dist/element.cjs +44 -7
- package/dist/element.cjs.map +2 -2
- package/dist/element.js +4 -4
- package/dist/index.cjs +44 -7
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +4 -4
- package/dist/loader.global.js +2 -2
- package/dist/loader.global.js.map +3 -3
- package/dist/protocol.cjs +1 -1
- package/dist/protocol.cjs.map +2 -2
- package/dist/protocol.d.ts +2 -0
- package/dist/protocol.js +2 -2
- package/dist/react.cjs +40 -4
- package/dist/react.cjs.map +2 -2
- package/dist/react.js +4 -3
- package/dist/react.js.map +2 -2
- package/package.json +2 -1
- package/dist/chunks/chunk-UAIDX54S.js.map +0 -7
- package/dist/chunks/chunk-XKLOFX52.js.map +0 -7
package/dist/react.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/react.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/width/\u2026) \u53D8\u5316\u4F1A\u91CD\u5EFA\u5B9E\u4F8B; lang / model / paused / mic \u53D8\u5316\u5219\u70ED\u66F4\u65B0 (\u4E0D\u91CD\u5EFA iframe)\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 type { XcConfig, XcExpressionPayload, XcMotionPayload, 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 onError?: (p: XiaochunEvents['error']) => void;\n onDestroy?: () => 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 ['error', 'onError'],\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, paused: _p, mic: _m, allowedOrigins, ...create } = cur;\n void [_a, _b, _c, _d, _e, _f, _g, _h, _i, _p, _m];\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/model/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.width, o.height, o.position,\n o.draggable, o.ui, o.heavy, o.controls, o.autoPause, o.passthrough, o.sandbox, o.handshakeTimeout, o.zIndex]);\n\n // \u70ED\u66F4\u65B0: lang / model (\u8DF3\u8FC7\u9996\u6B21: \u521B\u5EFA\u65F6\u5DF2\u7ECF\u4F5C\u4E3A\u521D\u59CB\u9009\u9879\u4F20\u5165)\n const first = useRef({ lang: o.lang, model: o.model });\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.model === o.model) return;\n first.current.model = o.model;\n if (o.model) void client.setModel(o.model).catch(() => {});\n }, [client, o.model]);\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 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 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"],
|
|
5
|
-
"mappings": ";;;;;;;;AAeA,SAAS,eAAe,YAAY,aAAa,WAAW,qBAAqB,QAAQ,gBAAgB;AA8CzG,IAAM,YAAoE;AAAA,EACxE,CAAC,aAAa,aAAa;AAAA,EAC3B,CAAC,SAAS,SAAS;AAAA,EACnB,CAAC,YAAY,YAAY;AAAA,EACzB,CAAC,SAAS,SAAS;AAAA,EACnB,CAAC,OAAO,OAAO;AAAA,EACf,CAAC,aAAa,aAAa;AAAA,EAC3B,CAAC,cAAc,aAAa;AAAA,EAC5B,CAAC,SAAS,SAAS;AAAA,EACnB,CAAC,WAAW,WAAW;AACzB;AAMO,SAAS,YAAY,UAA+B,CAAC,GAAsB;AAChF,QAAM,CAAC,IAAI,KAAK,IAAI,SAA6B,IAAI;AACrD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAkC,IAAI;AAClE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK;AACxC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAgC,IAAI;AAG9D,QAAM,OAAO,OAAO,OAAO;AAC3B,OAAK,UAAU;AAEf,QAAM,IAAI;AACV,QAAM,cAAc,EAAE,kBAAkB,CAAC,GAAG,KAAK,GAAG;AAEpD,YAAU,MAAM;AACd,QAAI,CAAC,GAAI;AACT,UAAM,MAAM,KAAK;AACjB,UAAM,EAAE,aAAa,IAAI,SAAS,IAAI,YAAY,IAAI,SAAS,IAAI,OAAO,IAAI,aAAa,IAAI,aAAa,IAAI,SAAS,IAAI,WAAW,IAAI,QAAQ,IAAI,KAAK,IAAI,gBAAgB,GAAG,OAAO,IAAI;AAC/L,SAAK,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;AAChD,UAAM,OAAO,eAAe,EAAE,GAAG,QAAQ,gBAAgB,gBAAgB,MAAM,GAAG,WAAW,GAAG,CAAC;AACjG,UAAM,OAA0B,CAAC;AACjC,eAAW,CAAC,IAAI,MAAM,KAAK,WAAW;AACpC,WAAK,KAAK,KAAK,GAAG,IAAI,CAAC,MAAe;AAAE,QAAC,KAAK,QAAQ,MAAM,IAA2C,CAAC;AAAA,MAAG,CAAC,CAAC;AAAA,IAC/G;AACA,SAAK,KAAK,KAAK,GAAG,SAAS,MAAM,SAAS,IAAI,CAAC,CAAC;AAChD,SAAK,KAAK,KAAK,GAAG,SAAS,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC;AAC9C,QAAI,IAAI,OAAQ,MAAK,MAAM;AAC3B,QAAI,IAAI,IAAK,MAAK,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACtE,cAAU,IAAI;AACd,WAAO,MAAM;AAEX,WAAK,QAAQ,CAAC,QAAQ,IAAI,CAAC;AAC3B,WAAK,QAAQ;AACb,gBAAU,IAAI;AACd,eAAS,KAAK;AACd,eAAS,IAAI;AAAA,IACf;AAAA,EAGF,GAAG;AAAA,IAAC;AAAA,IAAI,EAAE;AAAA,IAAK,EAAE;AAAA,IAAQ;AAAA,IAAY,EAAE;AAAA,IAAM,EAAE;AAAA,IAAY,EAAE;AAAA,IAAa,EAAE;AAAA,IAAa,EAAE;AAAA,IAAO,EAAE;AAAA,IAAQ,EAAE;AAAA,IAC5G,EAAE;AAAA,IAAW,EAAE;AAAA,IAAI,EAAE;AAAA,IAAO,EAAE;AAAA,IAAU,EAAE;AAAA,IAAW,EAAE;AAAA,IAAa,EAAE;AAAA,IAAS,EAAE;AAAA,IAAkB,EAAE;AAAA,EAAM,CAAC;
|
|
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/width/\u2026) \u53D8\u5316\u4F1A\u91CD\u5EFA\u5B9E\u4F8B; lang / model / paused / mic \u53D8\u5316\u5219\u70ED\u66F4\u65B0 (\u4E0D\u91CD\u5EFA iframe)\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 type { XcConfig, XcExpressionPayload, XcMotionPayload, 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 onError?: (p: XiaochunEvents['error']) => void;\n onDestroy?: () => 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 ['error', 'onError'],\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, paused: _p, mic: _m, allowedOrigins, ...create } = cur;\n void [_a, _b, _c, _d, _e, _f, _g, _h, _i, _p, _m];\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/model/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.width, o.height, o.position,\n o.draggable, o.ui, o.heavy, o.controls, o.autoPause, o.passthrough, o.sandbox, o.handshakeTimeout, o.crossOriginIsolated, o.zIndex]);\n\n // \u70ED\u66F4\u65B0: lang / model (\u8DF3\u8FC7\u9996\u6B21: \u521B\u5EFA\u65F6\u5DF2\u7ECF\u4F5C\u4E3A\u521D\u59CB\u9009\u9879\u4F20\u5165)\n const first = useRef({ lang: o.lang, model: o.model });\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.model === o.model) return;\n first.current.model = o.model;\n if (o.model) void client.setModel(o.model).catch(() => {});\n }, [client, o.model]);\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 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 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"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firetable/project-xiaochun",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Embed Project XiaoChun (3D anime companion) into any web page via a lazy, origin-checked iframe. Zero-dependency SDK + <xiaochun-avatar> web component.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "FireTable",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"files": [
|
|
43
43
|
"dist",
|
|
44
44
|
"README.md",
|
|
45
|
+
"README-CN.md",
|
|
45
46
|
"LICENSE"
|
|
46
47
|
],
|
|
47
48
|
"keywords": [
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/client.ts"],
|
|
4
|
-
"sourcesContent": ["/**\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 normalizeOrigin,\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 XcReadyPayload,\n type XcSttPayload,\n type XcStatePayload,\n type XcUtterancePayload,\n} from './protocol';\n\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 transparent?: boolean;\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 /** \u60AC\u6D6E\u6A21\u5F0F\u4E0B\u5141\u8BB8\u62D6\u52A8 (\u5DE6\u4E0A\u89D2\u624B\u67C4)\u3002 */\n draggable?: boolean;\n lang?: XcLang;\n /** \u521D\u59CB\u670D\u88C5: \u5185\u7F6E key (\u5982 'xiaochun_maid') \u6216 https .vrm/.vrmaddon URL\u3002 */\n model?: string;\n /** \u663E\u793A iframe \u5185\u7F6E ChatBar (\u9ED8\u8BA4 false)\u3002 */\n ui?: boolean;\n heavy?: XcHeavyMode;\n /** \u653E\u5F00 iframe \u5185\u6EDA\u8F6E\u7F29\u653E (\u9ED8\u8BA4\u9501, \u9632\u6B62\u541E\u5BBF\u4E3B\u6EDA\u52A8)\u3002 */\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 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\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 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 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 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 const transparent = options.transparent ?? false;\n const 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.borderRadius = 'var(--xc-radius, 0)';\n ws.boxShadow = 'var(--xc-shadow, none)';\n if (!transparent) ws.background = 'var(--xc-bg, transparent)';\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/\u624B\u67C4\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, 0)';\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 const queue: Array<{ type: XcHostMessageType; payload?: unknown; id?: string; transfer?: Transferable[] }> = [];\n const pending = new Map<string, { resolve: () => 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\n const postToFrame = (type: XcHostMessageType, payload?: unknown, id?: string, transfer?: Transferable[]) => {\n if (!port) { queue.push({ type, payload, id, transfer }); return; }\n port.postMessage(xcMessage(type, payload, id), transfer ?? []);\n };\n\n const send = (type: XcHostMessageType, payload?: unknown, wait = false, transfer?: Transferable[], fixedId?: string): Promise<void> => {\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 const p = wait\n ? new Promise<void>((resolve, reject) => pending.set(id, { resolve, reject, sawEnd: false }))\n : Promise.resolve();\n postToFrame(type, payload, id, transfer);\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 (options.ui) u.searchParams.set('ui', '1');\n if (options.lang) u.searchParams.set('lang', options.lang);\n if (options.heavy) u.searchParams.set('heavy', options.heavy);\n if (options.controls) u.searchParams.set('controls', '1');\n if (options.model) u.searchParams.set('outfit', options.model);\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 = '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, 0)'; // \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 setupPassthrough();\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 // targetOrigin = \u5DF2\u6821\u9A8C\u7684 ev.origin, \u7EDD\u4E0D\u7528 '*'\n iframe.contentWindow!.postMessage(\n xcMessage('xc.init', { hostOrigin: window.location.origin }),\n ev.origin,\n [ch.port2],\n );\n if (handshakeTimer) { clearTimeout(handshakeTimer); handshakeTimer = null; }\n emit('handshake', data.payload as XcReadyPayload);\n for (const m of queue.splice(0)) port.postMessage(xcMessage(m.type, m.payload, m.id), m.transfer ?? []);\n syncPause();\n };\n window.addEventListener('message', onWindowMessage);\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 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.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.error': {\n const { code, message, command } = data.payload;\n emit('error', { code, message, command });\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 let pointerRaf = 0;\n let lastPtr: { x: number; y: number } | null = null;\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 = iframe.getBoundingClientRect();\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 if (lastHit) { lastHit = false; iframe.style.pointerEvents = 'none'; }\n return;\n }\n port.postMessage(xcMessage('xc.pointer', { x, y }));\n });\n };\n function setupPassthrough() {\n if (passthrough) window.addEventListener('pointermove', onHostPointer, { passive: true });\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 \u53EF\u62D6\u52A8\u624B\u67C4 (\u4EC5\u60AC\u6D6E) \u2500\u2500\n let handle: HTMLElement | null = null;\n if (options.draggable && position !== 'inline') {\n handle = document.createElement('div');\n handle.setAttribute('aria-label', 'drag');\n Object.assign(handle.style, {\n position: 'absolute', left: '0', top: '0', width: '28px', height: '28px', cursor: 'grab',\n pointerEvents: 'auto', borderRadius: '8px', background: 'rgba(0,0,0,.25)', color: '#fff',\n font: '14px/28px system-ui', textAlign: 'center', userSelect: 'none', touchAction: 'none', zIndex: '2',\n opacity: '0.5',\n });\n handle.textContent = '\u283F';\n let drag: { dx: number; dy: number } | null = null;\n handle.addEventListener('pointerdown', (e) => {\n const r = wrapper.getBoundingClientRect();\n drag = { dx: e.clientX - r.left, dy: e.clientY - r.top };\n handle!.setPointerCapture(e.pointerId);\n });\n handle.addEventListener('pointermove', (e) => {\n if (!drag) return;\n ws.left = `${Math.min(Math.max(0, e.clientX - drag.dx), window.innerWidth - 40)}px`;\n ws.top = `${Math.min(Math.max(0, e.clientY - drag.dy), window.innerHeight - 40)}px`;\n ws.right = 'auto'; ws.bottom = 'auto';\n });\n const end = () => { drag = null; };\n handle.addEventListener('pointerup', end);\n handle.addEventListener('pointercancel', end);\n wrapper.appendChild(handle);\n }\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 setModel: (m) => send('xc.setModel', typeof m === 'string' ? (/^(https?:)?\\/|\\.vrm/i.test(m) ? { url: m } : { outfit: m }) : m),\n setConfig: (cfg) => send('xc.setConfig', cfg),\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('pointermove', onHostPointer);\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
|
-
"names": ["handle"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/avatar-element.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * avatar-element.ts \u2014 `<xiaochun-avatar>` Web Component (Shadow DOM \u5185\u5305 iframe)\u3002\n *\n * \u5C5E\u6027: src model lang mic transparent draggable position size lazy paused placeholder heavy ui controls allowed-origins\n * - \u5E03\u5C14\u5C5E\u6027: \u7F3A\u7701\u53D6\u9ED8\u8BA4\u503C; \"\" / \"true\" = true; \"false\" = false\u3002\n * - size=\"320x480\" \u6216 size=\"320\" (\u9AD8 = \u5BBD \u00D7 1.5); \u4E5F\u53EF\u5199 CSS \u957F\u5EA6 \"100%x480px\"\u3002\n * - model: \u5185\u7F6E\u670D\u88C5 key (xiaochun_maid) \u6216 https .vrm/.vrmaddon/.vrmbase URL\u3002\n * \u6837\u5F0F (CSS \u81EA\u5B9A\u4E49\u5C5E\u6027, \u53EF\u5199\u5728 <xiaochun-avatar> \u4E0A\u6216\u4EFB\u610F\u7956\u5148\u4E0A; \u53D6\u503C\u8303\u56F4/\u6548\u679C\u89C1 client.ts \u91CC\u7684\u6CE8\u91CA\u4E0E docs/EMBED.md \u00A7\u6837\u5F0F):\n * --xc-radius --xc-shadow --xc-z-index --xc-offset-x --xc-offset-y --xc-bg\n * \u53EF\u7528 ::part() \u5B9A\u5236\u5916\u58F3: ::part(mount) ::part(wrapper) ::part(iframe) ::part(placeholder) (iframe \u5185\u90E8\u4E0D\u53EF\u88AB\u5BBF\u4E3B CSS \u5F71\u54CD)\n * \u4E8B\u4EF6 (CustomEvent, composed, detail = \u534F\u8BAE payload): xc-ready(\u6A21\u578B\u52A0\u8F7D\u5B8C) xc-progress xc-state xc-stt xc-utterance xc-error\n * \u65B9\u6CD5: say(text) speakAudio(source, opts) speakAudioStream(opts) motion(m) expression(name) destroy() (+ client \u5C5E\u6027\u62FF\u5230\u5B8C\u6574 SDK \u5B9E\u4F8B)\n */\nimport {\n createXiaochun,\n type XiaochunAudioOptions,\n type XiaochunAudioSource,\n type XiaochunAudioStream,\n type XiaochunInstance,\n type XiaochunLazy,\n type XiaochunPosition,\n} from './client';\nimport type { XcExpressionPayload, XcHeavyMode, XcLang, XcMotionPayload } from './protocol';\n\nconst OBSERVED = [\n 'src', 'model', 'lang', 'mic', 'transparent', 'draggable', 'position', 'size', 'lazy',\n 'paused', 'placeholder', 'heavy', 'ui', 'controls', 'allowed-origins',\n] as const;\n/** \u6539\u4E86\u8FD9\u4E9B\u8981\u91CD\u5EFA iframe; \u5176\u4F59\u53EF\u4EE5\u70ED\u66F4\u65B0\u3002 */\nconst REBUILD = new Set(['src', 'draggable', 'position', 'size', 'lazy', 'placeholder', 'heavy', 'ui', 'controls', 'allowed-origins', 'transparent']);\n\nfunction boolAttr(el: Element, name: string, dflt: boolean): boolean {\n const v = el.getAttribute(name);\n if (v === null) return dflt;\n return v !== 'false';\n}\n\nfunction parseSize(v: string | null): { width: string; height: string } {\n if (!v) return { width: '320px', height: '480px' };\n const m = v.trim().split(/x/i);\n const px = (s: string) => (/^\\d+(\\.\\d+)?$/.test(s) ? `${s}px` : s);\n if (m.length >= 2) return { width: px(m[0]), height: px(m[1]) };\n const w = parseFloat(m[0]);\n return Number.isFinite(w) && /^\\d+(\\.\\d+)?$/.test(m[0]) ? { width: `${w}px`, height: `${Math.round(w * 1.5)}px` } : { width: m[0], height: '480px' };\n}\n\n/** \u516C\u5F00\u7C7B\u578B (\u7C7B\u672C\u8EAB\u5728\u6D4F\u89C8\u5668\u91CC\u624D\u521B\u5EFA, \u8FD9\u6837 SSR / Node \u4E0B import \u672C\u5305\u4E0D\u4F1A\u56E0 HTMLElement \u7F3A\u5931\u800C\u629B\u9519)\u3002 */\nexport interface XiaochunAvatarElement extends HTMLElement {\n client: XiaochunInstance | null;\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 destroy(): void;\n}\n\nfunction createElementClass(): CustomElementConstructor {\n class XiaochunAvatarElementImpl extends HTMLElement {\n static get observedAttributes() { return [...OBSERVED]; }\n\n /** \u5E95\u5C42 SDK \u5B9E\u4F8B (\u8FDE\u63A5 DOM \u540E\u53EF\u7528)\u3002 */\n client: XiaochunInstance | null = null;\n private mountEl: HTMLDivElement | null = null;\n private rebuildScheduled = false;\n\n connectedCallback(): void {\n if (!this.shadowRoot) {\n const root = this.attachShadow({ mode: 'open' });\n // :host \u9ED8\u8BA4 inline-block + max-width:100% (\u914D\u5408 SDK \u7684\u56FA\u5B9A\u5BBD\u9AD8, \u4E0D\u4F1A\u6491\u7834\u7A84\u5C4F\u5BB9\u5668)\u3002\n // \u60AC\u6D6E (position=bottom-right|bottom-left) \u65F6 SDK \u5185\u90E8\u7528 position:fixed, \u4E0D\u53D7 :host \u76D2\u6A21\u578B\u5F71\u54CD\u3002\n root.innerHTML = '<style>:host{display:inline-block;max-width:100%}:host([hidden]){display:none}</style><div part=\"mount\"></div>';\n }\n this.mountEl = this.shadowRoot!.querySelector('div');\n this.build();\n }\n\n disconnectedCallback(): void {\n this.destroy();\n }\n\n attributeChangedCallback(name: string, oldV: string | null, newV: string | null): void {\n if (!this.client || oldV === newV) return;\n if (REBUILD.has(name)) {\n if (!this.rebuildScheduled) {\n this.rebuildScheduled = true;\n queueMicrotask(() => { this.rebuildScheduled = false; if (this.isConnected) { this.destroy(); this.build(); } });\n }\n return;\n }\n const c = this.client;\n if (name === 'model' && newV) void c.setModel(newV).catch(() => {});\n else if (name === 'lang' && newV) void c.setConfig({ lang: newV as XcLang }).catch(() => {});\n else if (name === 'mic') void c.mic(boolAttr(this, 'mic', false)).catch(() => {});\n else if (name === 'paused') { if (boolAttr(this, 'paused', false)) c.pause(); else c.resume(); }\n }\n\n private build(): void {\n if (!this.mountEl || this.client) return;\n const { width, height } = parseSize(this.getAttribute('size'));\n const placeholder = this.getAttribute('placeholder');\n const allowed = this.getAttribute('allowed-origins');\n const lazyAttr = this.getAttribute('lazy');\n const lazy: XiaochunLazy = lazyAttr === 'click' ? 'click' : lazyAttr === 'false' ? false : true;\n const c = createXiaochun({\n container: this.mountEl,\n src: this.getAttribute('src') || undefined,\n allowedOrigins: allowed ? allowed.split(',').map((s) => s.trim()).filter(Boolean) : undefined,\n lazy,\n placeholder: placeholder === 'none' ? false : placeholder || undefined,\n transparent: boolAttr(this, 'transparent', true), // \u60AC\u6D6E\u5934\u50CF\u9ED8\u8BA4\u900F\u660E\n width, height,\n position: (this.getAttribute('position') as XiaochunPosition | null) ?? 'inline',\n draggable: boolAttr(this, 'draggable', false),\n lang: (this.getAttribute('lang') as XcLang | null) ?? undefined,\n model: this.getAttribute('model') ?? undefined,\n heavy: (this.getAttribute('heavy') as XcHeavyMode | null) ?? undefined,\n ui: boolAttr(this, 'ui', false),\n controls: boolAttr(this, 'controls', false),\n });\n this.client = c;\n const fwd = (ev: string, name: string) => c.on(ev as 'ready', (detail) =>\n this.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true })));\n fwd('ready', 'xc-ready');\n fwd('progress', 'xc-progress');\n fwd('state', 'xc-state');\n fwd('stt', 'xc-stt');\n fwd('utterance', 'xc-utterance');\n fwd('error', 'xc-error');\n if (boolAttr(this, 'paused', false)) c.pause();\n if (boolAttr(this, 'mic', false)) void c.ready.then(() => c.mic(true)).catch(() => {});\n }\n\n say(text: string, opts?: { mode?: 'speak' | 'chat' }): Promise<void> {\n return this.requireClient().say(text, opts);\n }\n speakAudio(source: XiaochunAudioSource, opts?: XiaochunAudioOptions): Promise<void> {\n return this.requireClient().speakAudio(source, opts);\n }\n speakAudioStream(opts: XiaochunAudioOptions & { sampleRate: number }): XiaochunAudioStream {\n return this.requireClient().speakAudioStream(opts);\n }\n motion(m: XcMotionPayload | string): Promise<void> { return this.requireClient().motion(m); }\n expression(name: XcExpressionPayload['name']): Promise<void> { return this.requireClient().expression(name); }\n\n destroy(): void {\n this.client?.destroy();\n this.client = null;\n }\n\n private requireClient(): XiaochunInstance {\n if (!this.client) throw new Error('<xiaochun-avatar> is not connected');\n return this.client;\n }\n }\n\n return XiaochunAvatarElementImpl;\n}\n\nexport const XIAOCHUN_ELEMENT_TAG = 'xiaochun-avatar';\n\n/** \u6CE8\u518C\u81EA\u5B9A\u4E49\u5143\u7D20 (\u5E42\u7B49)\u3002import '@firetable/project-xiaochun/element' \u4F1A\u81EA\u52A8\u8C03\u7528\u3002 */\nexport function defineXiaochunElement(tag: string = XIAOCHUN_ELEMENT_TAG): CustomElementConstructor | null {\n if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') return null;\n const existing = customElements.get(tag);\n if (existing) return existing;\n const ctor = createElementClass();\n customElements.define(tag, ctor);\n return ctor;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|