pixifact 0.1.3

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 (168) hide show
  1. package/README.md +44 -0
  2. package/dist/authoring/ActionRegistry.d.ts +10 -0
  3. package/dist/authoring/ActionRegistry.js +26 -0
  4. package/dist/authoring/ComponentPalette.d.ts +16 -0
  5. package/dist/authoring/ComponentPalette.js +50 -0
  6. package/dist/authoring/DesignToken.d.ts +16 -0
  7. package/dist/authoring/DesignToken.js +33 -0
  8. package/dist/authoring/DiffModel.d.ts +10 -0
  9. package/dist/authoring/DiffModel.js +104 -0
  10. package/dist/authoring/InspectorModel.d.ts +27 -0
  11. package/dist/authoring/InspectorModel.js +139 -0
  12. package/dist/authoring/LogicGraph.d.ts +66 -0
  13. package/dist/authoring/LogicGraph.js +184 -0
  14. package/dist/authoring/OverrideJournal.d.ts +18 -0
  15. package/dist/authoring/OverrideJournal.js +23 -0
  16. package/dist/authoring/PreferenceMemory.d.ts +21 -0
  17. package/dist/authoring/PreferenceMemory.js +39 -0
  18. package/dist/authoring/ProjectConfig.d.ts +20 -0
  19. package/dist/authoring/ProjectConfig.js +78 -0
  20. package/dist/authoring/RuntimePreview.d.ts +11 -0
  21. package/dist/authoring/RuntimePreview.js +25 -0
  22. package/dist/authoring/SceneDocument.d.ts +74 -0
  23. package/dist/authoring/SceneDocument.js +332 -0
  24. package/dist/authoring/SceneProjectState.d.ts +20 -0
  25. package/dist/authoring/SceneProjectState.js +8 -0
  26. package/dist/authoring/SceneSelection.d.ts +11 -0
  27. package/dist/authoring/SceneSelection.js +1 -0
  28. package/dist/authoring/index.d.ts +13 -0
  29. package/dist/authoring/index.js +13 -0
  30. package/dist/commands/Command.d.ts +63 -0
  31. package/dist/commands/Command.js +1 -0
  32. package/dist/commands/CommandStack.d.ts +14 -0
  33. package/dist/commands/CommandStack.js +45 -0
  34. package/dist/commands/applyCommand.d.ts +23 -0
  35. package/dist/commands/applyCommand.js +316 -0
  36. package/dist/commands/index.d.ts +4 -0
  37. package/dist/commands/index.js +4 -0
  38. package/dist/commands/utils.d.ts +17 -0
  39. package/dist/commands/utils.js +77 -0
  40. package/dist/commands/validateCommand.d.ts +12 -0
  41. package/dist/commands/validateCommand.js +285 -0
  42. package/dist/compiler/commands/index.d.ts +109 -0
  43. package/dist/compiler/commands/index.js +492 -0
  44. package/dist/compiler/compileScenes.d.ts +11 -0
  45. package/dist/compiler/compileScenes.js +220 -0
  46. package/dist/compiler/decorators.d.ts +6 -0
  47. package/dist/compiler/decorators.js +79 -0
  48. package/dist/compiler/eventRuntime.d.ts +8 -0
  49. package/dist/compiler/eventRuntime.js +29 -0
  50. package/dist/compiler/index.d.ts +14 -0
  51. package/dist/compiler/index.js +14 -0
  52. package/dist/compiler/pixiNodeSchema.d.ts +39 -0
  53. package/dist/compiler/pixiNodeSchema.js +267 -0
  54. package/dist/compiler/sceneAssetPair.d.ts +11 -0
  55. package/dist/compiler/sceneAssetPair.js +92 -0
  56. package/dist/compiler/scenePartValidation.d.ts +6 -0
  57. package/dist/compiler/scenePartValidation.js +24 -0
  58. package/dist/compiler/sceneRuntime.d.ts +13 -0
  59. package/dist/compiler/sceneRuntime.js +22 -0
  60. package/dist/compiler/sceneValidation.d.ts +48 -0
  61. package/dist/compiler/sceneValidation.js +383 -0
  62. package/dist/compiler/scriptInterfaceExtractor.d.ts +6 -0
  63. package/dist/compiler/scriptInterfaceExtractor.js +258 -0
  64. package/dist/compiler/slotRuntime.d.ts +3 -0
  65. package/dist/compiler/slotRuntime.js +17 -0
  66. package/dist/compiler/spec.d.ts +95 -0
  67. package/dist/compiler/spec.js +1 -0
  68. package/dist/compiler/templateParser.d.ts +2 -0
  69. package/dist/compiler/templateParser.js +302 -0
  70. package/dist/compiler/templateSerializer.d.ts +2 -0
  71. package/dist/compiler/templateSerializer.js +101 -0
  72. package/dist/compiler/typescriptCompiler.d.ts +2 -0
  73. package/dist/compiler/typescriptCompiler.js +494 -0
  74. package/dist/compiler-node/index.d.ts +2 -0
  75. package/dist/compiler-node/index.js +2 -0
  76. package/dist/compiler-node/vite.d.ts +8 -0
  77. package/dist/compiler-node/vite.js +21 -0
  78. package/dist/index.d.ts +6 -0
  79. package/dist/index.js +6 -0
  80. package/dist/nodes/Input.d.ts +91 -0
  81. package/dist/nodes/Input.js +352 -0
  82. package/dist/nodes/Textarea.d.ts +10 -0
  83. package/dist/nodes/Textarea.js +38 -0
  84. package/dist/nodes/components/Button.d.ts +8 -0
  85. package/dist/nodes/components/Button.js +45 -0
  86. package/dist/nodes/components/InputField.d.ts +12 -0
  87. package/dist/nodes/components/InputField.js +53 -0
  88. package/dist/nodes/components/ProgressBar.d.ts +14 -0
  89. package/dist/nodes/components/ProgressBar.js +66 -0
  90. package/dist/nodes/components/ScrollRect.d.ts +23 -0
  91. package/dist/nodes/components/ScrollRect.js +108 -0
  92. package/dist/nodes/components/Selectable.d.ts +32 -0
  93. package/dist/nodes/components/Selectable.js +153 -0
  94. package/dist/nodes/components/index.d.ts +5 -0
  95. package/dist/nodes/components/index.js +5 -0
  96. package/dist/nodes/graphics/Graphic.d.ts +14 -0
  97. package/dist/nodes/graphics/Graphic.js +47 -0
  98. package/dist/nodes/graphics/ImageGraphic.d.ts +9 -0
  99. package/dist/nodes/graphics/ImageGraphic.js +42 -0
  100. package/dist/nodes/graphics/RoundedRectGraphic.d.ts +13 -0
  101. package/dist/nodes/graphics/RoundedRectGraphic.js +65 -0
  102. package/dist/nodes/graphics/TextGraphic.d.ts +13 -0
  103. package/dist/nodes/graphics/TextGraphic.js +70 -0
  104. package/dist/nodes/graphics/index.d.ts +4 -0
  105. package/dist/nodes/graphics/index.js +4 -0
  106. package/dist/nodes/index.d.ts +3 -0
  107. package/dist/nodes/index.js +3 -0
  108. package/dist/runtime/Application.d.ts +15 -0
  109. package/dist/runtime/Application.js +67 -0
  110. package/dist/runtime/GameObject.d.ts +100 -0
  111. package/dist/runtime/GameObject.js +297 -0
  112. package/dist/runtime/GameObjectEvent.d.ts +52 -0
  113. package/dist/runtime/GameObjectEvent.js +38 -0
  114. package/dist/runtime/Transform.d.ts +32 -0
  115. package/dist/runtime/Transform.js +157 -0
  116. package/dist/runtime/component/Component.d.ts +13 -0
  117. package/dist/runtime/component/Component.js +13 -0
  118. package/dist/runtime/component/ComponentRegistry.d.ts +49 -0
  119. package/dist/runtime/component/ComponentRegistry.js +25 -0
  120. package/dist/runtime/component/Flex.d.ts +6 -0
  121. package/dist/runtime/component/Flex.js +15 -0
  122. package/dist/runtime/component/FlexGroup.d.ts +26 -0
  123. package/dist/runtime/component/FlexGroup.js +136 -0
  124. package/dist/runtime/component/GridLayout.d.ts +47 -0
  125. package/dist/runtime/component/GridLayout.js +129 -0
  126. package/dist/runtime/component/Layout.d.ts +104 -0
  127. package/dist/runtime/component/Layout.js +248 -0
  128. package/dist/runtime/component/decorators.d.ts +4 -0
  129. package/dist/runtime/component/decorators.js +52 -0
  130. package/dist/runtime/component/index.d.ts +7 -0
  131. package/dist/runtime/component/index.js +7 -0
  132. package/dist/runtime/graphics/index.d.ts +11 -0
  133. package/dist/runtime/graphics/index.js +29 -0
  134. package/dist/runtime/group/index.d.ts +39 -0
  135. package/dist/runtime/group/index.js +102 -0
  136. package/dist/runtime/image/Image.d.ts +19 -0
  137. package/dist/runtime/image/Image.js +60 -0
  138. package/dist/runtime/image/NineSliceImage.d.ts +23 -0
  139. package/dist/runtime/image/NineSliceImage.js +64 -0
  140. package/dist/runtime/image/index.d.ts +2 -0
  141. package/dist/runtime/image/index.js +2 -0
  142. package/dist/runtime/index.d.ts +9 -0
  143. package/dist/runtime/index.js +9 -0
  144. package/dist/runtime/label/Label.d.ts +11 -0
  145. package/dist/runtime/label/Label.js +26 -0
  146. package/dist/runtime/label/LabelStyle.d.ts +3 -0
  147. package/dist/runtime/label/LabelStyle.js +3 -0
  148. package/dist/runtime/label/index.d.ts +2 -0
  149. package/dist/runtime/label/index.js +2 -0
  150. package/dist/runtime/utils/index.d.ts +1 -0
  151. package/dist/runtime/utils/index.js +1 -0
  152. package/dist/runtime/utils/onlyOnceQueueMicrotask.d.ts +1 -0
  153. package/dist/runtime/utils/onlyOnceQueueMicrotask.js +12 -0
  154. package/dist/runtime/utils/setProps.d.ts +10 -0
  155. package/dist/runtime/utils/setProps.js +17 -0
  156. package/dist/scene/dsl.d.ts +25 -0
  157. package/dist/scene/dsl.js +112 -0
  158. package/dist/scene/index.d.ts +5 -0
  159. package/dist/scene/index.js +5 -0
  160. package/dist/scene/instantiate.d.ts +8 -0
  161. package/dist/scene/instantiate.js +208 -0
  162. package/dist/scene/nodesDsl.d.ts +42 -0
  163. package/dist/scene/nodesDsl.js +169 -0
  164. package/dist/scene/spec.d.ts +100 -0
  165. package/dist/scene/spec.js +1 -0
  166. package/dist/scene/templates.d.ts +21 -0
  167. package/dist/scene/templates.js +239 -0
  168. package/package.json +90 -0
