pixifact 0.4.0 → 0.6.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 (51) hide show
  1. package/dist/compiler/builtinScenes.d.ts +0 -5
  2. package/dist/compiler/builtinScenes.js +0 -26
  3. package/dist/compiler/commands/index.js +8 -5
  4. package/dist/compiler/compileScenes.d.ts +3 -1
  5. package/dist/compiler/compileScenes.js +32 -2
  6. package/dist/compiler/index.d.ts +0 -1
  7. package/dist/compiler/index.js +0 -1
  8. package/dist/compiler/pixiNodeSchema.d.ts +5 -3
  9. package/dist/compiler/pixiNodeSchema.js +61 -7
  10. package/dist/compiler/sceneValidation.d.ts +3 -1
  11. package/dist/compiler/sceneValidation.js +105 -6
  12. package/dist/compiler/spec.d.ts +18 -7
  13. package/dist/compiler/spec.js +3 -1
  14. package/dist/compiler/templateParser.js +19 -0
  15. package/dist/compiler/templateSerializer.js +7 -1
  16. package/dist/compiler/typescriptCompiler.js +66 -8
  17. package/dist/compiler-node/builtinSceneInterfaces.d.ts +6 -0
  18. package/dist/compiler-node/builtinSceneInterfaces.js +27 -0
  19. package/dist/compiler-node/index.d.ts +3 -0
  20. package/dist/compiler-node/index.js +3 -0
  21. package/dist/compiler-node/runtimeVite.d.ts +89 -0
  22. package/dist/compiler-node/runtimeVite.js +420 -0
  23. package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.d.ts +1 -1
  24. package/dist/{compiler → compiler-node}/scriptInterfaceExtractor.js +157 -25
  25. package/dist/errors.d.ts +1 -1
  26. package/dist/errors.js +4 -1
  27. package/dist/runtime/BitmapLabel.d.ts +9 -0
  28. package/dist/runtime/BitmapLabel.js +7 -0
  29. package/dist/runtime/Label.d.ts +9 -0
  30. package/dist/runtime/Label.js +7 -0
  31. package/dist/runtime/ScrollContainer.d.ts +2 -0
  32. package/dist/runtime/ScrollContainer.js +12 -2
  33. package/dist/runtime/TextBoxControl.d.ts +48 -0
  34. package/dist/runtime/TextBoxControl.js +162 -0
  35. package/dist/runtime/index.d.ts +2 -0
  36. package/dist/runtime/index.js +2 -0
  37. package/dist/runtime/runtimeBehavior.d.ts +3 -0
  38. package/dist/runtime/runtimeBehavior.js +11 -0
  39. package/dist/runtime-dev/index.d.ts +5 -0
  40. package/dist/runtime-dev/index.js +22 -0
  41. package/dist/runtime-dev/protocol.d.ts +58 -0
  42. package/dist/runtime-dev/protocol.js +1 -0
  43. package/dist/runtime-dev/runtimeClient.d.ts +22 -0
  44. package/dist/runtime-dev/runtimeClient.js +382 -0
  45. package/dist/scene/decorators.d.ts +2 -1
  46. package/dist/scene/decorators.js +12 -7
  47. package/dist/scene/index.d.ts +1 -0
  48. package/dist/scene/index.js +1 -0
  49. package/dist/scene/sceneBindingRuntime.d.ts +10 -0
  50. package/dist/scene/sceneBindingRuntime.js +124 -0
  51. package/package.json +6 -1
