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.
- package/README.md +44 -0
- package/dist/authoring/ActionRegistry.d.ts +10 -0
- package/dist/authoring/ActionRegistry.js +26 -0
- package/dist/authoring/ComponentPalette.d.ts +16 -0
- package/dist/authoring/ComponentPalette.js +50 -0
- package/dist/authoring/DesignToken.d.ts +16 -0
- package/dist/authoring/DesignToken.js +33 -0
- package/dist/authoring/DiffModel.d.ts +10 -0
- package/dist/authoring/DiffModel.js +104 -0
- package/dist/authoring/InspectorModel.d.ts +27 -0
- package/dist/authoring/InspectorModel.js +139 -0
- package/dist/authoring/LogicGraph.d.ts +66 -0
- package/dist/authoring/LogicGraph.js +184 -0
- package/dist/authoring/OverrideJournal.d.ts +18 -0
- package/dist/authoring/OverrideJournal.js +23 -0
- package/dist/authoring/PreferenceMemory.d.ts +21 -0
- package/dist/authoring/PreferenceMemory.js +39 -0
- package/dist/authoring/ProjectConfig.d.ts +20 -0
- package/dist/authoring/ProjectConfig.js +78 -0
- package/dist/authoring/RuntimePreview.d.ts +11 -0
- package/dist/authoring/RuntimePreview.js +25 -0
- package/dist/authoring/SceneDocument.d.ts +74 -0
- package/dist/authoring/SceneDocument.js +332 -0
- package/dist/authoring/SceneProjectState.d.ts +20 -0
- package/dist/authoring/SceneProjectState.js +8 -0
- package/dist/authoring/SceneSelection.d.ts +11 -0
- package/dist/authoring/SceneSelection.js +1 -0
- package/dist/authoring/index.d.ts +13 -0
- package/dist/authoring/index.js +13 -0
- package/dist/commands/Command.d.ts +63 -0
- package/dist/commands/Command.js +1 -0
- package/dist/commands/CommandStack.d.ts +14 -0
- package/dist/commands/CommandStack.js +45 -0
- package/dist/commands/applyCommand.d.ts +23 -0
- package/dist/commands/applyCommand.js +316 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/utils.d.ts +17 -0
- package/dist/commands/utils.js +77 -0
- package/dist/commands/validateCommand.d.ts +12 -0
- package/dist/commands/validateCommand.js +285 -0
- package/dist/compiler/commands/index.d.ts +109 -0
- package/dist/compiler/commands/index.js +492 -0
- package/dist/compiler/compileScenes.d.ts +11 -0
- package/dist/compiler/compileScenes.js +220 -0
- package/dist/compiler/decorators.d.ts +6 -0
- package/dist/compiler/decorators.js +79 -0
- package/dist/compiler/eventRuntime.d.ts +8 -0
- package/dist/compiler/eventRuntime.js +29 -0
- package/dist/compiler/index.d.ts +14 -0
- package/dist/compiler/index.js +14 -0
- package/dist/compiler/pixiNodeSchema.d.ts +39 -0
- package/dist/compiler/pixiNodeSchema.js +267 -0
- package/dist/compiler/sceneAssetPair.d.ts +11 -0
- package/dist/compiler/sceneAssetPair.js +92 -0
- package/dist/compiler/scenePartValidation.d.ts +6 -0
- package/dist/compiler/scenePartValidation.js +24 -0
- package/dist/compiler/sceneRuntime.d.ts +13 -0
- package/dist/compiler/sceneRuntime.js +22 -0
- package/dist/compiler/sceneValidation.d.ts +48 -0
- package/dist/compiler/sceneValidation.js +383 -0
- package/dist/compiler/scriptInterfaceExtractor.d.ts +6 -0
- package/dist/compiler/scriptInterfaceExtractor.js +258 -0
- package/dist/compiler/slotRuntime.d.ts +3 -0
- package/dist/compiler/slotRuntime.js +17 -0
- package/dist/compiler/spec.d.ts +95 -0
- package/dist/compiler/spec.js +1 -0
- package/dist/compiler/templateParser.d.ts +2 -0
- package/dist/compiler/templateParser.js +302 -0
- package/dist/compiler/templateSerializer.d.ts +2 -0
- package/dist/compiler/templateSerializer.js +101 -0
- package/dist/compiler/typescriptCompiler.d.ts +2 -0
- package/dist/compiler/typescriptCompiler.js +494 -0
- package/dist/compiler-node/index.d.ts +2 -0
- package/dist/compiler-node/index.js +2 -0
- package/dist/compiler-node/vite.d.ts +8 -0
- package/dist/compiler-node/vite.js +21 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/nodes/Input.d.ts +91 -0
- package/dist/nodes/Input.js +352 -0
- package/dist/nodes/Textarea.d.ts +10 -0
- package/dist/nodes/Textarea.js +38 -0
- package/dist/nodes/components/Button.d.ts +8 -0
- package/dist/nodes/components/Button.js +45 -0
- package/dist/nodes/components/InputField.d.ts +12 -0
- package/dist/nodes/components/InputField.js +53 -0
- package/dist/nodes/components/ProgressBar.d.ts +14 -0
- package/dist/nodes/components/ProgressBar.js +66 -0
- package/dist/nodes/components/ScrollRect.d.ts +23 -0
- package/dist/nodes/components/ScrollRect.js +108 -0
- package/dist/nodes/components/Selectable.d.ts +32 -0
- package/dist/nodes/components/Selectable.js +153 -0
- package/dist/nodes/components/index.d.ts +5 -0
- package/dist/nodes/components/index.js +5 -0
- package/dist/nodes/graphics/Graphic.d.ts +14 -0
- package/dist/nodes/graphics/Graphic.js +47 -0
- package/dist/nodes/graphics/ImageGraphic.d.ts +9 -0
- package/dist/nodes/graphics/ImageGraphic.js +42 -0
- package/dist/nodes/graphics/RoundedRectGraphic.d.ts +13 -0
- package/dist/nodes/graphics/RoundedRectGraphic.js +65 -0
- package/dist/nodes/graphics/TextGraphic.d.ts +13 -0
- package/dist/nodes/graphics/TextGraphic.js +70 -0
- package/dist/nodes/graphics/index.d.ts +4 -0
- package/dist/nodes/graphics/index.js +4 -0
- package/dist/nodes/index.d.ts +3 -0
- package/dist/nodes/index.js +3 -0
- package/dist/runtime/Application.d.ts +15 -0
- package/dist/runtime/Application.js +67 -0
- package/dist/runtime/GameObject.d.ts +100 -0
- package/dist/runtime/GameObject.js +297 -0
- package/dist/runtime/GameObjectEvent.d.ts +52 -0
- package/dist/runtime/GameObjectEvent.js +38 -0
- package/dist/runtime/Transform.d.ts +32 -0
- package/dist/runtime/Transform.js +157 -0
- package/dist/runtime/component/Component.d.ts +13 -0
- package/dist/runtime/component/Component.js +13 -0
- package/dist/runtime/component/ComponentRegistry.d.ts +49 -0
- package/dist/runtime/component/ComponentRegistry.js +25 -0
- package/dist/runtime/component/Flex.d.ts +6 -0
- package/dist/runtime/component/Flex.js +15 -0
- package/dist/runtime/component/FlexGroup.d.ts +26 -0
- package/dist/runtime/component/FlexGroup.js +136 -0
- package/dist/runtime/component/GridLayout.d.ts +47 -0
- package/dist/runtime/component/GridLayout.js +129 -0
- package/dist/runtime/component/Layout.d.ts +104 -0
- package/dist/runtime/component/Layout.js +248 -0
- package/dist/runtime/component/decorators.d.ts +4 -0
- package/dist/runtime/component/decorators.js +52 -0
- package/dist/runtime/component/index.d.ts +7 -0
- package/dist/runtime/component/index.js +7 -0
- package/dist/runtime/graphics/index.d.ts +11 -0
- package/dist/runtime/graphics/index.js +29 -0
- package/dist/runtime/group/index.d.ts +39 -0
- package/dist/runtime/group/index.js +102 -0
- package/dist/runtime/image/Image.d.ts +19 -0
- package/dist/runtime/image/Image.js +60 -0
- package/dist/runtime/image/NineSliceImage.d.ts +23 -0
- package/dist/runtime/image/NineSliceImage.js +64 -0
- package/dist/runtime/image/index.d.ts +2 -0
- package/dist/runtime/image/index.js +2 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.js +9 -0
- package/dist/runtime/label/Label.d.ts +11 -0
- package/dist/runtime/label/Label.js +26 -0
- package/dist/runtime/label/LabelStyle.d.ts +3 -0
- package/dist/runtime/label/LabelStyle.js +3 -0
- package/dist/runtime/label/index.d.ts +2 -0
- package/dist/runtime/label/index.js +2 -0
- package/dist/runtime/utils/index.d.ts +1 -0
- package/dist/runtime/utils/index.js +1 -0
- package/dist/runtime/utils/onlyOnceQueueMicrotask.d.ts +1 -0
- package/dist/runtime/utils/onlyOnceQueueMicrotask.js +12 -0
- package/dist/runtime/utils/setProps.d.ts +10 -0
- package/dist/runtime/utils/setProps.js +17 -0
- package/dist/scene/dsl.d.ts +25 -0
- package/dist/scene/dsl.js +112 -0
- package/dist/scene/index.d.ts +5 -0
- package/dist/scene/index.js +5 -0
- package/dist/scene/instantiate.d.ts +8 -0
- package/dist/scene/instantiate.js +208 -0
- package/dist/scene/nodesDsl.d.ts +42 -0
- package/dist/scene/nodesDsl.js +169 -0
- package/dist/scene/spec.d.ts +100 -0
- package/dist/scene/spec.js +1 -0
- package/dist/scene/templates.d.ts +21 -0
- package/dist/scene/templates.js +239 -0
- package/package.json +90 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { findNode } from "../commands/utils.js";
|
|
2
|
+
import { actionExists } from "./ActionRegistry.js";
|
|
3
|
+
export function createLogicGraph(flows = []) {
|
|
4
|
+
return {
|
|
5
|
+
version: 1,
|
|
6
|
+
type: 'pixifact.logicGraph',
|
|
7
|
+
flows,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function createUseInventoryItemFlow() {
|
|
11
|
+
return {
|
|
12
|
+
id: 'flow-useInventoryItem',
|
|
13
|
+
action: 'useInventoryItem',
|
|
14
|
+
name: 'Use Inventory Item',
|
|
15
|
+
description: 'Decrease item quantity and remove empty inventory slots.',
|
|
16
|
+
steps: [
|
|
17
|
+
{
|
|
18
|
+
id: 'hasQuantity',
|
|
19
|
+
type: 'condition',
|
|
20
|
+
condition: {
|
|
21
|
+
left: { kind: 'state', path: 'selectedItem.quantity' },
|
|
22
|
+
op: 'gt',
|
|
23
|
+
right: { kind: 'const', value: 0 },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'decreaseQuantity',
|
|
28
|
+
type: 'setState',
|
|
29
|
+
path: 'selectedItem.quantity',
|
|
30
|
+
value: { kind: 'state', path: 'selectedItem.quantity - 1' },
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'removeEmptySlot',
|
|
34
|
+
type: 'comment',
|
|
35
|
+
text: 'When quantity reaches zero, remove or hide the inventory slot in game code.',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function validateValue(value, errors, target) {
|
|
41
|
+
if (value.kind !== 'const' && !value.path) {
|
|
42
|
+
errors.push(`${target} requires a path.`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function validateStep(step, flow, context, errors) {
|
|
46
|
+
if (!step.id) {
|
|
47
|
+
errors.push(`Logic flow "${flow.id}" contains a step without id.`);
|
|
48
|
+
}
|
|
49
|
+
switch (step.type) {
|
|
50
|
+
case 'condition':
|
|
51
|
+
validateValue(step.condition.left, errors, `${step.id}.condition.left`);
|
|
52
|
+
if (step.condition.op !== 'truthy' && step.condition.op !== 'falsy' && !step.condition.right) {
|
|
53
|
+
errors.push(`${step.id}.condition.right is required for ${step.condition.op}.`);
|
|
54
|
+
}
|
|
55
|
+
if (step.condition.right) {
|
|
56
|
+
validateValue(step.condition.right, errors, `${step.id}.condition.right`);
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case 'setState':
|
|
60
|
+
if (!step.path) {
|
|
61
|
+
errors.push(`${step.id}.path is required.`);
|
|
62
|
+
}
|
|
63
|
+
validateValue(step.value, errors, `${step.id}.value`);
|
|
64
|
+
break;
|
|
65
|
+
case 'setNodeVisible':
|
|
66
|
+
if (context.scene && !findNode(context.scene, step.node)) {
|
|
67
|
+
errors.push(`${step.id} references missing node "${step.node}".`);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
case 'emitAction':
|
|
71
|
+
if (context.actions && !actionExists(context.actions, step.action)) {
|
|
72
|
+
errors.push(`${step.id} emits undeclared action "${step.action}".`);
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case 'comment':
|
|
76
|
+
if (!step.text) {
|
|
77
|
+
errors.push(`${step.id}.text is required.`);
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function validateLogicGraph(graph, context = {}) {
|
|
83
|
+
const errors = [];
|
|
84
|
+
if (graph.type !== 'pixifact.logicGraph') {
|
|
85
|
+
errors.push('Logic graph type must be "pixifact.logicGraph".');
|
|
86
|
+
}
|
|
87
|
+
const flowIds = new Set();
|
|
88
|
+
for (const flow of graph.flows) {
|
|
89
|
+
if (!flow.id) {
|
|
90
|
+
errors.push('Logic flow id is required.');
|
|
91
|
+
}
|
|
92
|
+
if (flowIds.has(flow.id)) {
|
|
93
|
+
errors.push(`Duplicate logic flow id "${flow.id}".`);
|
|
94
|
+
}
|
|
95
|
+
flowIds.add(flow.id);
|
|
96
|
+
if (context.actions && !actionExists(context.actions, flow.action)) {
|
|
97
|
+
errors.push(`Logic flow "${flow.id}" references undeclared action "${flow.action}".`);
|
|
98
|
+
}
|
|
99
|
+
for (const step of flow.steps) {
|
|
100
|
+
validateStep(step, flow, context, errors);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
ok: errors.length === 0,
|
|
105
|
+
errors,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function accessPath(root, path) {
|
|
109
|
+
if (path.includes(' - ') || path.includes(' + ')) {
|
|
110
|
+
const [left, operator, right] = path.split(/\s+/);
|
|
111
|
+
const numeric = Number(right);
|
|
112
|
+
if ((operator === '-' || operator === '+') && Number.isFinite(numeric)) {
|
|
113
|
+
return `(${accessPath(root, left)} ${operator} ${JSON.stringify(numeric)})`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return `${root}${path.split('.').map((part) => `[${JSON.stringify(part)}]`).join('')}`;
|
|
117
|
+
}
|
|
118
|
+
function compileValue(value) {
|
|
119
|
+
switch (value.kind) {
|
|
120
|
+
case 'const':
|
|
121
|
+
return JSON.stringify(value.value);
|
|
122
|
+
case 'state':
|
|
123
|
+
return accessPath('context.state', value.path);
|
|
124
|
+
case 'payload':
|
|
125
|
+
return accessPath('payload', value.path);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function compileCondition(condition) {
|
|
129
|
+
const left = compileValue(condition.left);
|
|
130
|
+
const right = condition.right ? compileValue(condition.right) : undefined;
|
|
131
|
+
switch (condition.op) {
|
|
132
|
+
case 'truthy':
|
|
133
|
+
return `Boolean(${left})`;
|
|
134
|
+
case 'falsy':
|
|
135
|
+
return `!Boolean(${left})`;
|
|
136
|
+
case 'eq':
|
|
137
|
+
return `${left} === ${right}`;
|
|
138
|
+
case 'neq':
|
|
139
|
+
return `${left} !== ${right}`;
|
|
140
|
+
case 'lt':
|
|
141
|
+
return `${left} < ${right}`;
|
|
142
|
+
case 'lte':
|
|
143
|
+
return `${left} <= ${right}`;
|
|
144
|
+
case 'gt':
|
|
145
|
+
return `${left} > ${right}`;
|
|
146
|
+
case 'gte':
|
|
147
|
+
return `${left} >= ${right}`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function compileStep(step) {
|
|
151
|
+
switch (step.type) {
|
|
152
|
+
case 'condition':
|
|
153
|
+
return ` if (!(${compileCondition(step.condition)})) return;`;
|
|
154
|
+
case 'setState':
|
|
155
|
+
return ` ${accessPath('context.state', step.path)} = ${compileValue(step.value)};`;
|
|
156
|
+
case 'setNodeVisible':
|
|
157
|
+
return ` context.setNodeVisible?.(${JSON.stringify(step.node)}, ${JSON.stringify(step.visible)});`;
|
|
158
|
+
case 'emitAction':
|
|
159
|
+
return ` context.emit?.(${JSON.stringify(step.action)});`;
|
|
160
|
+
case 'comment':
|
|
161
|
+
return ` // ${step.text.replaceAll('\n', ' ')}`;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
export function compileLogicGraphToTypescript(graph) {
|
|
165
|
+
const handlers = graph.flows.map((flow) => {
|
|
166
|
+
const steps = flow.steps.map(compileStep).join('\n');
|
|
167
|
+
return ` ${JSON.stringify(flow.action)}(context: LogicRuntimeContext, payload: Record<string, unknown> = {}) {\n${steps}\n },`;
|
|
168
|
+
}).join('\n');
|
|
169
|
+
return `export interface LogicRuntimeContext {
|
|
170
|
+
state: Record<string, unknown>;
|
|
171
|
+
emit?: (action: string, payload?: unknown) => void;
|
|
172
|
+
setNodeVisible?: (node: string, visible: boolean) => void;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const logicHandlers = {
|
|
176
|
+
${handlers}
|
|
177
|
+
};
|
|
178
|
+
`;
|
|
179
|
+
}
|
|
180
|
+
export function summarizeLogicGraphForAi(graph) {
|
|
181
|
+
return (graph?.flows ?? [])
|
|
182
|
+
.map((flow) => `- ${flow.action}: ${flow.steps.map((step) => step.type).join(' -> ')}`)
|
|
183
|
+
.join('\n');
|
|
184
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface LockSpec {
|
|
2
|
+
target: 'transform' | 'component' | 'nodeData';
|
|
3
|
+
node: string;
|
|
4
|
+
field?: string;
|
|
5
|
+
component?: string;
|
|
6
|
+
prop: string;
|
|
7
|
+
reason?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface OverrideSpec {
|
|
10
|
+
source: 'manual' | 'agent';
|
|
11
|
+
target: string;
|
|
12
|
+
before: unknown;
|
|
13
|
+
after: unknown;
|
|
14
|
+
reason?: string;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function lockKey(lock: Omit<LockSpec, 'reason'>): string;
|
|
18
|
+
export declare function isLocked(locks: readonly LockSpec[] | undefined, candidate: Omit<LockSpec, 'reason'>): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function lockKey(lock) {
|
|
2
|
+
if (lock.target === 'transform') {
|
|
3
|
+
return `${lock.node}.transform.${lock.prop}`;
|
|
4
|
+
}
|
|
5
|
+
if (lock.target === 'nodeData') {
|
|
6
|
+
return `${lock.node}.${lock.field}.${lock.prop}`;
|
|
7
|
+
}
|
|
8
|
+
return `${lock.node}.${lock.component}.${lock.prop}`;
|
|
9
|
+
}
|
|
10
|
+
export function isLocked(locks, candidate) {
|
|
11
|
+
return (locks ?? []).some((lock) => {
|
|
12
|
+
if (lock.target !== candidate.target || lock.node !== candidate.node || lock.prop !== candidate.prop) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (candidate.target === 'component') {
|
|
16
|
+
return lock.component === candidate.component;
|
|
17
|
+
}
|
|
18
|
+
if (candidate.target === 'nodeData') {
|
|
19
|
+
return lock.field === candidate.field;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { OverrideSpec } from "./OverrideJournal.js";
|
|
2
|
+
export interface PreferenceMemory {
|
|
3
|
+
id: string;
|
|
4
|
+
context: string;
|
|
5
|
+
pattern: string;
|
|
6
|
+
before?: unknown;
|
|
7
|
+
after: unknown;
|
|
8
|
+
reason?: string;
|
|
9
|
+
confidence: number;
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
source?: 'manual' | 'imported' | 'agent';
|
|
12
|
+
}
|
|
13
|
+
export interface MemorySuggestion {
|
|
14
|
+
id: string;
|
|
15
|
+
memory: PreferenceMemory;
|
|
16
|
+
sourceOverride: OverrideSpec;
|
|
17
|
+
}
|
|
18
|
+
export declare function createMemorySuggestion(override: OverrideSpec): MemorySuggestion | undefined;
|
|
19
|
+
export declare function createMemorySuggestions(overrides: readonly OverrideSpec[]): MemorySuggestion[];
|
|
20
|
+
export declare function summarizeMemoryForAgent(memory: readonly PreferenceMemory[]): string;
|
|
21
|
+
export declare function enabledMemory(memory: readonly PreferenceMemory[]): PreferenceMemory[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
function propFromTarget(target) {
|
|
2
|
+
const parts = target.split('.');
|
|
3
|
+
return parts.at(-1) ?? target;
|
|
4
|
+
}
|
|
5
|
+
export function createMemorySuggestion(override) {
|
|
6
|
+
if (override.source !== 'manual') {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const prop = propFromTarget(override.target);
|
|
10
|
+
return {
|
|
11
|
+
id: `suggestion-${override.timestamp}-${override.target}`,
|
|
12
|
+
sourceOverride: override,
|
|
13
|
+
memory: {
|
|
14
|
+
id: `memory-${override.timestamp}-${override.target}`,
|
|
15
|
+
context: override.target,
|
|
16
|
+
pattern: `When editing ${override.target}, prefer ${prop}=${JSON.stringify(override.after)}.`,
|
|
17
|
+
before: override.before,
|
|
18
|
+
after: override.after,
|
|
19
|
+
reason: override.reason,
|
|
20
|
+
confidence: 0.5,
|
|
21
|
+
enabled: true,
|
|
22
|
+
source: 'manual',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function createMemorySuggestions(overrides) {
|
|
27
|
+
return overrides
|
|
28
|
+
.map(createMemorySuggestion)
|
|
29
|
+
.filter((suggestion) => !!suggestion);
|
|
30
|
+
}
|
|
31
|
+
export function summarizeMemoryForAgent(memory) {
|
|
32
|
+
return memory
|
|
33
|
+
.filter((item) => item.enabled !== false)
|
|
34
|
+
.map((item) => `- ${item.pattern}`)
|
|
35
|
+
.join('\n');
|
|
36
|
+
}
|
|
37
|
+
export function enabledMemory(memory) {
|
|
38
|
+
return memory.filter((item) => item.enabled !== false);
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const pixifactProjectConfigFileName = "pixifact.project.json";
|
|
2
|
+
export interface PixifactProjectRunConfig {
|
|
3
|
+
command: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
cwd: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PixifactProjectConfig {
|
|
9
|
+
version: 1;
|
|
10
|
+
name: string;
|
|
11
|
+
scenes: Record<string, string>;
|
|
12
|
+
run?: PixifactProjectRunConfig;
|
|
13
|
+
}
|
|
14
|
+
export interface PixifactProjectSummary {
|
|
15
|
+
name: string;
|
|
16
|
+
scenes: Record<string, string>;
|
|
17
|
+
run?: PixifactProjectRunConfig;
|
|
18
|
+
}
|
|
19
|
+
export declare function parsePixifactProjectConfig(value: unknown): PixifactProjectConfig;
|
|
20
|
+
export declare function summarizePixifactProjectConfig(config: PixifactProjectConfig): PixifactProjectSummary;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export const pixifactProjectConfigFileName = 'pixifact.project.json';
|
|
2
|
+
function isRecord(value) {
|
|
3
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
function assertRecord(value, name) {
|
|
6
|
+
if (!isRecord(value)) {
|
|
7
|
+
throw new Error(`${name} must be an object.`);
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
function assertString(value, name) {
|
|
12
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
13
|
+
throw new Error(`${name} must be a non-empty string.`);
|
|
14
|
+
}
|
|
15
|
+
return value.trim();
|
|
16
|
+
}
|
|
17
|
+
function normalizeProjectPath(value, name) {
|
|
18
|
+
const input = assertString(value, name).replaceAll('\\', '/');
|
|
19
|
+
if (input.startsWith('/') || /^[A-Za-z]:\//.test(input)) {
|
|
20
|
+
throw new Error(`${name} must be project-relative.`);
|
|
21
|
+
}
|
|
22
|
+
const parts = input.split('/');
|
|
23
|
+
if (parts.some((part) => part === '..')) {
|
|
24
|
+
throw new Error(`${name} must stay inside projectRoot.`);
|
|
25
|
+
}
|
|
26
|
+
if (parts.some((part) => part === '')) {
|
|
27
|
+
throw new Error(`${name} must not contain empty path segments.`);
|
|
28
|
+
}
|
|
29
|
+
return input;
|
|
30
|
+
}
|
|
31
|
+
function normalizeRunCwd(value) {
|
|
32
|
+
const input = assertString(value, 'run.cwd').replaceAll('\\', '/');
|
|
33
|
+
if (input === '.') {
|
|
34
|
+
return input;
|
|
35
|
+
}
|
|
36
|
+
return normalizeProjectPath(input, 'run.cwd');
|
|
37
|
+
}
|
|
38
|
+
function parseScenes(value) {
|
|
39
|
+
const scenes = assertRecord(value, 'scenes');
|
|
40
|
+
return Object.fromEntries(Object.entries(scenes).map(([key, scenePath]) => [
|
|
41
|
+
assertString(key, 'scene key'),
|
|
42
|
+
normalizeProjectPath(scenePath, `scenes.${key}`),
|
|
43
|
+
]));
|
|
44
|
+
}
|
|
45
|
+
function parseRun(value) {
|
|
46
|
+
if (value === undefined) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const run = assertRecord(value, 'run');
|
|
50
|
+
if (!Array.isArray(run.args) || !run.args.every((arg) => typeof arg === 'string')) {
|
|
51
|
+
throw new Error('run.args must be an array of strings.');
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
command: assertString(run.command, 'run.command'),
|
|
55
|
+
args: run.args,
|
|
56
|
+
cwd: normalizeRunCwd(run.cwd),
|
|
57
|
+
...(run.url === undefined ? {} : { url: assertString(run.url, 'run.url') }),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function parsePixifactProjectConfig(value) {
|
|
61
|
+
const config = assertRecord(value, 'pixifact.project.json');
|
|
62
|
+
if (config.version !== 1) {
|
|
63
|
+
throw new Error('pixifact.project.json version must be 1.');
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
version: 1,
|
|
67
|
+
name: assertString(config.name, 'name'),
|
|
68
|
+
scenes: parseScenes(config.scenes),
|
|
69
|
+
run: parseRun(config.run),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function summarizePixifactProjectConfig(config) {
|
|
73
|
+
return {
|
|
74
|
+
name: config.name,
|
|
75
|
+
scenes: config.scenes,
|
|
76
|
+
...(config.run === undefined ? {} : { run: config.run }),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Group } from "../runtime/index.js";
|
|
2
|
+
import type { Component } from "../runtime/index.js";
|
|
3
|
+
import type { InstantiateContext, SceneSpec } from "../scene/index.js";
|
|
4
|
+
export interface RuntimePreview {
|
|
5
|
+
root: Group;
|
|
6
|
+
nodes: Map<string, Group>;
|
|
7
|
+
components: Map<string, Component>;
|
|
8
|
+
resolveNode(runtimeNode: Group): string | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function createRuntimePreview(scene: SceneSpec, parent?: Group, context?: InstantiateContext): RuntimePreview;
|
|
11
|
+
export declare function destroyRuntimePreview(preview?: RuntimePreview): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { GameObject } from "../runtime/index.js";
|
|
2
|
+
import { instantiate } from "../scene/index.js";
|
|
3
|
+
export function createRuntimePreview(scene, parent, context) {
|
|
4
|
+
const result = instantiate(scene, parent, context);
|
|
5
|
+
const nodeIdsByObject = new WeakMap();
|
|
6
|
+
for (const [id, node] of result.nodes) {
|
|
7
|
+
if (!nodeIdsByObject.has(node)) {
|
|
8
|
+
nodeIdsByObject.set(node, id);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
root: result.root,
|
|
13
|
+
nodes: result.nodes,
|
|
14
|
+
components: result.components,
|
|
15
|
+
resolveNode(runtimeNode) {
|
|
16
|
+
return nodeIdsByObject.get(runtimeNode);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function destroyRuntimePreview(preview) {
|
|
21
|
+
if (!preview) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
GameObject.destroy(preview.root);
|
|
25
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import EventEmitter from "eventemitter3";
|
|
2
|
+
import type { SceneCommand } from "../commands/Command.js";
|
|
3
|
+
import type { CommandResult } from "../commands/applyCommand.js";
|
|
4
|
+
import type { InstantiateContext, SceneSpec } from "../scene/index.js";
|
|
5
|
+
import type { Group } from "../runtime/index.js";
|
|
6
|
+
import type { SceneSelection } from "./SceneSelection.js";
|
|
7
|
+
import type { InspectorNodeModel } from "./InspectorModel.js";
|
|
8
|
+
import type { RuntimePreview } from "./RuntimePreview.js";
|
|
9
|
+
import type { LockSpec, OverrideSpec } from "./OverrideJournal.js";
|
|
10
|
+
import type { MemorySuggestion, PreferenceMemory } from "./PreferenceMemory.js";
|
|
11
|
+
import type { SceneProjectState } from "./SceneProjectState.js";
|
|
12
|
+
import type { DesignTokenSpec } from "./DesignToken.js";
|
|
13
|
+
import type { ActionSpec } from "./ActionRegistry.js";
|
|
14
|
+
import type { LogicFlowSpec, LogicGraphSpec } from "./LogicGraph.js";
|
|
15
|
+
export interface SceneDocumentEventMap {
|
|
16
|
+
changed: [result: CommandResult];
|
|
17
|
+
loaded: [scene: SceneSpec];
|
|
18
|
+
previewRebuilt: [preview: RuntimePreview];
|
|
19
|
+
selectionChanged: [selection: SceneSelection];
|
|
20
|
+
}
|
|
21
|
+
export declare class SceneDocument {
|
|
22
|
+
scene: SceneSpec;
|
|
23
|
+
selection: SceneSelection;
|
|
24
|
+
dirty: boolean;
|
|
25
|
+
emitter: EventEmitter<SceneDocumentEventMap, any>;
|
|
26
|
+
preview?: RuntimePreview;
|
|
27
|
+
locks: LockSpec[];
|
|
28
|
+
overrides: OverrideSpec[];
|
|
29
|
+
memory: PreferenceMemory[];
|
|
30
|
+
designTokens?: DesignTokenSpec;
|
|
31
|
+
actions: ActionSpec[];
|
|
32
|
+
logicGraph: LogicGraphSpec;
|
|
33
|
+
private commandStack;
|
|
34
|
+
private previewContext?;
|
|
35
|
+
private previewParent?;
|
|
36
|
+
constructor(scene: SceneSpec);
|
|
37
|
+
apply(command: SceneCommand, source?: OverrideSpec['source']): CommandResult;
|
|
38
|
+
addLock(lock: LockSpec): void;
|
|
39
|
+
removeLock(lock: Omit<LockSpec, 'reason'>): void;
|
|
40
|
+
getMemorySuggestions(): MemorySuggestion[];
|
|
41
|
+
acceptMemorySuggestion(suggestion: MemorySuggestion): void;
|
|
42
|
+
upsertMemory(memory: PreferenceMemory): void;
|
|
43
|
+
setMemoryEnabled(id: string, enabled: boolean): void;
|
|
44
|
+
removeMemory(id: string): void;
|
|
45
|
+
importMemory(memory: readonly PreferenceMemory[], replace?: boolean): void;
|
|
46
|
+
addAction(action: ActionSpec): void;
|
|
47
|
+
removeAction(key: string): void;
|
|
48
|
+
addLogicFlow(flow: LogicFlowSpec): {
|
|
49
|
+
ok: false;
|
|
50
|
+
errors: string[];
|
|
51
|
+
graph?: undefined;
|
|
52
|
+
} | {
|
|
53
|
+
ok: true;
|
|
54
|
+
graph: LogicGraphSpec;
|
|
55
|
+
errors?: undefined;
|
|
56
|
+
};
|
|
57
|
+
removeLogicFlow(id: string): void;
|
|
58
|
+
private recordOverride;
|
|
59
|
+
undo(): CommandResult | undefined;
|
|
60
|
+
redo(): CommandResult | undefined;
|
|
61
|
+
get canUndo(): boolean;
|
|
62
|
+
get canRedo(): boolean;
|
|
63
|
+
setSelection(selection: SceneSelection): void;
|
|
64
|
+
private ensureSelectionValid;
|
|
65
|
+
serialize(): string;
|
|
66
|
+
serializeState(): string;
|
|
67
|
+
getState(): SceneProjectState;
|
|
68
|
+
load(json: string | SceneSpec | SceneProjectState): void;
|
|
69
|
+
loadState(state: SceneProjectState): void;
|
|
70
|
+
rebuildPreview(context?: InstantiateContext | undefined, parent?: Group | undefined): RuntimePreview;
|
|
71
|
+
getInspectorModel(node?: string | undefined): InspectorNodeModel | undefined;
|
|
72
|
+
clearPreview(): void;
|
|
73
|
+
destroy(): void;
|
|
74
|
+
}
|