pixifact 0.3.0 → 0.5.0

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.
Files changed (73) hide show
  1. package/README.md +14 -0
  2. package/dist/compiler/builtinScenes.d.ts +0 -5
  3. package/dist/compiler/builtinScenes.js +0 -26
  4. package/dist/compiler/commands/index.js +8 -5
  5. package/dist/compiler/compileScenes.d.ts +4 -1
  6. package/dist/compiler/compileScenes.js +40 -11
  7. package/dist/compiler/index.d.ts +0 -5
  8. package/dist/compiler/index.js +0 -5
  9. package/dist/compiler/pixiNodeSchema.d.ts +4 -3
  10. package/dist/compiler/pixiNodeSchema.js +60 -6
  11. package/dist/compiler/sceneValidation.d.ts +3 -1
  12. package/dist/compiler/sceneValidation.js +105 -6
  13. package/dist/compiler/spec.d.ts +19 -8
  14. package/dist/compiler/spec.js +3 -1
  15. package/dist/compiler/templateParser.js +19 -0
  16. package/dist/compiler/templateSerializer.js +7 -1
  17. package/dist/compiler/typescriptCompiler.js +118 -51
  18. package/dist/compiler-node/builtinSceneInterfaces.d.ts +6 -0
  19. package/dist/compiler-node/builtinSceneInterfaces.js +27 -0
  20. package/dist/compiler-node/index.d.ts +2 -0
  21. package/dist/compiler-node/index.js +2 -0
  22. package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.d.ts +1 -1
  23. package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.js +157 -25
  24. package/dist/compiler-node/vite.d.ts +2 -1
  25. package/dist/compiler-node/vite.js +29 -2
  26. package/dist/platform/wechat/adapter.d.ts +316 -0
  27. package/dist/platform/wechat/adapter.js +26 -0
  28. package/dist/platform/wechat/application.d.ts +32 -0
  29. package/dist/platform/wechat/application.js +79 -0
  30. package/dist/platform/wechat/fetch.d.ts +1 -0
  31. package/dist/platform/wechat/fetch.js +145 -0
  32. package/dist/platform/wechat/index.d.ts +4 -0
  33. package/dist/platform/wechat/index.js +3 -0
  34. package/dist/platform/wechat/input.d.ts +12 -0
  35. package/dist/platform/wechat/input.js +93 -0
  36. package/dist/platform/wechat/lifecycle.d.ts +14 -0
  37. package/dist/platform/wechat/lifecycle.js +42 -0
  38. package/dist/platform/wechat/runtime.d.ts +49 -0
  39. package/dist/platform/wechat/runtime.js +189 -0
  40. package/dist/platform/wechat/subpackage.d.ts +1 -0
  41. package/dist/platform/wechat/subpackage.js +27 -0
  42. package/dist/platform/wechat/types.d.ts +105 -0
  43. package/dist/platform/wechat/types.js +3 -0
  44. package/dist/project/index.d.ts +23 -0
  45. package/dist/project/index.js +69 -0
  46. package/dist/runtime/BitmapLabel.d.ts +9 -0
  47. package/dist/runtime/BitmapLabel.js +7 -0
  48. package/dist/runtime/Label.d.ts +9 -0
  49. package/dist/runtime/Label.js +7 -0
  50. package/dist/runtime/ScrollContainer.d.ts +2 -0
  51. package/dist/runtime/ScrollContainer.js +12 -2
  52. package/dist/runtime/TextBoxControl.d.ts +48 -0
  53. package/dist/runtime/TextBoxControl.js +162 -0
  54. package/dist/runtime/index.d.ts +2 -0
  55. package/dist/runtime/index.js +2 -0
  56. package/dist/runtime/runtimeBehavior.d.ts +3 -0
  57. package/dist/runtime/runtimeBehavior.js +11 -0
  58. package/dist/{compiler → scene}/decorators.d.ts +2 -1
  59. package/dist/{compiler → scene}/decorators.js +12 -7
  60. package/dist/scene/index.d.ts +6 -0
  61. package/dist/scene/index.js +6 -0
  62. package/dist/scene/sceneAssetRuntime.d.ts +11 -0
  63. package/dist/scene/sceneAssetRuntime.js +43 -0
  64. package/dist/scene/sceneBindingRuntime.d.ts +10 -0
  65. package/dist/scene/sceneBindingRuntime.js +124 -0
  66. package/dist/{compiler → scene}/sceneRuntime.d.ts +7 -0
  67. package/dist/scene/sceneRuntime.js +85 -0
  68. package/package.json +11 -1
  69. package/dist/compiler/sceneRuntime.js +0 -22
  70. /package/dist/{compiler → scene}/eventRuntime.d.ts +0 -0
  71. /package/dist/{compiler → scene}/eventRuntime.js +0 -0
  72. /package/dist/{compiler → scene}/slotRuntime.d.ts +0 -0
  73. /package/dist/{compiler → scene}/slotRuntime.js +0 -0