@@ -0,0 +1,101 @@
1
+ const colorPropNames = new Set([
2
+ 'backgroundColor',
3
+ 'borderColor',
4
+ 'disabledColor',
5
+ 'fill',
6
+ 'highlightedColor',
7
+ 'normalColor',
8
+ 'pressedColor',
9
+ 'strokeColor',
10
+ 'textColor',
11
+ 'tint',
12
+ ]);
13
+ export function serializeSceneTemplate(template) {
14
+ const rootAttributes = [
15
+ ['name', template.name],
16
+ ...Object.entries(template.props),
17
+ ];
18
+ const lines = [`<Scene${serializeAttributes(rootAttributes)}>`];
19
+ for (const child of template.children) {
20
+ lines.push(...serializeTemplateNode(child, 1));
21
+ }
22
+ lines.push('</Scene>');
23
+ return `${lines.join('\n')}\n`;
24
+ }
25
+ function serializeTemplateNode(node, depth, extraAttributes = []) {
26
+ if (node.kind === 'slotOutlet') {
27
+ const attributes = [
28
+ ...(node.name === 'default' ? [] : [['name', node.name]]),
29
+ ...extraAttributes,
30
+ ];
31
+ return [`${indent(depth)}<slot${serializeAttributes(attributes)} />`];
32
+ }
33
+ if (node.kind === 'pixi') {
34
+ const attributes = [
35
+ ...(node.id ? [['id', node.id]] : []),
36
+ ...extraAttributes,
37
+ ...Object.entries(node.props),
38
+ ];
39
+ return serializeElement(node.type, attributes, node.children, depth);
40
+ }
41
+ const attributes = [
42
+ ...(node.id ? [['id', node.id]] : []),
43
+ ['scene', node.scene],
44
+ ...extraAttributes,
45
+ ...Object.entries(node.props),
46
+ ...Object.entries(node.events).map(([name, value]) => [`@${name}`, value]),
47
+ ];
48
+ return serializeElement(node.type, attributes, serializeSceneInstanceChildren(node), depth);
49
+ }
50
+ function serializeSceneInstanceChildren(node) {
51
+ return Object.entries(node.slots).flatMap(([slot, children]) => children.map((child) => ({
52
+ node: child,
53
+ slot,
54
+ })));
55
+ }
56
+ function serializeElement(tag, attributes, children, depth) {
57
+ if (children.length === 0) {
58
+ return [`${indent(depth)}<${tag}${serializeAttributes(attributes)} />`];
59
+ }
60
+ const lines = [`${indent(depth)}<${tag}${serializeAttributes(attributes)}>`];
61
+ for (const child of children) {
62
+ if ('slot' in child) {
63
+ const slotAttributes = child.slot === 'default' ? [] : [['slot', child.slot]];
64
+ lines.push(...serializeTemplateNode(child.node, depth + 1, slotAttributes));
65
+ }
66
+ else {
67
+ lines.push(...serializeTemplateNode(child, depth + 1));
68
+ }
69
+ }
70
+ lines.push(`${indent(depth)}</${tag}>`);
71
+ return lines;
72
+ }
73
+ function serializeAttributes(attributes) {
74
+ return flattenAttributes(attributes)
75
+ .map(([name, value]) => ` ${name}="${escapeAttribute(formatAttributeValue(name, value))}"`)
76
+ .join('');
77
+ }
78
+ function flattenAttributes(attributes) {
79
+ return attributes.flatMap(([name, value]) => {
80
+ if (!value || typeof value !== 'object') {
81
+ return [[name, value]];
82
+ }
83
+ return Object.entries(value).map(([field, fieldValue]) => [`${name}.${field}`, fieldValue]);
84
+ });
85
+ }
86
+ function formatAttributeValue(name, value) {
87
+ if (typeof value === 'number' && colorPropNames.has(name)) {
88
+ return `#${value.toString(16).padStart(6, '0').slice(-6)}`;
89
+ }
90
+ return String(value);
91
+ }
92
+ function escapeAttribute(value) {
93
+ return value
94
+ .replaceAll('&', '&amp;')
95
+ .replaceAll('"', '&quot;')
96
+ .replaceAll('<', '&lt;')
97
+ .replaceAll('>', '&gt;');
98
+ }
99
+ function indent(depth) {
100
+ return ' '.repeat(depth);
101
+ }
@@ -0,0 +1,2 @@
1
+ import type { CompileSceneTemplateOptions, SceneTemplate } from './spec.js';
2
+ export declare function compileSceneTemplateToTs(template: SceneTemplate, options?: CompileSceneTemplateOptions): string;
@@ -0,0 +1,494 @@
1
+ import { pixiSceneDisplayProps, pixiSceneGraphicsProps, pixiSceneSpriteLikeProps, pixiSceneTextStyleProps, pixiSceneTransformProps, } from './pixiNodeSchema.js';
2
+ const transformProps = new Set(pixiSceneTransformProps);
3
+ const pixiProps = new Set(pixiSceneDisplayProps);
4
+ const spriteProps = new Set(pixiSceneSpriteLikeProps);
5
+ const graphicsProps = new Set(pixiSceneGraphicsProps);
6
+ const textStyleProps = new Set(pixiSceneTextStyleProps);
7
+ export function compileSceneTemplateToTs(template, options = {}) {
8
+ const context = new CompileContext(template, options);
9
+ return context.compile();
10
+ }
11
+ class CompileContext {
12
+ template;
13
+ options;
14
+ #imports = new Set();
15
+ #pixiImports = new Set();
16
+ #runtimeImports = new Set();
17
+ #lines = [];
18
+ #parts = [];
19
+ #textures = new Map();
20
+ #nextId = 0;
21
+ #nextTextureId = 0;
22
+ constructor(template, options) {
23
+ this.template = template;
24
+ this.options = options;
25
+ }
26
+ compile() {
27
+ for (const child of this.template.children) {
28
+ this.#collectImports(child);
29
+ this.#collectParts(child);
30
+ this.#collectTextures(child);
31
+ }
32
+ const functionName = this.options.functionName || `mount${this.template.name}Scene`;
33
+ const actionsParameter = this.options.actionsParameter || 'actions';
34
+ const partsType = this.#formatPartsType();
35
+ const textureLoads = this.#formatTextureLoads();
36
+ this.#lines.push(`export function ${functionName}(root: Container${this.#hasEvents() ? `, ${actionsParameter}: Record<string, () => void> = {}` : ''}) {`);
37
+ this.#lines.push(' const __pixifactSlots: Record<string, Container> = {};');
38
+ this.#applyPixiProps('root', this.template.props);
39
+ for (const child of this.template.children) {
40
+ this.#compileNode(child, 'root', actionsParameter);
41
+ }
42
+ this.#lines.push(' return {');
43
+ this.#lines.push(' root,');
44
+ this.#lines.push(` parts: { ${this.#parts.map((part) => part.id).join(', ')} },`);
45
+ this.#lines.push(' slots: __pixifactSlots,');
46
+ this.#lines.push(' };');
47
+ this.#lines.push('}');
48
+ if (this.options.registrationPath) {
49
+ this.#runtimeImports.add('registerScene');
50
+ if (this.options.scriptImport) {
51
+ this.#runtimeImports.add('registerSceneClass');
52
+ }
53
+ this.#lines.push('');
54
+ this.#lines.push(`registerScene(${JSON.stringify(this.options.registrationPath)}, {`);
55
+ this.#lines.push(` mount: ${functionName},`);
56
+ this.#lines.push('});');
57
+ if (this.options.scriptImport) {
58
+ this.#lines.push(`registerSceneClass(${this.options.scriptImport.localName}, ${JSON.stringify(this.options.registrationPath)});`);
59
+ }
60
+ }
61
+ const imports = this.#formatImports();
62
+ return [
63
+ imports,
64
+ textureLoads,
65
+ partsType,
66
+ this.#lines.join('\n'),
67
+ ].filter(Boolean).join('\n\n') + '\n';
68
+ }
69
+ #formatImports() {
70
+ const imports = [...new Set([
71
+ 'Container',
72
+ ...[...this.#imports].filter((item) => item !== 'Container').sort(),
73
+ ...[...this.#pixiImports].sort(),
74
+ ])];
75
+ const lines = [`import { ${imports.join(', ')} } from 'pixi.js';`];
76
+ for (const [texture, variable] of this.#textureImportEntries()) {
77
+ lines.push(`import ${variable} from ${JSON.stringify(this.options.textureImports?.[texture])};`);
78
+ }
79
+ for (const sceneImport of this.options.sceneImports ?? []) {
80
+ const classImport = sceneImport.exportName === sceneImport.localName
81
+ ? sceneImport.exportName
82
+ : `${sceneImport.exportName} as ${sceneImport.localName}`;
83
+ const imports = [classImport, ...this.#sceneStructImports(sceneImport)];
84
+ lines.push(`import { ${imports.join(', ')} } from ${JSON.stringify(sceneImport.source)};`);
85
+ }
86
+ if (this.options.scriptImport) {
87
+ lines.push(`import { ${this.options.scriptImport.exportName} as ${this.options.scriptImport.localName} } from ${JSON.stringify(this.options.scriptImport.source)};`);
88
+ }
89
+ if (this.#runtimeImports.size > 0) {
90
+ lines.push(`import { ${[...this.#runtimeImports].sort().join(', ')} } from 'pixifact/compiler';`);
91
+ }
92
+ return lines.join('\n');
93
+ }
94
+ #formatPartsType() {
95
+ const lines = [`export type ${this.template.name}Parts = {`, ' root: Container;'];
96
+ lines.push(' parts: {');
97
+ for (const part of this.#parts) {
98
+ lines.push(` ${part.id}: ${part.type};`);
99
+ }
100
+ lines.push(' };');
101
+ lines.push(' slots: Record<string, Container>;');
102
+ lines.push('};');
103
+ return lines.join('\n');
104
+ }
105
+ #collectImports(node) {
106
+ if (node.kind === 'pixi') {
107
+ this.#imports.add(node.type);
108
+ for (const child of node.children) {
109
+ this.#collectImports(child);
110
+ }
111
+ return;
112
+ }
113
+ if (node.kind === 'sceneInstance') {
114
+ for (const children of Object.values(node.slots)) {
115
+ for (const child of children) {
116
+ this.#collectImports(child);
117
+ }
118
+ }
119
+ }
120
+ }
121
+ #collectParts(node) {
122
+ if (node.kind === 'pixi') {
123
+ if (node.id) {
124
+ this.#parts.push({ id: node.id, type: node.type });
125
+ }
126
+ for (const child of node.children) {
127
+ this.#collectParts(child);
128
+ }
129
+ return;
130
+ }
131
+ if (node.kind === 'sceneInstance') {
132
+ if (node.id) {
133
+ this.#parts.push({ id: node.id, type: this.#sceneConstructorName(node) });
134
+ }
135
+ for (const children of Object.values(node.slots)) {
136
+ for (const child of children) {
137
+ this.#collectParts(child);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ #collectTextures(node) {
143
+ if (node.kind === 'slotOutlet') {
144
+ return;
145
+ }
146
+ if (node.kind === 'pixi') {
147
+ if (typeof node.props.texture === 'string') {
148
+ this.#textureVariable(node.props.texture);
149
+ }
150
+ for (const child of node.children) {
151
+ this.#collectTextures(child);
152
+ }
153
+ return;
154
+ }
155
+ for (const children of Object.values(node.slots)) {
156
+ for (const child of children) {
157
+ this.#collectTextures(child);
158
+ }
159
+ }
160
+ }
161
+ #formatTextureLoads() {
162
+ if (this.#textures.size === 0) {
163
+ return '';
164
+ }
165
+ this.#pixiImports.add('Assets');
166
+ return [...this.#textures.entries()]
167
+ .map(([texture, variable]) => `const ${variable} = await Assets.load(${this.#textureLoadSource(texture)});`)
168
+ .join('\n');
169
+ }
170
+ #compileNode(node, parent, actionsParameter) {
171
+ if (node.kind === 'slotOutlet') {
172
+ this.#runtimeImports.add('registerSlot');
173
+ this.#lines.push(` __pixifactSlots[${JSON.stringify(node.name)}] = ${parent};`);
174
+ this.#lines.push(` registerSlot(root, ${JSON.stringify(node.name)}, ${parent});`);
175
+ return;
176
+ }
177
+ if (node.kind === 'sceneInstance') {
178
+ this.#compileSceneInstance(node, parent, actionsParameter);
179
+ return;
180
+ }
181
+ this.#compilePixiNode(node, parent, actionsParameter);
182
+ }
183
+ #compilePixiNode(node, parent, actionsParameter) {
184
+ const variable = node.id || this.#anonymousName(node.type);
185
+ this.#lines.push(` const ${variable} = ${this.#constructPixiNode(node)};`);
186
+ this.#applyNodeId(variable, node.id);
187
+ this.#applyPixiProps(variable, node.props);
188
+ this.#applyParentSorting(parent, node.props);
189
+ this.#lines.push(` ${parent}.addChild(${variable});`);
190
+ for (const child of node.children) {
191
+ this.#compileNode(child, variable, actionsParameter);
192
+ }
193
+ }
194
+ #compileSceneInstance(node, parent, actionsParameter) {
195
+ const variable = node.id || this.#anonymousName(node.type);
196
+ const constructorName = this.#sceneConstructorName(node);
197
+ this.#lines.push(` const ${variable} = new ${constructorName}();`);
198
+ this.#applyPixiProps(variable, node.props, true, node);
199
+ for (const [name, action] of Object.entries(node.events)) {
200
+ this.#runtimeImports.add('connectSceneEvent');
201
+ this.#lines.push(` connectSceneEvent(${variable}.${name}, ${JSON.stringify(action)}, root, ${actionsParameter});`);
202
+ }
203
+ this.#applyParentSorting(parent, node.props);
204
+ this.#lines.push(` ${parent}.addChild(${variable});`);
205
+ for (const [slot, children] of Object.entries(node.slots)) {
206
+ for (const child of children) {
207
+ const childVariable = this.#compileSlottedNode(child, variable, actionsParameter);
208
+ this.#runtimeImports.add('mount');
209
+ this.#lines.push(` mount(${variable}, ${childVariable}, ${JSON.stringify(slot)});`);
210
+ }
211
+ }
212
+ }
213
+ #compileSlottedNode(node, slotTarget, actionsParameter) {
214
+ if (node.kind === 'slotOutlet') {
215
+ throw new Error(`Cannot place <slot> inside ${slotTarget}.`);
216
+ }
217
+ if (node.kind === 'sceneInstance') {
218
+ const variable = node.id || this.#anonymousName(node.type);
219
+ const constructorName = this.#sceneConstructorName(node);
220
+ this.#lines.push(` const ${variable} = new ${constructorName}();`);
221
+ this.#applyPixiProps(variable, node.props, true, node);
222
+ for (const [name, action] of Object.entries(node.events)) {
223
+ this.#runtimeImports.add('connectSceneEvent');
224
+ this.#lines.push(` connectSceneEvent(${variable}.${name}, ${JSON.stringify(action)}, root, ${actionsParameter});`);
225
+ }
226
+ for (const [slot, children] of Object.entries(node.slots)) {
227
+ for (const child of children) {
228
+ const childVariable = this.#compileSlottedNode(child, variable, actionsParameter);
229
+ this.#runtimeImports.add('mount');
230
+ this.#lines.push(` mount(${variable}, ${childVariable}, ${JSON.stringify(slot)});`);
231
+ }
232
+ }
233
+ return variable;
234
+ }
235
+ const variable = node.id || this.#anonymousName(node.type);
236
+ this.#lines.push(` const ${variable} = ${this.#constructPixiNode(node)};`);
237
+ this.#applyNodeId(variable, node.id);
238
+ this.#applyPixiProps(variable, node.props);
239
+ for (const child of node.children) {
240
+ this.#compileNode(child, variable, actionsParameter);
241
+ }
242
+ return variable;
243
+ }
244
+ #constructPixiNode(node) {
245
+ if (node.type === 'Text' || node.type === 'BitmapText' || node.type === 'HTMLText') {
246
+ const text = this.#stringValue(node.props.text ?? '');
247
+ const style = this.#styleObject(node.props);
248
+ return `new ${node.type}({ text: ${text}${style ? `, style: ${style}` : ''} })`;
249
+ }
250
+ if (node.type === 'Sprite') {
251
+ return node.props.texture === undefined
252
+ ? 'new Sprite()'
253
+ : `new Sprite({ texture: ${this.#textureValue(node.props.texture)} })`;
254
+ }
255
+ if (node.type === 'NineSliceSprite') {
256
+ return `new NineSliceSprite(${this.#spriteTextureOptions(node.props)})`;
257
+ }
258
+ if (node.type === 'TilingSprite') {
259
+ return `new TilingSprite(${this.#spriteTextureOptions(node.props)})`;
260
+ }
261
+ if (node.type === 'Graphics') {
262
+ return 'new Graphics()';
263
+ }
264
+ return `new ${node.type}()`;
265
+ }
266
+ #sceneConstructorName(node) {
267
+ return this.options.sceneClassAliases?.[node.scene] ?? node.type;
268
+ }
269
+ #sceneStructImports(sceneImport) {
270
+ const sceneInterface = this.options.sceneInterfaces?.[Object.entries(this.options.sceneClassAliases ?? {})
271
+ .find(([, alias]) => alias === sceneImport.localName)?.[0] ?? ''];
272
+ if (!sceneInterface) {
273
+ return [];
274
+ }
275
+ return [...new Set(Object.values(sceneInterface.props)
276
+ .filter((contract) => contract.type === 'struct')
277
+ .map((contract) => contract.struct))]
278
+ .sort();
279
+ }
280
+ #applyPixiProps(variable, props, instance = false, sceneInstance) {
281
+ const x = props.x;
282
+ const y = props.y;
283
+ if (x !== undefined || y !== undefined) {
284
+ this.#lines.push(` ${variable}.position.set(${this.#value(x ?? 0)}, ${this.#value(y ?? 0)});`);
285
+ }
286
+ if (props.width !== undefined && props.shape === undefined) {
287
+ this.#lines.push(` ${variable}.width = ${this.#value(props.width)};`);
288
+ }
289
+ if (props.height !== undefined && props.shape === undefined) {
290
+ this.#lines.push(` ${variable}.height = ${this.#value(props.height)};`);
291
+ }
292
+ const scaleX = props.scaleX;
293
+ const scaleY = props.scaleY;
294
+ if (scaleX !== undefined || scaleY !== undefined) {
295
+ this.#lines.push(` ${variable}.scale.set(${this.#value(scaleX ?? 1)}, ${this.#value(scaleY ?? 1)});`);
296
+ }
297
+ if (props.rotation !== undefined) {
298
+ this.#lines.push(` ${variable}.rotation = ${this.#value(props.rotation)};`);
299
+ }
300
+ const pivotX = props.pivotX;
301
+ const pivotY = props.pivotY;
302
+ if (pivotX !== undefined || pivotY !== undefined) {
303
+ this.#lines.push(` ${variable}.pivot.set(${this.#value(pivotX ?? 0)}, ${this.#value(pivotY ?? 0)});`);
304
+ }
305
+ const skewX = props.skewX;
306
+ const skewY = props.skewY;
307
+ if (skewX !== undefined || skewY !== undefined) {
308
+ this.#lines.push(` ${variable}.skew.set(${this.#value(skewX ?? 0)}, ${this.#value(skewY ?? 0)});`);
309
+ }
310
+ this.#applySpriteProps(variable, props);
311
+ if (!instance && props.shape !== undefined) {
312
+ this.#drawGraphics(variable, props);
313
+ }
314
+ for (const [key, value] of Object.entries(props)) {
315
+ const nativePixiNodeProp = transformProps.has(key)
316
+ || spriteProps.has(key)
317
+ || graphicsProps.has(key)
318
+ || key === 'text'
319
+ || this.#isTextStyleProp(key);
320
+ if (!instance && nativePixiNodeProp) {
321
+ continue;
322
+ }
323
+ if (instance && transformProps.has(key)) {
324
+ continue;
325
+ }
326
+ if (instance && value && typeof value === 'object') {
327
+ this.#applyStructProp(variable, key, value, sceneInstance);
328
+ continue;
329
+ }
330
+ if (instance || pixiProps.has(key)) {
331
+ this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
332
+ }
333
+ }
334
+ }
335
+ #applyStructProp(variable, key, value, sceneInstance) {
336
+ const contract = this.#sceneInstanceStructContract(sceneInstance, key);
337
+ if (!contract) {
338
+ this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
339
+ return;
340
+ }
341
+ const structVariable = `${variable}${key.charAt(0).toUpperCase()}${key.slice(1)}`;
342
+ this.#lines.push(` const ${structVariable} = new ${contract.struct}();`);
343
+ for (const [field, fieldValue] of Object.entries(value)) {
344
+ this.#lines.push(` ${structVariable}.${field} = ${this.#value(fieldValue)};`);
345
+ }
346
+ this.#lines.push(` ${variable}.${key} = ${structVariable};`);
347
+ }
348
+ #sceneInstanceStructContract(sceneInstance, key) {
349
+ const contract = sceneInstance ? this.options.sceneInterfaces?.[sceneInstance.scene]?.props[key] : undefined;
350
+ return contract?.type === 'struct' ? contract : undefined;
351
+ }
352
+ #applySpriteProps(variable, props) {
353
+ const anchorX = props.anchorX;
354
+ const anchorY = props.anchorY;
355
+ if (anchorX !== undefined || anchorY !== undefined) {
356
+ this.#lines.push(` ${variable}.anchor.set(${this.#value(anchorX ?? 0)}, ${this.#value(anchorY ?? 0)});`);
357
+ }
358
+ if (props.tint !== undefined) {
359
+ this.#lines.push(` ${variable}.tint = ${this.#value(props.tint)};`);
360
+ }
361
+ for (const key of ['leftWidth', 'rightWidth', 'topHeight', 'bottomHeight', 'tileRotation']) {
362
+ const value = props[key];
363
+ if (value !== undefined) {
364
+ this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
365
+ }
366
+ }
367
+ const tilePositionX = props.tilePositionX;
368
+ const tilePositionY = props.tilePositionY;
369
+ if (tilePositionX !== undefined || tilePositionY !== undefined) {
370
+ this.#lines.push(` ${variable}.tilePosition.set(${this.#value(tilePositionX ?? 0)}, ${this.#value(tilePositionY ?? 0)});`);
371
+ }
372
+ const tileScaleX = props.tileScaleX;
373
+ const tileScaleY = props.tileScaleY;
374
+ if (tileScaleX !== undefined || tileScaleY !== undefined) {
375
+ this.#lines.push(` ${variable}.tileScale.set(${this.#value(tileScaleX ?? 1)}, ${this.#value(tileScaleY ?? 1)});`);
376
+ }
377
+ }
378
+ #drawGraphics(variable, props) {
379
+ const shape = props.shape;
380
+ if (shape === 'roundRect') {
381
+ this.#lines.push(` ${variable}.roundRect(0, 0, ${this.#value(props.width ?? 0)}, ${this.#value(props.height ?? 0)}, ${this.#value(props.radius ?? 0)})${this.#graphicsStyles(props)};`);
382
+ return;
383
+ }
384
+ if (shape === 'rect') {
385
+ this.#lines.push(` ${variable}.rect(0, 0, ${this.#value(props.width ?? 0)}, ${this.#value(props.height ?? 0)})${this.#graphicsStyles(props)};`);
386
+ }
387
+ }
388
+ #graphicsStyles(props) {
389
+ const fill = props.fillAlpha === undefined
390
+ ? `.fill(${this.#value(props.fill ?? 0xffffff)})`
391
+ : `.fill({ color: ${this.#value(props.fill ?? 0xffffff)}, alpha: ${this.#value(props.fillAlpha)} })`;
392
+ if (props.strokeWidth === undefined) {
393
+ return fill;
394
+ }
395
+ const stroke = props.strokeAlpha === undefined
396
+ ? `.stroke({ width: ${this.#value(props.strokeWidth)}, color: ${this.#value(props.strokeColor ?? 0x000000)} })`
397
+ : `.stroke({ width: ${this.#value(props.strokeWidth)}, color: ${this.#value(props.strokeColor ?? 0x000000)}, alpha: ${this.#value(props.strokeAlpha)} })`;
398
+ return `${fill}${stroke}`;
399
+ }
400
+ #applyNodeId(variable, id) {
401
+ if (id) {
402
+ this.#lines.push(` ${variable}.label = ${JSON.stringify(id)};`);
403
+ }
404
+ }
405
+ #applyParentSorting(parent, props) {
406
+ if (props.zIndex !== undefined) {
407
+ this.#lines.push(` ${parent}.sortableChildren = true;`);
408
+ }
409
+ }
410
+ #styleObject(props) {
411
+ const entries = [];
412
+ for (const key of pixiSceneTextStyleProps) {
413
+ const value = props[key];
414
+ if (value !== undefined) {
415
+ entries.push(`${key}: ${key === 'fontWeight' ? JSON.stringify(String(value)) : this.#value(value)}`);
416
+ }
417
+ }
418
+ return entries.length > 0 ? `{ ${entries.join(', ')} }` : undefined;
419
+ }
420
+ #spriteTextureOptions(props) {
421
+ return props.texture === undefined
422
+ ? '{}'
423
+ : `{ texture: ${this.#textureValue(props.texture)} }`;
424
+ }
425
+ #hasEvents() {
426
+ for (const child of this.template.children) {
427
+ if (this.#nodeHasEvents(child)) {
428
+ return true;
429
+ }
430
+ }
431
+ return false;
432
+ }
433
+ #nodeHasEvents(node) {
434
+ if (node.kind === 'slotOutlet') {
435
+ return false;
436
+ }
437
+ if (node.kind === 'sceneInstance') {
438
+ if (Object.keys(node.events).length > 0) {
439
+ return true;
440
+ }
441
+ return Object.values(node.slots).some((children) => children.some((child) => this.#nodeHasEvents(child)));
442
+ }
443
+ return node.children.some((child) => this.#nodeHasEvents(child));
444
+ }
445
+ #isTextStyleProp(key) {
446
+ return textStyleProps.has(key);
447
+ }
448
+ #anonymousName(type) {
449
+ this.#nextId += 1;
450
+ return `${type.charAt(0).toLowerCase()}${type.slice(1)}${this.#nextId}`;
451
+ }
452
+ #textureVariable(texture) {
453
+ const existing = this.#textures.get(texture);
454
+ if (existing) {
455
+ return existing;
456
+ }
457
+ this.#nextTextureId += 1;
458
+ const variable = `__pixifactTexture${this.#nextTextureId}`;
459
+ this.#textures.set(texture, variable);
460
+ return variable;
461
+ }
462
+ #textureImportEntries() {
463
+ return [...this.#textures.keys()]
464
+ .filter((texture) => this.options.textureImports?.[texture])
465
+ .map((texture, index) => [texture, `__pixifactTextureUrl${index + 1}`]);
466
+ }
467
+ #textureImportVariable(texture) {
468
+ const index = [...this.#textures.keys()]
469
+ .filter((key) => this.options.textureImports?.[key])
470
+ .indexOf(texture);
471
+ return index >= 0 ? `__pixifactTextureUrl${index + 1}` : undefined;
472
+ }
473
+ #textureLoadSource(texture) {
474
+ return this.#textureImportVariable(texture) ?? this.#value(texture);
475
+ }
476
+ #textureValue(value) {
477
+ return typeof value === 'string' ? this.#textureVariable(value) : this.#value(value);
478
+ }
479
+ #value(value) {
480
+ if (typeof value === 'string') {
481
+ return JSON.stringify(value);
482
+ }
483
+ if (value && typeof value === 'object') {
484
+ return `{ ${Object.entries(value).map(([key, fieldValue]) => `${key}: ${this.#scalarValue(fieldValue)}`).join(', ')} }`;
485
+ }
486
+ return String(value);
487
+ }
488
+ #scalarValue(value) {
489
+ return typeof value === 'string' ? JSON.stringify(value) : String(value);
490
+ }
491
+ #stringValue(value) {
492
+ return JSON.stringify(String(value));
493
+ }
494
+ }
@@ -0,0 +1,2 @@
1
+ export * from '../compiler/compileScenes.js';
2
+ export * from './vite.js';
@@ -0,0 +1,2 @@
1
+ export * from '../compiler/compileScenes.js';
2
+ export * from './vite.js';
@@ -0,0 +1,8 @@
1
+ export interface PixifactScenesPluginOptions {
2
+ projectRoot?: string | URL;
3
+ generatedDir?: string;
4
+ }
5
+ export declare function pixifactScenesPlugin(options?: PixifactScenesPluginOptions): {
6
+ name: string;
7
+ resolveId(id: string): string | undefined;
8
+ };
@@ -0,0 +1,21 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ function projectRootPath(projectRoot) {
4
+ if (typeof projectRoot === 'string') {
5
+ return projectRoot;
6
+ }
7
+ if (projectRoot) {
8
+ return fileURLToPath(projectRoot);
9
+ }
10
+ return process.cwd();
11
+ }
12
+ export function pixifactScenesPlugin(options = {}) {
13
+ const generatedDir = path.resolve(projectRootPath(options.projectRoot), options.generatedDir ?? '.pixifact/generated');
14
+ const sceneRegistry = path.join(generatedDir, 'scenes.generated.ts');
15
+ return {
16
+ name: 'pixifact-scenes',
17
+ resolveId(id) {
18
+ return id === 'pixifact:scenes' ? sceneRegistry : undefined;
19
+ },
20
+ };
21
+ }
@@ -0,0 +1,6 @@
1
+ export * from './runtime/index.js';
2
+ export * from './nodes/index.js';
3
+ export * from './scene/index.js';
4
+ export * from './authoring/index.js';
5
+ export * from './commands/index.js';
6
+ export * from 'eventemitter3';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './runtime/index.js';
2
+ export * from './nodes/index.js';
3
+ export * from './scene/index.js';
4
+ export * from './authoring/index.js';
5
+ export * from './commands/index.js';
6
+ export * from 'eventemitter3';