package/dist/errors.js CHANGED
@@ -8,8 +8,11 @@ export function hintForCommandError(error) {
8
8
  if (error.includes('Unknown template kind')) {
9
9
  return 'Use one of: button, progressBar, scrollView, loginForm.';
10
10
  }
11
+ if (error.includes('Node locator') && error.includes('was not found')) {
12
+ return 'Run scene inspect --scene <scene-path> and pass one of the returned node locator values.';
13
+ }
11
14
  if (error.includes('was not found')) {
12
- return 'Re-run scene get or node inspect to refresh locators before regenerating the command.';
15
+ return 'Inspect the current project state again before regenerating the command.';
13
16
  }
14
17
  if (error.includes('Only container nodes')) {
15
18
  return 'Choose a container node as the parent, or create a container template before adding children.';
@@ -0,0 +1,9 @@
1
+ import { BitmapText } from 'pixi.js';
2
+ import { TextBoxControl, type TextBoxAlign, type TextBoxFontWeight, type TextBoxOptions, type TextBoxOverflow } from './TextBoxControl.js';
3
+ export type BitmapLabelAlign = TextBoxAlign;
4
+ export type BitmapLabelOverflow = TextBoxOverflow;
5
+ export type BitmapLabelFontWeight = TextBoxFontWeight;
6
+ export type BitmapLabelOptions = TextBoxOptions;
7
+ export declare class BitmapLabel extends TextBoxControl<BitmapText> {
8
+ constructor(options?: BitmapLabelOptions);
9
+ }
@@ -0,0 +1,7 @@
1
+ import { BitmapText } from 'pixi.js';
2
+ import { TextBoxControl, } from './TextBoxControl.js';
3
+ export class BitmapLabel extends TextBoxControl {
4
+ constructor(options = {}) {
5
+ super(options, (textOptions) => new BitmapText(textOptions));
6
+ }
7
+ }
@@ -0,0 +1,9 @@
1
+ import { Text } from 'pixi.js';
2
+ import { TextBoxControl, type TextBoxAlign, type TextBoxFontWeight, type TextBoxOptions, type TextBoxOverflow } from './TextBoxControl.js';
3
+ export type LabelAlign = TextBoxAlign;
4
+ export type LabelOverflow = TextBoxOverflow;
5
+ export type LabelFontWeight = TextBoxFontWeight;
6
+ export type LabelOptions = TextBoxOptions;
7
+ export declare class Label extends TextBoxControl<Text> {
8
+ constructor(options?: LabelOptions);
9
+ }
@@ -0,0 +1,7 @@
1
+ import { Text } from 'pixi.js';
2
+ import { TextBoxControl, } from './TextBoxControl.js';
3
+ export class Label extends TextBoxControl {
4
+ constructor(options = {}) {
5
+ super(options, (textOptions) => new Text(textOptions));
6
+ }
7
+ }
@@ -1,6 +1,7 @@
1
1
  import { Container, type ContainerChild, type DestroyOptions } from 'pixi.js';
2
2
  import { Control } from './Control.js';
3
3
  import type { GroupOptions } from './Group.js';
4
+ import { runtimeBehavior } from './runtimeBehavior.js';
4
5
  export type ScrollDirection = 'vertical' | 'horizontal' | 'both';
5
6
  export type ScrollContainerOptions = GroupOptions & {
6
7
  direction?: ScrollDirection;
@@ -11,6 +12,7 @@ export declare class ScrollContainer extends Control {
11
12
  #private;
12
13
  readonly contentLayer: Container<ContainerChild>;
13
14
  constructor(options?: ScrollContainerOptions);
15
+ [runtimeBehavior](): void;
14
16
  get direction(): ScrollDirection;
15
17
  set direction(value: ScrollDirection);
16
18
  get scrollX(): number;
@@ -1,5 +1,6 @@
1
1
  import { Container, Graphics, Ticker, } from 'pixi.js';
2
2
  import { Control } from './Control.js';
3
+ import { runtimeBehavior } from './runtimeBehavior.js';
3
4
  const elasticResistance = 0.5;
4
5
  const inertiaFriction = 0.92;
5
6
  const springStrength = 0.18;
@@ -26,19 +27,21 @@ export class ScrollContainer extends Control {
26
27
  this.#direction = direction ?? this.#direction;
27
28
  this.#targetScrollX = scrollX ?? this.#targetScrollX;
28
29
  this.#targetScrollY = scrollY ?? this.#targetScrollY;
29
- this.eventMode = 'static';
30
30
  this.contentLayer.mask = this.#mask;
31
31
  this.contentLayer.on('childAdded', this.#handleContentChildAdded, this);
32
32
  this.contentLayer.on('childRemoved', this.#handleContentChildRemoved, this);
33
33
  super.addChild(this.contentLayer);
34
34
  super.addChild(this.#mask);
35
+ this.layout();
36
+ }
37
+ [runtimeBehavior]() {
38
+ this.eventMode = 'static';
35
39
  this.on('wheel', this.#handleWheel, this);
36
40
  this.on('pointerdown', this.#handlePointerDown, this);
37
41
  this.on('globalpointermove', this.#handleGlobalPointerMove, this);
38
42
  this.on('pointerup', this.#handlePointerUp, this);
39
43
  this.on('pointerupoutside', this.#handlePointerUp, this);
40
44
  this.on('pointercancel', this.#handlePointerUp, this);
41
- this.layout();
42
45
  }
43
46
  get direction() {
44
47
  return this.#direction;
@@ -116,6 +119,13 @@ export class ScrollContainer extends Control {
116
119
  destroy(options) {
117
120
  this.#destroying = true;
118
121
  this.#stopMomentum();
122
+ this.#drag = undefined;
123
+ this.off('wheel', this.#handleWheel, this);
124
+ this.off('pointerdown', this.#handlePointerDown, this);
125
+ this.off('globalpointermove', this.#handleGlobalPointerMove, this);
126
+ this.off('pointerup', this.#handlePointerUp, this);
127
+ this.off('pointerupoutside', this.#handlePointerUp, this);
128
+ this.off('pointercancel', this.#handlePointerUp, this);
119
129
  this.contentLayer.off('childAdded', this.#handleContentChildAdded, this);
120
130
  this.contentLayer.off('childRemoved', this.#handleContentChildRemoved, this);
121
131
  for (const child of this.#watchedContent) {
@@ -0,0 +1,48 @@
1
+ import { BitmapText, Text, type TextOptions } from 'pixi.js';
2
+ import { Control } from './Control.js';
3
+ import type { GroupOptions } from './Group.js';
4
+ export type TextBoxAlign = 'start' | 'center' | 'end';
5
+ export type TextBoxOverflow = 'visible' | 'clip';
6
+ export type TextBoxFontWeight = 400 | 500 | 600 | 700 | '400' | '500' | '600' | '700' | 'bold';
7
+ export type TextBoxOptions = GroupOptions & {
8
+ text?: string;
9
+ fontFamily?: string;
10
+ fontSize?: number;
11
+ fontWeight?: TextBoxFontWeight;
12
+ fill?: number;
13
+ lineHeight?: number;
14
+ letterSpacing?: number;
15
+ wordWrap?: boolean;
16
+ alignX?: TextBoxAlign;
17
+ alignY?: TextBoxAlign;
18
+ overflow?: TextBoxOverflow;
19
+ };
20
+ type TextBoxRenderer = Text | BitmapText;
21
+ export declare class TextBoxControl<T extends TextBoxRenderer> extends Control {
22
+ #private;
23
+ constructor(options: TextBoxOptions, createTextNode: (options: TextOptions) => T);
24
+ get text(): string;
25
+ set text(value: string);
26
+ get fontFamily(): string;
27
+ set fontFamily(value: string);
28
+ get fontSize(): number;
29
+ set fontSize(value: number);
30
+ get fontWeight(): TextBoxFontWeight;
31
+ set fontWeight(value: TextBoxFontWeight);
32
+ get fill(): number;
33
+ set fill(value: number);
34
+ get lineHeight(): number;
35
+ set lineHeight(value: number);
36
+ get letterSpacing(): number;
37
+ set letterSpacing(value: number);
38
+ get wordWrap(): boolean;
39
+ set wordWrap(value: boolean);
40
+ get alignX(): TextBoxAlign;
41
+ set alignX(value: TextBoxAlign);
42
+ get alignY(): TextBoxAlign;
43
+ set alignY(value: TextBoxAlign);
44
+ get overflow(): TextBoxOverflow;
45
+ set overflow(value: TextBoxOverflow);
46
+ layout(): void;
47
+ }
48
+ export {};
@@ -0,0 +1,162 @@
1
+ import { Graphics, } from 'pixi.js';
2
+ import { Control } from './Control.js';
3
+ export class TextBoxControl extends Control {
4
+ #textNode;
5
+ #clipMask = new Graphics();
6
+ #fontFamily = 'Arial';
7
+ #fontSize = 16;
8
+ #fontWeight = 400;
9
+ #fill = 0x111827;
10
+ #lineHeight = 0;
11
+ #letterSpacing = 0;
12
+ #wordWrap = false;
13
+ #alignX = 'start';
14
+ #alignY = 'start';
15
+ #overflow = 'visible';
16
+ constructor(options, createTextNode) {
17
+ const { text = 'Text', width = 120, height = 28, fontFamily = 'Arial', fontSize = 16, fontWeight = 400, fill = 0x111827, lineHeight = 0, letterSpacing = 0, wordWrap = false, alignX = 'start', alignY = 'start', overflow = 'visible', ...groupOptions } = options;
18
+ super({ ...groupOptions, width, height });
19
+ this.#fontFamily = fontFamily;
20
+ this.#fontSize = fontSize;
21
+ this.#fontWeight = fontWeight;
22
+ this.#fill = fill;
23
+ this.#lineHeight = lineHeight;
24
+ this.#letterSpacing = letterSpacing;
25
+ this.#wordWrap = wordWrap;
26
+ this.#alignX = alignX;
27
+ this.#alignY = alignY;
28
+ this.#overflow = overflow;
29
+ this.#textNode = createTextNode({
30
+ text,
31
+ style: {
32
+ fontFamily,
33
+ fontSize,
34
+ fontWeight: String(fontWeight),
35
+ fill,
36
+ lineHeight,
37
+ letterSpacing,
38
+ wordWrap,
39
+ wordWrapWidth: width,
40
+ align: horizontalTextAlign(alignX),
41
+ },
42
+ });
43
+ super.addChild(this.#textNode, this.#clipMask);
44
+ this.layout();
45
+ }
46
+ get text() {
47
+ return this.#textNode.text;
48
+ }
49
+ set text(value) {
50
+ this.#textNode.text = value;
51
+ this.layout();
52
+ }
53
+ get fontFamily() {
54
+ return this.#fontFamily;
55
+ }
56
+ set fontFamily(value) {
57
+ this.#fontFamily = value;
58
+ this.#textNode.style.fontFamily = value;
59
+ this.layout();
60
+ }
61
+ get fontSize() {
62
+ return this.#fontSize;
63
+ }
64
+ set fontSize(value) {
65
+ this.#fontSize = value;
66
+ this.#textNode.style.fontSize = value;
67
+ this.layout();
68
+ }
69
+ get fontWeight() {
70
+ return this.#fontWeight;
71
+ }
72
+ set fontWeight(value) {
73
+ this.#fontWeight = value;
74
+ this.#textNode.style.fontWeight = String(value);
75
+ this.layout();
76
+ }
77
+ get fill() {
78
+ return this.#fill;
79
+ }
80
+ set fill(value) {
81
+ this.#fill = value;
82
+ this.#textNode.style.fill = value;
83
+ this.layout();
84
+ }
85
+ get lineHeight() {
86
+ return this.#lineHeight;
87
+ }
88
+ set lineHeight(value) {
89
+ this.#lineHeight = value;
90
+ this.#textNode.style.lineHeight = value;
91
+ this.layout();
92
+ }
93
+ get letterSpacing() {
94
+ return this.#letterSpacing;
95
+ }
96
+ set letterSpacing(value) {
97
+ this.#letterSpacing = value;
98
+ this.#textNode.style.letterSpacing = value;
99
+ this.layout();
100
+ }
101
+ get wordWrap() {
102
+ return this.#wordWrap;
103
+ }
104
+ set wordWrap(value) {
105
+ this.#wordWrap = value;
106
+ this.#textNode.style.wordWrap = value;
107
+ this.layout();
108
+ }
109
+ get alignX() {
110
+ return this.#alignX;
111
+ }
112
+ set alignX(value) {
113
+ this.#alignX = value;
114
+ this.#textNode.style.align = horizontalTextAlign(value);
115
+ this.layout();
116
+ }
117
+ get alignY() {
118
+ return this.#alignY;
119
+ }
120
+ set alignY(value) {
121
+ this.#alignY = value;
122
+ this.layout();
123
+ }
124
+ get overflow() {
125
+ return this.#overflow;
126
+ }
127
+ set overflow(value) {
128
+ this.#overflow = value;
129
+ this.layout();
130
+ }
131
+ layout() {
132
+ super.layout();
133
+ if (!this.#textNode) {
134
+ return;
135
+ }
136
+ this.#textNode.style.wordWrapWidth = this.width;
137
+ this.#textNode.anchor.set(alignmentFactor(this.#alignX), alignmentFactor(this.#alignY));
138
+ this.#textNode.position.set(this.width * alignmentFactor(this.#alignX), this.height * alignmentFactor(this.#alignY));
139
+ this.#clipMask.clear().rect(0, 0, this.width, this.height).fill(0xffffff);
140
+ const clip = this.#overflow === 'clip';
141
+ this.#clipMask.visible = clip;
142
+ this.#textNode.mask = clip ? this.#clipMask : null;
143
+ }
144
+ }
145
+ function horizontalTextAlign(align) {
146
+ if (align === 'center') {
147
+ return 'center';
148
+ }
149
+ if (align === 'end') {
150
+ return 'right';
151
+ }
152
+ return 'left';
153
+ }
154
+ function alignmentFactor(align) {
155
+ if (align === 'center') {
156
+ return 0.5;
157
+ }
158
+ if (align === 'end') {
159
+ return 1;
160
+ }
161
+ return 0;
162
+ }
@@ -1,5 +1,7 @@
1
1
  export * from './Group.js';
2
2
  export * from './Control.js';
3
+ export * from './Label.js';
4
+ export * from './BitmapLabel.js';
3
5
  export * from './Rect.js';
4
6
  export * from './Image.js';
5
7
  export * from './NineImage.js';
@@ -1,5 +1,7 @@
1
1
  export * from './Group.js';
2
2
  export * from './Control.js';
3
+ export * from './Label.js';
4
+ export * from './BitmapLabel.js';
3
5
  export * from './Rect.js';
4
6
  export * from './Image.js';
5
7
  export * from './NineImage.js';
@@ -0,0 +1,3 @@
1
+ import type { Container } from 'pixi.js';
2
+ export declare const runtimeBehavior: unique symbol;
3
+ export declare function activateRuntimeTree(root: Container): void;
@@ -0,0 +1,11 @@
1
+ export const runtimeBehavior = Symbol('pixifact.runtimeBehavior');
2
+ const activatedContainers = new WeakSet();
3
+ export function activateRuntimeTree(root) {
4
+ if (runtimeBehavior in root && !activatedContainers.has(root)) {
5
+ activatedContainers.add(root);
6
+ root[runtimeBehavior]();
7
+ }
8
+ for (const child of root.children) {
9
+ activateRuntimeTree(child);
10
+ }
11
+ }
@@ -0,0 +1,5 @@
1
+ import type { Application } from 'pixi.js';
2
+ import { type RegisterPixiRuntimeOptions } from './runtimeClient.js';
3
+ export declare function registerPixiRuntime(app: Application, options?: RegisterPixiRuntimeOptions): void;
4
+ export type { RegisterPixiRuntimeOptions } from './runtimeClient.js';
5
+ export type { RuntimeJsonValue, RuntimeLogLevel, RuntimePageDescriptor, RuntimeRequest, } from './protocol.js';
@@ -0,0 +1,22 @@
1
+ import { createPixifactRuntimeClient, } from './runtimeClient.js';
2
+ const runtimeHotKey = Symbol.for('pixifact.runtime.hot');
3
+ const runtimeClientKey = Symbol.for('pixifact.runtime.client');
4
+ const runtimeGlobal = globalThis;
5
+ const injectedHot = runtimeGlobal[runtimeHotKey];
6
+ const existingRuntimeClient = runtimeGlobal[runtimeClientKey];
7
+ const runtimeClient = existingRuntimeClient ?? (injectedHot
8
+ ? createPixifactRuntimeClient({
9
+ runtimeId: crypto.randomUUID(),
10
+ hot: injectedHot,
11
+ console,
12
+ window,
13
+ })
14
+ : undefined);
15
+ if (runtimeClient && !existingRuntimeClient)
16
+ runtimeGlobal[runtimeClientKey] = runtimeClient;
17
+ export function registerPixiRuntime(app, options = {}) {
18
+ if (!runtimeClient) {
19
+ throw new Error('registerPixiRuntime requires pixifactRuntimePlugin in the Vite development server.');
20
+ }
21
+ runtimeClient.register(app, options);
22
+ }
@@ -0,0 +1,58 @@
1
+ export declare const pixifactRuntimeProtocolVersion = 1;
2
+ export type RuntimeJsonPrimitive = boolean | number | string | null;
3
+ export type RuntimeJsonValue = RuntimeJsonPrimitive | RuntimeJsonValue[] | {
4
+ [key: string]: RuntimeJsonValue;
5
+ };
6
+ export type RuntimeLogLevel = 'debug' | 'log' | 'info' | 'warn' | 'error';
7
+ export interface RuntimeLogEntry {
8
+ seq: number;
9
+ time: string;
10
+ level: RuntimeLogLevel;
11
+ message: string;
12
+ args: RuntimeJsonValue[];
13
+ stack?: string;
14
+ }
15
+ export type RuntimeInputRequest = {
16
+ type: 'input';
17
+ action: 'click' | 'move';
18
+ x: number;
19
+ y: number;
20
+ } | {
21
+ type: 'input';
22
+ action: 'key' | 'keydown' | 'keyup';
23
+ key: string;
24
+ };
25
+ export type RuntimeRequest = {
26
+ type: 'tree';
27
+ } | {
28
+ type: 'node';
29
+ uid: number;
30
+ } | {
31
+ type: 'state';
32
+ } | {
33
+ type: 'logs';
34
+ after?: number;
35
+ level?: RuntimeLogLevel;
36
+ } | RuntimeInputRequest;
37
+ export interface RuntimePageDescriptor {
38
+ runtimeId: string;
39
+ url: string;
40
+ title: string;
41
+ ready: boolean;
42
+ }
43
+ export interface RuntimeHmrRequest {
44
+ requestId: string;
45
+ runtimeId: string;
46
+ request: RuntimeRequest;
47
+ }
48
+ export type RuntimeHmrResponse = {
49
+ requestId: string;
50
+ runtimeId: string;
51
+ ok: true;
52
+ result: RuntimeJsonValue;
53
+ } | {
54
+ requestId: string;
55
+ runtimeId: string;
56
+ ok: false;
57
+ error: string;
58
+ };
@@ -0,0 +1 @@
1
+ export const pixifactRuntimeProtocolVersion = 1;
@@ -0,0 +1,22 @@
1
+ import { type Application } from 'pixi.js';
2
+ import { type RuntimeJsonValue, type RuntimeRequest } from './protocol.js';
3
+ export interface RegisterPixiRuntimeOptions {
4
+ getState?: () => RuntimeJsonValue;
5
+ }
6
+ export interface PixifactRuntimeHotContext {
7
+ on(event: string, listener: (data: unknown) => void): void;
8
+ send(event: string, data: unknown): void;
9
+ }
10
+ interface RuntimeClientOptions {
11
+ runtimeId: string;
12
+ hot: PixifactRuntimeHotContext;
13
+ console: Console;
14
+ window: Window;
15
+ now?: () => Date;
16
+ }
17
+ export declare function createPixifactRuntimeClient(options: RuntimeClientOptions): {
18
+ register(application: Application, registerOptions?: RegisterPixiRuntimeOptions): void;
19
+ handleRequest: (request: RuntimeRequest) => Promise<RuntimeJsonValue>;
20
+ dispose: () => void;
21
+ };
22
+ export {};