@@ -0,0 +1,79 @@
1
+ import 'pixi.js/unsafe-eval';
2
+ import 'pixi.js/events';
3
+ import { Container, DOMAdapter, loadTextures, Rectangle, Ticker, UPDATE_PRIORITY, WebGLRenderer, } from 'pixi.js';
4
+ import { createWechatPixiAdapter } from './adapter.js';
5
+ import { bindWechatPointerEvents } from './input.js';
6
+ import { bindWechatLifecycle } from './lifecycle.js';
7
+ import { createWechatRuntime } from './runtime.js';
8
+ export async function createWechatPixiApplication(options = {}) {
9
+ const runtime = createWechatRuntime();
10
+ DOMAdapter.set(createWechatPixiAdapter(runtime));
11
+ loadTextures.config.preferCreateImageBitmap = false;
12
+ const renderer = new WebGLRenderer();
13
+ await renderer.init({
14
+ antialias: options.antialias ?? true,
15
+ autoDensity: false,
16
+ backgroundAlpha: options.backgroundAlpha ?? 1,
17
+ backgroundColor: options.backgroundColor ?? 0x000000,
18
+ canvas: runtime.canvas,
19
+ context: runtime.context,
20
+ eventFeatures: options.eventFeatures ?? {
21
+ click: true,
22
+ globalMove: true,
23
+ move: true,
24
+ wheel: false,
25
+ },
26
+ height: runtime.height,
27
+ resolution: options.resolution ?? runtime.resolution,
28
+ skipExtensionImports: true,
29
+ width: runtime.width,
30
+ });
31
+ const stage = new Container();
32
+ const screen = new Rectangle(0, 0, runtime.width, runtime.height);
33
+ const ticker = new Ticker();
34
+ const render = () => renderer.render(stage);
35
+ const events = renderer.events;
36
+ const sink = {
37
+ pointerdown: (event) => events._onPointerDown(event),
38
+ pointermove: (event) => events._onPointerMove(event),
39
+ pointerup: (event) => events._onPointerUp(event),
40
+ };
41
+ const input = bindWechatPointerEvents(runtime.canvas, sink);
42
+ const lifecycle = bindWechatLifecycle(ticker, {
43
+ onHide: () => {
44
+ input.cancelAll();
45
+ options.onHide?.();
46
+ },
47
+ onShow: options.onShow,
48
+ });
49
+ let destroyed = false;
50
+ ticker.add(render, undefined, UPDATE_PRIORITY.LOW);
51
+ render();
52
+ if (options.autoStart !== false) {
53
+ ticker.start();
54
+ }
55
+ return {
56
+ canvas: runtime.canvas,
57
+ destroy() {
58
+ if (destroyed) {
59
+ return;
60
+ }
61
+ destroyed = true;
62
+ lifecycle.dispose();
63
+ input.dispose();
64
+ ticker.destroy();
65
+ stage.destroy({ children: true });
66
+ renderer.destroy();
67
+ },
68
+ input,
69
+ lifecycle,
70
+ render,
71
+ renderer,
72
+ runtime,
73
+ screen,
74
+ stage,
75
+ start: () => ticker.start(),
76
+ stop: () => ticker.stop(),
77
+ ticker,
78
+ };
79
+ }
@@ -0,0 +1 @@
1
+ export declare function fetchWechatResource(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
@@ -0,0 +1,145 @@
1
+ import { wechatApi } from './types.js';
2
+ class WechatResponseHeaders {
3
+ values;
4
+ constructor(headers) {
5
+ this.values = new Map(Object.entries(headers).map(([name, value]) => [name.toLowerCase(), String(value)]));
6
+ }
7
+ get(name) {
8
+ return this.values.get(name.toLowerCase()) ?? null;
9
+ }
10
+ }
11
+ function decodeUtf8(buffer) {
12
+ const bytes = new Uint8Array(buffer);
13
+ let output = '';
14
+ for (let index = 0; index < bytes.length;) {
15
+ const first = bytes[index++];
16
+ let codePoint;
17
+ if (first < 0x80) {
18
+ codePoint = first;
19
+ }
20
+ else if (first < 0xe0) {
21
+ codePoint = ((first & 0x1f) << 6) | (bytes[index++] & 0x3f);
22
+ }
23
+ else if (first < 0xf0) {
24
+ codePoint = ((first & 0x0f) << 12)
25
+ | ((bytes[index++] & 0x3f) << 6)
26
+ | (bytes[index++] & 0x3f);
27
+ }
28
+ else {
29
+ codePoint = ((first & 0x07) << 18)
30
+ | ((bytes[index++] & 0x3f) << 12)
31
+ | ((bytes[index++] & 0x3f) << 6)
32
+ | (bytes[index++] & 0x3f);
33
+ }
34
+ output += String.fromCodePoint(codePoint);
35
+ }
36
+ return output;
37
+ }
38
+ function encodeUtf8(value) {
39
+ const bytes = [];
40
+ for (const character of value) {
41
+ const codePoint = character.codePointAt(0);
42
+ if (codePoint < 0x80) {
43
+ bytes.push(codePoint);
44
+ }
45
+ else if (codePoint < 0x800) {
46
+ bytes.push(0xc0 | (codePoint >> 6), 0x80 | (codePoint & 0x3f));
47
+ }
48
+ else if (codePoint < 0x10000) {
49
+ bytes.push(0xe0 | (codePoint >> 12), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
50
+ }
51
+ else {
52
+ bytes.push(0xf0 | (codePoint >> 18), 0x80 | ((codePoint >> 12) & 0x3f), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
53
+ }
54
+ }
55
+ return new Uint8Array(bytes).buffer;
56
+ }
57
+ class WechatResourceResponse {
58
+ responseBody;
59
+ status;
60
+ url;
61
+ body = null;
62
+ bodyUsed = false;
63
+ ok;
64
+ redirected = false;
65
+ statusText = '';
66
+ type = 'basic';
67
+ headers;
68
+ constructor(responseBody, status, url, responseHeaders = {}) {
69
+ this.responseBody = responseBody;
70
+ this.status = status;
71
+ this.url = url;
72
+ this.ok = status >= 200 && status < 300;
73
+ this.headers = new WechatResponseHeaders(responseHeaders);
74
+ }
75
+ async arrayBuffer() {
76
+ return typeof this.responseBody === 'string'
77
+ ? encodeUtf8(this.responseBody)
78
+ : this.responseBody.slice(0);
79
+ }
80
+ async blob() {
81
+ throw new Error('Blob responses are not supported by the WeChat resource adapter.');
82
+ }
83
+ clone() {
84
+ const body = typeof this.responseBody === 'string'
85
+ ? this.responseBody
86
+ : this.responseBody.slice(0);
87
+ return new WechatResourceResponse(body, this.status, this.url);
88
+ }
89
+ async formData() {
90
+ throw new Error('FormData responses are not supported by the WeChat resource adapter.');
91
+ }
92
+ async json() {
93
+ return JSON.parse((await this.text()).replace(/^\uFEFF/, ''));
94
+ }
95
+ async text() {
96
+ return typeof this.responseBody === 'string'
97
+ ? this.responseBody
98
+ : decodeUtf8(this.responseBody);
99
+ }
100
+ }
101
+ function toResponseBody(data) {
102
+ if (data instanceof ArrayBuffer) {
103
+ return data;
104
+ }
105
+ if (ArrayBuffer.isView(data)) {
106
+ return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
107
+ }
108
+ return typeof data === 'string' ? data : JSON.stringify(data);
109
+ }
110
+ function requestUrl(input) {
111
+ return typeof input === 'string' ? input : (input.url ?? String(input));
112
+ }
113
+ function localPath(url) {
114
+ const suffix = url.search(/[?#]/);
115
+ return (suffix >= 0 ? url.slice(0, suffix) : url).replace(/^(\.\/)+/, '');
116
+ }
117
+ export function fetchWechatResource(input, init = {}) {
118
+ const method = (init.method ?? 'GET').toUpperCase();
119
+ const url = requestUrl(input);
120
+ if (method !== 'GET') {
121
+ return Promise.reject(new Error(`The WeChat resource adapter only supports GET requests, received ${method}.`));
122
+ }
123
+ if (init.signal?.aborted) {
124
+ return Promise.reject(new Error(`Resource request was aborted: ${url}`));
125
+ }
126
+ const wx = wechatApi();
127
+ if (/^https?:\/\//i.test(url)) {
128
+ return new Promise((resolve, reject) => wx.request({
129
+ url,
130
+ method: 'GET',
131
+ responseType: 'arraybuffer',
132
+ fail: (error) => reject(new Error(`Failed to request ${url}: ${error.errMsg}`)),
133
+ success: (result) => resolve(new WechatResourceResponse(toResponseBody(result.data), result.statusCode, url, result.header)),
134
+ }));
135
+ }
136
+ if (/^data:/i.test(url)) {
137
+ return Promise.reject(new Error('Data URLs are not supported by the WeChat resource adapter.'));
138
+ }
139
+ const filePath = localPath(url);
140
+ return new Promise((resolve, reject) => wx.getFileSystemManager().readFile({
141
+ filePath,
142
+ fail: (error) => reject(new Error(`Failed to read ${filePath}: ${error.errMsg}`)),
143
+ success: (result) => resolve(new WechatResourceResponse(toResponseBody(result.data), 200, url)),
144
+ }));
145
+ }
@@ -0,0 +1,4 @@
1
+ export * from './application.js';
2
+ export * from './fetch.js';
3
+ export * from './subpackage.js';
4
+ export type { WechatCanvas, WechatMiniGameApi } from './types.js';
@@ -0,0 +1,3 @@
1
+ export * from './application.js';
2
+ export * from './fetch.js';
3
+ export * from './subpackage.js';
@@ -0,0 +1,12 @@
1
+ import { type WechatCanvas } from './types.js';
2
+ export interface WechatPointerEventSink {
3
+ pointerdown(event: Event): void;
4
+ pointermove(event: Event): void;
5
+ pointerup(event: Event): void;
6
+ }
7
+ export interface WechatPointerBinding {
8
+ readonly activePointerCount: number;
9
+ cancelAll(): void;
10
+ dispose(): void;
11
+ }
12
+ export declare function bindWechatPointerEvents(canvas: WechatCanvas, sink: WechatPointerEventSink): WechatPointerBinding;
@@ -0,0 +1,93 @@
1
+ import { WechatPointerEvent } from './runtime.js';
2
+ import { wechatApi } from './types.js';
3
+ function pointerState(touch) {
4
+ return {
5
+ force: touch.force ?? 0.5,
6
+ pointerId: (touch.identifier ?? 0) + 1,
7
+ x: touch.clientX ?? touch.x ?? touch.pageX ?? 0,
8
+ y: touch.clientY ?? touch.y ?? touch.pageY ?? 0,
9
+ };
10
+ }
11
+ function changedTouches(event) {
12
+ return event.changedTouches?.length ? event.changedTouches : event.touches ?? [];
13
+ }
14
+ export function bindWechatPointerEvents(canvas, sink) {
15
+ const wx = wechatApi();
16
+ const activePointers = new Map();
17
+ let disposed = false;
18
+ let primaryPointerId = null;
19
+ const dispatch = (type, state, eventTarget, buttons) => {
20
+ const event = new WechatPointerEvent(type, {
21
+ button: 0,
22
+ buttons,
23
+ clientX: state.x,
24
+ clientY: state.y,
25
+ height: 1,
26
+ isPrimary: state.pointerId === primaryPointerId,
27
+ pointerId: state.pointerId,
28
+ pointerType: 'touch',
29
+ pressure: buttons ? state.force : 0,
30
+ width: 1,
31
+ });
32
+ event.target = eventTarget;
33
+ event.srcElement = canvas;
34
+ event.isTrusted = true;
35
+ sink[type](event);
36
+ };
37
+ const handleStart = (event) => {
38
+ for (const touch of changedTouches(event)) {
39
+ const state = pointerState(touch);
40
+ primaryPointerId ??= state.pointerId;
41
+ activePointers.set(state.pointerId, state);
42
+ dispatch('pointerdown', state, canvas, 1);
43
+ }
44
+ };
45
+ const handleMove = (event) => {
46
+ for (const touch of changedTouches(event)) {
47
+ const state = pointerState(touch);
48
+ activePointers.set(state.pointerId, state);
49
+ dispatch('pointermove', state, canvas, 1);
50
+ }
51
+ };
52
+ const release = (event, cancelled) => {
53
+ const touches = event.changedTouches?.length
54
+ ? event.changedTouches.map(pointerState)
55
+ : [...activePointers.values()];
56
+ for (const state of touches) {
57
+ dispatch('pointerup', state, cancelled ? globalThis : canvas, 0);
58
+ activePointers.delete(state.pointerId);
59
+ }
60
+ if (primaryPointerId !== null && !activePointers.has(primaryPointerId)) {
61
+ primaryPointerId = activePointers.keys().next().value ?? null;
62
+ }
63
+ };
64
+ const handleEnd = (event) => release(event, false);
65
+ const handleCancel = (event) => release(event, true);
66
+ wx.onTouchStart(handleStart);
67
+ wx.onTouchMove(handleMove);
68
+ wx.onTouchEnd(handleEnd);
69
+ wx.onTouchCancel(handleCancel);
70
+ return {
71
+ get activePointerCount() {
72
+ return activePointers.size;
73
+ },
74
+ cancelAll() {
75
+ for (const state of activePointers.values()) {
76
+ dispatch('pointerup', state, globalThis, 0);
77
+ }
78
+ activePointers.clear();
79
+ primaryPointerId = null;
80
+ },
81
+ dispose() {
82
+ if (disposed) {
83
+ return;
84
+ }
85
+ disposed = true;
86
+ this.cancelAll();
87
+ wx.offTouchStart?.(handleStart);
88
+ wx.offTouchMove?.(handleMove);
89
+ wx.offTouchEnd?.(handleEnd);
90
+ wx.offTouchCancel?.(handleCancel);
91
+ },
92
+ };
93
+ }
@@ -0,0 +1,14 @@
1
+ interface LifecycleTarget {
2
+ readonly started?: boolean;
3
+ start(): void;
4
+ stop(): void;
5
+ }
6
+ export interface WechatLifecycleBinding {
7
+ dispose(): void;
8
+ readonly hidden: boolean;
9
+ }
10
+ export declare function bindWechatLifecycle(target: LifecycleTarget, options?: {
11
+ onHide?(): void;
12
+ onShow?(): void;
13
+ }): WechatLifecycleBinding;
14
+ export {};
@@ -0,0 +1,42 @@
1
+ import { wechatApi } from './types.js';
2
+ export function bindWechatLifecycle(target, options = {}) {
3
+ const wx = wechatApi();
4
+ let disposed = false;
5
+ let hidden = false;
6
+ let resumeOnShow = false;
7
+ const handleHide = () => {
8
+ if (disposed || hidden) {
9
+ return;
10
+ }
11
+ hidden = true;
12
+ resumeOnShow = target.started ?? true;
13
+ options.onHide?.();
14
+ target.stop();
15
+ };
16
+ const handleShow = () => {
17
+ if (disposed || !hidden) {
18
+ return;
19
+ }
20
+ hidden = false;
21
+ if (resumeOnShow) {
22
+ target.start();
23
+ }
24
+ options.onShow?.();
25
+ };
26
+ wx.onHide(handleHide);
27
+ wx.onShow(handleShow);
28
+ return {
29
+ dispose() {
30
+ if (disposed) {
31
+ return;
32
+ }
33
+ disposed = true;
34
+ target.stop();
35
+ wx.offHide?.(handleHide);
36
+ wx.offShow?.(handleShow);
37
+ },
38
+ get hidden() {
39
+ return hidden;
40
+ },
41
+ };
42
+ }
@@ -0,0 +1,49 @@
1
+ import { type WechatCanvas } from './types.js';
2
+ export interface WechatRuntime {
3
+ canvas: WechatCanvas;
4
+ context: WebGLRenderingContext | WebGL2RenderingContext;
5
+ height: number;
6
+ resolution: number;
7
+ userAgent: string;
8
+ webGLVersion: 1 | 2;
9
+ width: number;
10
+ }
11
+ export declare class WechatPointerEvent {
12
+ altKey: boolean;
13
+ bubbles: boolean;
14
+ button: number;
15
+ buttons: number;
16
+ cancelBubble: boolean;
17
+ cancelable: boolean;
18
+ clientX: number;
19
+ clientY: number;
20
+ ctrlKey: boolean;
21
+ defaultPrevented: boolean;
22
+ height: number;
23
+ isPrimary: boolean;
24
+ isTrusted: boolean;
25
+ metaKey: boolean;
26
+ movementX: number;
27
+ movementY: number;
28
+ pageX: number;
29
+ pageY: number;
30
+ pointerId: number;
31
+ pointerType: string;
32
+ pressure: number;
33
+ relatedTarget: EventTarget | null;
34
+ shiftKey: boolean;
35
+ srcElement: EventTarget | null;
36
+ tangentialPressure: number;
37
+ target: EventTarget | null;
38
+ tiltX: number;
39
+ tiltY: number;
40
+ twist: number;
41
+ type: string;
42
+ width: number;
43
+ constructor(type: string, init?: PointerEventInit);
44
+ composedPath(): EventTarget[];
45
+ preventDefault(): void;
46
+ stopImmediatePropagation(): void;
47
+ stopPropagation(): void;
48
+ }
49
+ export declare function createWechatRuntime(): WechatRuntime;
@@ -0,0 +1,189 @@
1
+ import { wechatApi } from './types.js';
2
+ export class WechatPointerEvent {
3
+ altKey = false;
4
+ bubbles = true;
5
+ button = 0;
6
+ buttons = 0;
7
+ cancelBubble = false;
8
+ cancelable = true;
9
+ clientX = 0;
10
+ clientY = 0;
11
+ ctrlKey = false;
12
+ defaultPrevented = false;
13
+ height = 1;
14
+ isPrimary = false;
15
+ isTrusted = false;
16
+ metaKey = false;
17
+ movementX = 0;
18
+ movementY = 0;
19
+ pageX = 0;
20
+ pageY = 0;
21
+ pointerId = 0;
22
+ pointerType = '';
23
+ pressure = 0;
24
+ relatedTarget = null;
25
+ shiftKey = false;
26
+ srcElement = null;
27
+ tangentialPressure = 0;
28
+ target = null;
29
+ tiltX = 0;
30
+ tiltY = 0;
31
+ twist = 0;
32
+ type;
33
+ width = 1;
34
+ constructor(type, init = {}) {
35
+ this.type = type;
36
+ Object.assign(this, init);
37
+ this.pageX = this.clientX;
38
+ this.pageY = this.clientY;
39
+ }
40
+ composedPath() {
41
+ return this.target ? [this.target] : [];
42
+ }
43
+ preventDefault() {
44
+ this.defaultPrevented = true;
45
+ }
46
+ stopImmediatePropagation() {
47
+ this.cancelBubble = true;
48
+ }
49
+ stopPropagation() {
50
+ this.cancelBubble = true;
51
+ }
52
+ }
53
+ function installEventTarget(target, nativeTypes = new Set()) {
54
+ const listeners = new Map();
55
+ const nativeAdd = target.addEventListener?.bind(target);
56
+ const nativeRemove = target.removeEventListener?.bind(target);
57
+ target.addEventListener = (type, listener, options) => {
58
+ const typeListeners = listeners.get(type) ?? new Set();
59
+ typeListeners.add(listener);
60
+ listeners.set(type, typeListeners);
61
+ if (nativeTypes.has(type)) {
62
+ nativeAdd?.(type, listener, options);
63
+ }
64
+ };
65
+ target.removeEventListener = (type, listener, options) => {
66
+ listeners.get(type)?.delete(listener);
67
+ if (nativeTypes.has(type)) {
68
+ nativeRemove?.(type, listener, options);
69
+ }
70
+ };
71
+ target.dispatchEvent = (event) => {
72
+ const mutableEvent = event;
73
+ mutableEvent.target ??= target;
74
+ mutableEvent.srcElement ??= mutableEvent.target;
75
+ for (const listener of listeners.get(event.type) ?? []) {
76
+ if (typeof listener === 'function') {
77
+ listener.call(target, event);
78
+ }
79
+ else {
80
+ listener.handleEvent(event);
81
+ }
82
+ if (mutableEvent.cancelBubble) {
83
+ break;
84
+ }
85
+ }
86
+ return !event.defaultPrevented;
87
+ };
88
+ }
89
+ function installCanvasSurface(canvas, width, height) {
90
+ installEventTarget(canvas, new Set(['webglcontextlost', 'webglcontextrestored']));
91
+ canvas.style ??= {};
92
+ Object.defineProperty(canvas, 'isConnected', { configurable: true, value: true });
93
+ Object.defineProperty(canvas, 'getBoundingClientRect', {
94
+ configurable: true,
95
+ value: () => ({
96
+ bottom: height,
97
+ height,
98
+ left: 0,
99
+ right: width,
100
+ top: 0,
101
+ width,
102
+ x: 0,
103
+ y: 0,
104
+ }),
105
+ });
106
+ }
107
+ function createDocumentElement(tagName) {
108
+ const wx = wechatApi();
109
+ if (tagName.toLowerCase() === 'canvas') {
110
+ const canvas = wx.createOffscreenCanvas?.({ type: '2d', width: 1, height: 1 }) ?? wx.createCanvas();
111
+ canvas.width = 1;
112
+ canvas.height = 1;
113
+ return canvas;
114
+ }
115
+ if (tagName.toLowerCase() === 'video') {
116
+ return { canPlayType: () => '' };
117
+ }
118
+ return {};
119
+ }
120
+ function installGlobals(canvas, userAgent) {
121
+ const globals = globalThis;
122
+ const mutableGlobals = globals;
123
+ installEventTarget(mutableGlobals);
124
+ const documentTarget = (globals.document ?? {});
125
+ installEventTarget(documentTarget);
126
+ documentTarget.createElement ??= createDocumentElement;
127
+ if (!globals.document) {
128
+ Object.defineProperty(globals, 'document', { configurable: true, value: documentTarget });
129
+ }
130
+ if (!globals.PointerEvent) {
131
+ Object.defineProperty(globals, 'PointerEvent', { configurable: true, value: WechatPointerEvent });
132
+ }
133
+ if (!globals.navigator) {
134
+ Object.defineProperty(globals, 'navigator', {
135
+ configurable: true,
136
+ value: { gpu: null, userAgent },
137
+ });
138
+ }
139
+ if (!globals.performance) {
140
+ Object.defineProperty(globals, 'performance', {
141
+ configurable: true,
142
+ value: { now: () => Date.now() },
143
+ });
144
+ }
145
+ globals.requestAnimationFrame ??= canvas.requestAnimationFrame
146
+ ? canvas.requestAnimationFrame.bind(canvas)
147
+ : (callback) => setTimeout(() => callback(performance.now()), 16);
148
+ globals.cancelAnimationFrame ??= canvas.cancelAnimationFrame
149
+ ? canvas.cancelAnimationFrame.bind(canvas)
150
+ : (requestId) => clearTimeout(requestId);
151
+ }
152
+ function createContext(canvas) {
153
+ const attributes = {
154
+ alpha: false,
155
+ antialias: true,
156
+ powerPreference: 'high-performance',
157
+ premultipliedAlpha: true,
158
+ preserveDrawingBuffer: false,
159
+ stencil: true,
160
+ };
161
+ const webGL2 = canvas.getContext('webgl2', attributes);
162
+ if (webGL2) {
163
+ return { context: webGL2, webGLVersion: 2 };
164
+ }
165
+ const webGL1 = canvas.getContext('webgl', attributes);
166
+ if (webGL1) {
167
+ return { context: webGL1, webGLVersion: 1 };
168
+ }
169
+ throw new Error('The current WeChat Mini Game runtime does not provide WebGL.');
170
+ }
171
+ export function createWechatRuntime() {
172
+ const wx = wechatApi();
173
+ const canvas = wx.createCanvas();
174
+ const info = {
175
+ ...(wx.getSystemInfoSync?.() ?? {}),
176
+ ...(wx.getDeviceInfo?.() ?? {}),
177
+ ...(wx.getWindowInfo?.() ?? {}),
178
+ };
179
+ const width = Math.max(1, Math.round(Number(info.windowWidth ?? info.screenWidth)));
180
+ const height = Math.max(1, Math.round(Number(info.windowHeight ?? info.screenHeight)));
181
+ const resolution = Math.min(2, Math.max(1, Number(info.pixelRatio)));
182
+ const userAgent = ['WeChatMiniGame', info.platform, info.system, info.model]
183
+ .filter(Boolean)
184
+ .join('/');
185
+ installCanvasSurface(canvas, width, height);
186
+ installGlobals(canvas, userAgent);
187
+ const { context, webGLVersion } = createContext(canvas);
188
+ return { canvas, context, height, resolution, userAgent, webGLVersion, width };
189
+ }
@@ -0,0 +1 @@
1
+ export declare function loadWechatSubpackage(name: string): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import { wechatApi } from './types.js';
2
+ const loaded = new Set();
3
+ const loading = new Map();
4
+ export function loadWechatSubpackage(name) {
5
+ if (loaded.has(name)) {
6
+ return Promise.resolve();
7
+ }
8
+ const existing = loading.get(name);
9
+ if (existing) {
10
+ return existing;
11
+ }
12
+ const pending = new Promise((resolve, reject) => {
13
+ wechatApi().loadSubpackage({
14
+ name,
15
+ fail: (error) => reject(new Error(`Failed to load WeChat subpackage ${name}: ${error.errMsg}`)),
16
+ success: resolve,
17
+ });
18
+ }).then(() => {
19
+ loaded.add(name);
20
+ loading.delete(name);
21
+ }, (error) => {
22
+ loading.delete(name);
23
+ throw error;
24
+ });
25
+ loading.set(name, pending);
26
+ return pending;
27
+ }