@world-engines/blocks-editor 0.1.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 (76) hide show
  1. package/LICENSE +46 -0
  2. package/README.md +40 -0
  3. package/dist/adapters/trigger.d.ts +72 -0
  4. package/dist/adapters/trigger.js +206 -0
  5. package/dist/blockly-config.d.ts +3 -0
  6. package/dist/blockly-config.js +7 -0
  7. package/dist/blocks/ctx.d.ts +67 -0
  8. package/dist/blocks/ctx.js +96 -0
  9. package/dist/blocks/registry-taxonomy.d.ts +12 -0
  10. package/dist/blocks/registry-taxonomy.js +79 -0
  11. package/dist/blocks/registry.d.ts +39 -0
  12. package/dist/blocks/registry.js +1000 -0
  13. package/dist/blocks/time-fields.d.ts +16 -0
  14. package/dist/blocks/time-fields.js +45 -0
  15. package/dist/blocks/toolbox.d.ts +53 -0
  16. package/dist/blocks/toolbox.js +195 -0
  17. package/dist/fields/AttrPickerField.d.ts +13 -0
  18. package/dist/fields/AttrPickerField.js +48 -0
  19. package/dist/fields/EdgePickerField.d.ts +10 -0
  20. package/dist/fields/EdgePickerField.js +36 -0
  21. package/dist/fields/EntityPickerField.d.ts +10 -0
  22. package/dist/fields/EntityPickerField.js +36 -0
  23. package/dist/fields/StatePickerField.d.ts +13 -0
  24. package/dist/fields/StatePickerField.js +47 -0
  25. package/dist/fields/TimePickerField.d.ts +10 -0
  26. package/dist/fields/TimePickerField.js +81 -0
  27. package/dist/fields/picker-events.d.ts +21 -0
  28. package/dist/fields/picker-events.js +28 -0
  29. package/dist/fields/register.d.ts +6 -0
  30. package/dist/fields/register.js +22 -0
  31. package/dist/i18n/messages-zh.d.ts +6 -0
  32. package/dist/i18n/messages-zh.js +34 -0
  33. package/dist/index.d.ts +21 -0
  34. package/dist/index.js +11 -0
  35. package/dist/migration/index.d.ts +1 -0
  36. package/dist/migration/index.js +1 -0
  37. package/dist/migration/types.d.ts +91 -0
  38. package/dist/migration/types.js +1 -0
  39. package/dist/react/PickerHost.d.ts +6 -0
  40. package/dist/react/PickerHost.js +110 -0
  41. package/dist/sdk-to-block/index.d.ts +4 -0
  42. package/dist/sdk-to-block/index.js +4 -0
  43. package/dist/sdk-to-block/parser.d.ts +2 -0
  44. package/dist/sdk-to-block/parser.js +101 -0
  45. package/dist/sdk-to-block/register.d.ts +3 -0
  46. package/dist/sdk-to-block/register.js +27 -0
  47. package/dist/sdk-to-block/signature.d.ts +31 -0
  48. package/dist/sdk-to-block/signature.js +12 -0
  49. package/dist/sdk-to-block/to-block-def.d.ts +25 -0
  50. package/dist/sdk-to-block/to-block-def.js +71 -0
  51. package/dist/themes/index.d.ts +4 -0
  52. package/dist/themes/index.js +12 -0
  53. package/dist/themes/liquid-glass-dark.d.ts +57 -0
  54. package/dist/themes/liquid-glass-dark.js +187 -0
  55. package/dist/themes/liquid-glass.css +195 -0
  56. package/dist/view-to-block/index.d.ts +10 -0
  57. package/dist/view-to-block/index.js +67 -0
  58. package/dist/workspace.d.ts +33 -0
  59. package/dist/workspace.js +306 -0
  60. package/package.json +65 -0
  61. package/public/blockly-media/1x1.gif +0 -0
  62. package/public/blockly-media/click.mp3 +0 -0
  63. package/public/blockly-media/delete-icon.svg +1 -0
  64. package/public/blockly-media/delete.mp3 +0 -0
  65. package/public/blockly-media/disconnect.mp3 +0 -0
  66. package/public/blockly-media/drop.mp3 +0 -0
  67. package/public/blockly-media/dropdown-arrow.svg +1 -0
  68. package/public/blockly-media/foldout-icon.svg +1 -0
  69. package/public/blockly-media/handclosed.cur +0 -0
  70. package/public/blockly-media/handdelete.cur +0 -0
  71. package/public/blockly-media/handopen.cur +0 -0
  72. package/public/blockly-media/pilcrow.png +0 -0
  73. package/public/blockly-media/quote0.png +0 -0
  74. package/public/blockly-media/quote1.png +0 -0
  75. package/public/blockly-media/resize-handle.svg +3 -0
  76. package/public/blockly-media/sprites.svg +74 -0
@@ -0,0 +1,306 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from "react";
3
+ import * as Blockly from "blockly";
4
+ import { BlocklyWorkspace } from "react-blockly";
5
+ import { BlocksEditorCtxContext, EMPTY_CTX, attachCtxToWorkspace } from "./blocks/ctx.js";
6
+ import { BLOCK_TYPES, registerTriggerBlocks } from "./blocks/registry.js";
7
+ import { buildToolbox, CATEGORY_IDS, categoryDisplayNameOf } from "./blocks/toolbox.js";
8
+ import { registerPickerFieldsOnce } from "./fields/register.js";
9
+ import { PickerHost } from "./react/PickerHost.js";
10
+ import { applyLiquidGlassCss, liquidGlassDarkTheme } from "./themes/index.js";
11
+ import { GRID_COLOUR } from "./themes/liquid-glass-dark.js";
12
+ import { applyDragTolerance } from "./blockly-config.js";
13
+ import { applyZhMessages } from "./i18n/messages-zh.js";
14
+ import { parseTmwWorkspaceV3, TMW_CONDITION_BLOCK_TYPES } from "./adapters/trigger.js";
15
+ import { isViewActionBlockType, registerViewBlocks } from "./view-to-block/index.js";
16
+ applyZhMessages(Blockly);
17
+ applyDragTolerance();
18
+ const DEFAULT_MEDIA_BASE = "/blockly-media/";
19
+ const EMPTY_WORKSPACE_JSON = '{"blocks":{"languageVersion":0,"blocks":[]}}';
20
+ const TMW_CONDITION_MUTATOR = "tmw_v3_condition_items";
21
+ let tmwConditionBlocksRegistered = false;
22
+ const registerTmwConditionBlocks = () => {
23
+ if (tmwConditionBlocksRegistered)
24
+ return;
25
+ if (!Blockly.Extensions.isRegistered(TMW_CONDITION_MUTATOR)) {
26
+ Blockly.Extensions.registerMutator(TMW_CONDITION_MUTATOR, {
27
+ itemCount_: 2,
28
+ saveExtraState() { return { itemCount: this.itemCount_ }; },
29
+ loadExtraState(state) {
30
+ const count = typeof state.itemCount === "number" ? state.itemCount : 2;
31
+ this.itemCount_ = Math.max(1, Math.min(16, Math.floor(count)));
32
+ this.updateShape_();
33
+ },
34
+ updateShape_() {
35
+ let index = 0;
36
+ while (this.getInput(`ITEM${index}`) !== null)
37
+ this.removeInput(`ITEM${index++}`);
38
+ for (let item = 0; item < this.itemCount_; item += 1) {
39
+ this.appendValueInput(`ITEM${item}`).setCheck("Boolean").appendField(item === 0 ? "条件" : "以及");
40
+ }
41
+ }
42
+ });
43
+ }
44
+ Blockly.common.defineBlocksWithJsonArray([
45
+ {
46
+ type: TMW_CONDITION_BLOCK_TYPES.root,
47
+ message0: "条件节点 %1",
48
+ args0: [{ type: "field_input", name: "STABLE_ID", text: "condition.new" }],
49
+ message1: "时钟 %1 到期 %2 生效 %3 穿越 %4",
50
+ args1: [
51
+ { type: "field_dropdown", name: "DOMAIN", options: [["逻辑序", "logical_seq"], ["世界时间", "world_time"], ["演出序", "presentation_seq"], ["真实时间", "real_time"]] },
52
+ { type: "field_number", name: "DUE_VALUE", value: 0 },
53
+ { type: "field_number", name: "EFFECTIVE_VALUE", value: 0 },
54
+ { type: "field_dropdown", name: "CROSSING_POLICY", options: [["仅正向", "forward_only"], ["仅反向", "backward_only"], ["双向", "both_directions"]] },
55
+ ],
56
+ message2: "真实时钟 %1 挂起策略 %2",
57
+ args2: [
58
+ { type: "field_dropdown", name: "REAL_TIME_CLOCK", options: [["活跃游玩", "active_play"], ["会话单调钟", "monotonic_session"], ["墙上时间", "wall_clock"]] },
59
+ { type: "field_dropdown", name: "WALL_CLOCK_POLICY", options: [["仅活跃会话", "active_session_only"], ["挂起仍流逝", "elapse_while_suspended"], ["拒绝挂起", "reject"]] },
60
+ ],
61
+ message3: "满足 %1",
62
+ args3: [{ type: "input_value", name: "EXPRESSION", check: "Boolean" }],
63
+ colour: 174,
64
+ tooltip: "现行 TriggerDocumentV3 condition;时间坐标和表达式一起无损写回",
65
+ },
66
+ { type: TMW_CONDITION_BLOCK_TYPES.all, message0: "全部满足", output: "Boolean", colour: 118, mutator: TMW_CONDITION_MUTATOR },
67
+ { type: TMW_CONDITION_BLOCK_TYPES.any, message0: "任一满足", output: "Boolean", colour: 118, mutator: TMW_CONDITION_MUTATOR },
68
+ { type: TMW_CONDITION_BLOCK_TYPES.not, message0: "不满足 %1", args0: [{ type: "input_value", name: "VALUE", check: "Boolean" }], output: "Boolean", colour: 118 },
69
+ { type: TMW_CONDITION_BLOCK_TYPES.literal, message0: "常量 %1", args0: [{ type: "field_dropdown", name: "VALUE", options: [["真", "TRUE"], ["假", "FALSE"]] }], output: "Boolean", colour: 210 },
70
+ {
71
+ type: TMW_CONDITION_BLOCK_TYPES.eventField,
72
+ message0: "事件属性 %1 %2 JSON %3",
73
+ args0: [
74
+ { type: "field_input", name: "PATH", text: "timestamp" },
75
+ { type: "field_dropdown", name: "COMPARISON", options: [["=", "eq"], ["≠", "neq"], [">", "gt"], ["≥", "gte"], ["<", "lt"], ["≤", "lte"], ["包含", "contains"]] },
76
+ { type: "field_input", name: "VALUE_JSON", text: "0" },
77
+ ],
78
+ output: "Boolean",
79
+ colour: 210,
80
+ tooltip: "读取本次 committed event payload 的属性;timestamp 也是普通事件属性",
81
+ },
82
+ { type: TMW_CONDITION_BLOCK_TYPES.selectorExists, message0: "存在选择器 JSON %1", args0: [{ type: "field_input", name: "SELECTOR_JSON", text: "{\"op\":\"entity_kind\",\"entity_kind\":\"npc\"}" }], output: "Boolean", colour: 210 },
83
+ {
84
+ type: TMW_CONDITION_BLOCK_TYPES.naturalLanguage,
85
+ message0: "请 Judge 判断 %1",
86
+ args0: [{ type: "field_input", name: "TEXT", text: "自然语言条件" }],
87
+ message1: "叶子 ID %1 locale %2",
88
+ args1: [{ type: "field_input", name: "STABLE_ID", text: "nl.condition" }, { type: "field_input", name: "LOCALE", text: "zh-CN" }],
89
+ message2: "可选 anchor JSON %1",
90
+ args2: [{ type: "field_input", name: "ANCHOR_JSON", text: "" }],
91
+ output: "Boolean",
92
+ colour: 285,
93
+ tooltip: "现行 TMW3 nl_condition;运行时产生 unknown 并请求语义 Judge,不直接视为 true",
94
+ },
95
+ ]);
96
+ tmwConditionBlocksRegistered = true;
97
+ };
98
+ const TMW_CONDITION_TOOLBOX = {
99
+ kind: "categoryToolbox",
100
+ contents: [
101
+ { kind: "category", name: "条件节点", colour: "#16897b", contents: [{ kind: "block", type: TMW_CONDITION_BLOCK_TYPES.root }] },
102
+ { kind: "category", name: "逻辑", colour: "#59a83b", contents: [
103
+ { kind: "block", type: TMW_CONDITION_BLOCK_TYPES.all },
104
+ { kind: "block", type: TMW_CONDITION_BLOCK_TYPES.any },
105
+ { kind: "block", type: TMW_CONDITION_BLOCK_TYPES.not },
106
+ ] },
107
+ { kind: "category", name: "条件", colour: "#3373cc", contents: [
108
+ { kind: "block", type: TMW_CONDITION_BLOCK_TYPES.eventField },
109
+ { kind: "block", type: TMW_CONDITION_BLOCK_TYPES.selectorExists },
110
+ { kind: "block", type: TMW_CONDITION_BLOCK_TYPES.naturalLanguage },
111
+ { kind: "block", type: TMW_CONDITION_BLOCK_TYPES.literal },
112
+ ] },
113
+ ],
114
+ };
115
+ const parseWorkspaceJson = (raw, schema, authorizedViewBlockTypes) => {
116
+ const parsed = parseTmwWorkspaceV3(JSON.parse(raw));
117
+ if (schema === "trigger-definition") {
118
+ const roots = parsed.blocks?.blocks?.filter((block) => block.type === BLOCK_TYPES.triggerRoot) ?? [];
119
+ if (roots.length > 1)
120
+ throw new Error(`trigger_definition_workspace_multiple_roots:${roots.length}`);
121
+ }
122
+ const persistedViewBlockTypes = new Set();
123
+ const collectViewBlockTypes = (node) => {
124
+ if (node === undefined)
125
+ return;
126
+ if (isViewActionBlockType(node.type))
127
+ persistedViewBlockTypes.add(node.type);
128
+ for (const slot of Object.values(node.inputs ?? {}))
129
+ collectViewBlockTypes(slot.block);
130
+ collectViewBlockTypes(node.next?.block);
131
+ };
132
+ for (const root of parsed.blocks?.blocks ?? [])
133
+ collectViewBlockTypes(root);
134
+ const unauthorized = [...persistedViewBlockTypes]
135
+ .filter((type) => !authorizedViewBlockTypes.has(type));
136
+ if (unauthorized.length > 0) {
137
+ throw new Error(`tmw_workspace_view_capability_revoked:${unauthorized.sort().join(",")}`);
138
+ }
139
+ return { parsed, serialized: JSON.stringify(parsed) };
140
+ };
141
+ const disableUnauthorizedViewBlocks = (workspace, authorizedViewBlockTypes) => {
142
+ for (const block of workspace.getAllBlocks(false)) {
143
+ if (!isViewActionBlockType(block.type) || authorizedViewBlockTypes.has(block.type))
144
+ continue;
145
+ block.setDisabledReason(true, "unauthorized_view_action");
146
+ block.setWarningText("此视图操作不属于当前 manifest 版本,已禁用且不会编译执行。");
147
+ }
148
+ };
149
+ const SHELL_STYLE = {
150
+ display: "flex",
151
+ flexDirection: "column",
152
+ gap: "0.5rem",
153
+ height: "100%",
154
+ flex: 1,
155
+ minHeight: 0
156
+ };
157
+ const WORKSPACE_HOST_STYLE = { flex: 1, minHeight: "20rem" };
158
+ const TriggerWorkspace = ({ schema, workspaceJson, ctx, onWorkspaceJsonChange, mediaBaseUrl, toolbox, authorizedViewBlockTypes, className, workspaceRefOut }) => {
159
+ // Registration must precede the child BlocklyWorkspace render, but it must not run
160
+ // as an import side effect because Rollup may evaluate this workspace module in
161
+ // multiple chunks that share Blockly's global block registry.
162
+ registerTriggerBlocks();
163
+ if (schema === "tmw-condition-v3")
164
+ registerTmwConditionBlocks();
165
+ registerPickerFieldsOnce();
166
+ const containerRef = useRef(null);
167
+ const onChangeRef = useRef(onWorkspaceJsonChange);
168
+ onChangeRef.current = onWorkspaceJsonChange;
169
+ const initialJsonRef = useRef(workspaceJson);
170
+ initialJsonRef.current = workspaceJson;
171
+ const lastEmittedRef = useRef("");
172
+ useEffect(() => {
173
+ const workspace = workspaceRefOut.current;
174
+ if (workspace === null || workspaceJson.length === 0)
175
+ return;
176
+ const current = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
177
+ const target = parseWorkspaceJson(workspaceJson, schema, authorizedViewBlockTypes);
178
+ Blockly.Events.disable();
179
+ try {
180
+ if (current === target.serialized) {
181
+ disableUnauthorizedViewBlocks(workspace, authorizedViewBlockTypes);
182
+ return;
183
+ }
184
+ lastEmittedRef.current = target.serialized;
185
+ Blockly.serialization.workspaces.load(target.parsed, workspace);
186
+ disableUnauthorizedViewBlocks(workspace, authorizedViewBlockTypes);
187
+ }
188
+ finally {
189
+ Blockly.Events.enable();
190
+ }
191
+ if (target.serialized !== workspaceJson)
192
+ onChangeRef.current(target.serialized);
193
+ }, [authorizedViewBlockTypes, schema, workspaceJson, workspaceRefOut]);
194
+ useEffect(() => {
195
+ const workspace = workspaceRefOut.current;
196
+ if (workspace !== null) {
197
+ attachCtxToWorkspace(workspace, ctx);
198
+ }
199
+ }, [ctx, workspaceRefOut]);
200
+ useEffect(() => {
201
+ const host = containerRef.current;
202
+ if (host === null)
203
+ return;
204
+ return applyLiquidGlassCss(host);
205
+ }, []);
206
+ const workspaceConfiguration = useMemo(() => ({
207
+ theme: liquidGlassDarkTheme,
208
+ media: mediaBaseUrl,
209
+ renderer: "zelos",
210
+ grid: { spacing: 24, length: 2, snap: true, colour: GRID_COLOUR },
211
+ ...(schema === "trigger-definition" || schema === "tmw-condition-v3"
212
+ ? { maxInstances: { [schema === "tmw-condition-v3" ? TMW_CONDITION_BLOCK_TYPES.root : BLOCK_TYPES.triggerRoot]: 1 } }
213
+ : {}),
214
+ trashcan: false,
215
+ zoom: { controls: false, wheel: true, startScale: 0.9, maxScale: 1.5, minScale: 0.5 }
216
+ }), [mediaBaseUrl, schema]);
217
+ const handleWorkspaceChange = useCallback((workspace) => {
218
+ const workspaceJsonNext = Blockly.serialization.workspaces.save(workspace);
219
+ const serialized = JSON.stringify(workspaceJsonNext);
220
+ if (lastEmittedRef.current === serialized)
221
+ return;
222
+ lastEmittedRef.current = serialized;
223
+ onChangeRef.current(serialized);
224
+ }, []);
225
+ const handleInject = useCallback((workspace) => {
226
+ workspaceRefOut.current = workspace;
227
+ attachCtxToWorkspace(workspace, ctx);
228
+ const seed = initialJsonRef.current;
229
+ if (seed.length === 0)
230
+ return;
231
+ try {
232
+ const target = parseWorkspaceJson(seed, schema, authorizedViewBlockTypes);
233
+ const parsed = target.parsed;
234
+ lastEmittedRef.current = target.serialized;
235
+ Blockly.serialization.workspaces.load(parsed, workspace);
236
+ disableUnauthorizedViewBlocks(workspace, authorizedViewBlockTypes);
237
+ if (target.serialized !== seed)
238
+ onChangeRef.current(target.serialized);
239
+ }
240
+ catch (err) {
241
+ console.warn("blocks-editor: failed to load initial workspaceJson", err);
242
+ }
243
+ }, [authorizedViewBlockTypes, ctx, schema, workspaceRefOut]);
244
+ const handleDispose = useCallback(() => {
245
+ workspaceRefOut.current = null;
246
+ }, [workspaceRefOut]);
247
+ return (_jsx("div", { ref: containerRef, className: className, style: WORKSPACE_HOST_STYLE, children: _jsx(BlocklyWorkspace, { className: "blocks-editor__blockly-host", toolboxConfiguration: toolbox, workspaceConfiguration: workspaceConfiguration, onWorkspaceChange: handleWorkspaceChange, onInject: handleInject, onDispose: handleDispose }) }));
248
+ };
249
+ export const BlocksWorkspace = forwardRef(function BlocksWorkspace(props, ref) {
250
+ const { schema, workspaceJson, ctx, onWorkspaceJsonChange, className, mediaBaseUrl } = props;
251
+ if (schema !== "trigger" && schema !== "trigger-definition" && schema !== "tmw-condition-v3") {
252
+ throw new Error(`BlocksWorkspace schema=${schema} not supported yet`);
253
+ }
254
+ const resolvedMedia = mediaBaseUrl ?? DEFAULT_MEDIA_BASE;
255
+ const resolvedJson = workspaceJson.length === 0 ? EMPTY_WORKSPACE_JSON : workspaceJson;
256
+ const workspaceRef = useRef(null);
257
+ const triggerCtx = useMemo(() => {
258
+ const next = {
259
+ event_list: ctx.event_list,
260
+ entity_list: ctx.entity_list
261
+ };
262
+ if (ctx.edge_list !== undefined)
263
+ next.edge_list = ctx.edge_list;
264
+ if (ctx.variable_list !== undefined)
265
+ next.variable_list = ctx.variable_list;
266
+ if (ctx.sdk_catalog !== undefined)
267
+ next.sdk_catalog = ctx.sdk_catalog;
268
+ if (ctx.worldTime !== undefined)
269
+ next.worldTime = ctx.worldTime;
270
+ if (ctx.view_catalog !== undefined)
271
+ next.view_catalog = ctx.view_catalog;
272
+ return next;
273
+ }, [ctx]);
274
+ const viewBlockTypes = useMemo(() => schema === "trigger" && triggerCtx.view_catalog !== undefined
275
+ ? registerViewBlocks(triggerCtx.view_catalog)
276
+ : [], [schema, triggerCtx.view_catalog]);
277
+ const authorizedViewBlockTypes = useMemo(() => new Set(viewBlockTypes), [viewBlockTypes]);
278
+ const toolboxConfiguration = useMemo(() => schema === "tmw-condition-v3"
279
+ ? TMW_CONDITION_TOOLBOX
280
+ : JSON.parse(JSON.stringify(buildToolbox({ schema, viewBlockTypes }))), [schema, viewBlockTypes]);
281
+ useImperativeHandle(ref, () => ({
282
+ selectCategory(id) {
283
+ const ws = workspaceRef.current;
284
+ if (!ws)
285
+ return;
286
+ const toolbox = ws.getToolbox();
287
+ if (!toolbox)
288
+ return;
289
+ const displayName = categoryDisplayNameOf(id);
290
+ const items = toolbox.getToolboxItems?.() ?? [];
291
+ for (let i = 0; i < items.length; i++) {
292
+ const it = items[i];
293
+ const name = it.getName?.();
294
+ if (name === displayName) {
295
+ toolbox.selectItemByPosition?.(i);
296
+ return;
297
+ }
298
+ }
299
+ },
300
+ getWorkspace() {
301
+ return workspaceRef.current;
302
+ }
303
+ }), []);
304
+ return (_jsx(BlocksEditorCtxContext.Provider, { value: triggerCtx ?? EMPTY_CTX, children: _jsxs("div", { className: className, style: SHELL_STYLE, children: [_jsx(TriggerWorkspace, { schema: schema, workspaceJson: resolvedJson, ctx: triggerCtx, onWorkspaceJsonChange: onWorkspaceJsonChange, mediaBaseUrl: resolvedMedia, toolbox: toolboxConfiguration, authorizedViewBlockTypes: authorizedViewBlockTypes, workspaceRefOut: workspaceRef, ...(className ? { className } : {}) }), _jsx(PickerHost, {})] }) }));
305
+ });
306
+ export { CATEGORY_IDS };
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@world-engines/blocks-editor",
3
+ "private": false,
4
+ "version": "0.1.0",
5
+ "description": "面向浏览器与 Vite 的 Blockly 场景编辑器组件",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "browser": "./dist/index.js",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "public",
18
+ "README.md"
19
+ ],
20
+ "peerDependencies": {
21
+ "react": "^18.3.1",
22
+ "react-dom": "^18.3.1"
23
+ },
24
+ "dependencies": {
25
+ "@world-engines/tmw": "0.1.0-alpha.0",
26
+ "@world-engines/protocol-ts": "0.1.0-alpha.0",
27
+ "@world-engines/view-exposure": "0.0.0",
28
+ "@blockly/field-multilineinput": "^6.0.9",
29
+ "@world-engines/monaco-host": "0.1.0",
30
+ "blockly": "^13.1.0",
31
+ "react-blockly": "^9.0.0"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "worldengine_source_sha256": "3d10b3aa183316e67c98fb03db2660a41e8d5e18906e04ea5c685b84cec8c633",
37
+ "worldengine_source_identity_provenance": {
38
+ "schema": "worldengine-public-namespace-projection/v1",
39
+ "kind": "composite-source-identity; namespace projection; not-full-source-recompile",
40
+ "original_name": "@chat/blocks-editor",
41
+ "original_archive_sha256": "78128a459e6d08da84115c261d8bfe775c5f3f763b2cddc3149c038e90bdc99b",
42
+ "original_source_sha256": "375e73a1788e6e4d8966c7342ea9e4e203cd777655d7ee714dcc6c95e0371356",
43
+ "projected_name": "@world-engines/blocks-editor",
44
+ "package_name_mapping": {
45
+ "@chat/blocks-editor": "@world-engines/blocks-editor",
46
+ "@chat/ladybug-bridge": "@world-engines/ladybug-bridge",
47
+ "@chat/monaco-host": "@world-engines/monaco-host",
48
+ "@chat/protocol-ts": "@world-engines/protocol-ts",
49
+ "@chat/scenario-author-source": "@world-engines/scenario-author-source",
50
+ "@chat/scenario-review-snapshot": "@world-engines/scenario-review-snapshot",
51
+ "@chat/tmw": "@world-engines/tmw",
52
+ "@chat/view-exposure": "@world-engines/view-exposure",
53
+ "@world-engines/chatplay-vite-plugin": "@world-engines/chatplay-vite-plugin",
54
+ "@worldengine/agent-kit": "@world-engines/agent-kit",
55
+ "@worldengine/authoring-bridge": "@world-engines/authoring-bridge",
56
+ "@worldengine/authoring-ui": "@world-engines/authoring-ui",
57
+ "@worldengine/create-project": "@world-engines/create-project",
58
+ "@worldengine/project-format": "@world-engines/project-format",
59
+ "@worldengine/project-host": "@world-engines/project-host",
60
+ "@worldengine/project-setup": "@world-engines/project-setup",
61
+ "@worldengine/spatial-authoring": "@world-engines/spatial-authoring",
62
+ "@worldengine/view-sdk": "@world-engines/view-sdk"
63
+ }
64
+ }
65
+ }
Binary file
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="#041E49"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>
Binary file
Binary file
@@ -0,0 +1 @@
1
+ <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="12.71" height="8.79" viewBox="0 0 12.71 8.79"><title>dropdown-arrow</title><g opacity="0.1"><path d="M12.71,2.44A2.41,2.41,0,0,1,12,4.16L8.08,8.08a2.45,2.45,0,0,1-3.45,0L0.72,4.16A2.42,2.42,0,0,1,0,2.44,2.48,2.48,0,0,1,.71.71C1,0.47,1.43,0,6.36,0S11.75,0.46,12,.71A2.44,2.44,0,0,1,12.71,2.44Z" fill="#231f20"/></g><path d="M6.36,7.79a1.43,1.43,0,0,1-1-.42L1.42,3.45a1.44,1.44,0,0,1,0-2c0.56-.56,9.31-0.56,9.87,0a1.44,1.44,0,0,1,0,2L7.37,7.37A1.43,1.43,0,0,1,6.36,7.79Z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="#041E49"><path d="M480-360 280-560h400L480-360Z"/></svg>
Binary file
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="8" viewBox="0 0 8 8" width="8" fill="#041E49" stroke="#000">
2
+ <g><line x1="2.67" y1="7" x2="7" y2="2.67"></line><line x1="5.33" y1="7" x2="7" y2="5.33"></line></g>
3
+ </svg>
@@ -0,0 +1,74 @@
1
+ <?xml version="1.0" encoding="utf-8" standalone="no"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="96px" height="124px">
3
+ <style type="text/css">
4
+ #background {
5
+ fill: none;
6
+ }
7
+ .arrows {
8
+ fill: #000;
9
+ stroke: none;
10
+ }
11
+ .selected>.arrows {
12
+ fill: #fff;
13
+ }
14
+ .checkmark {
15
+ fill: #000;
16
+ font-family: sans-serif;
17
+ font-size: 10pt;
18
+ text-anchor: middle;
19
+ }
20
+ .trash {
21
+ fill: #888;
22
+ }
23
+ .zoom {
24
+ fill: none;
25
+ stroke: #888;
26
+ stroke-width: 2;
27
+ stroke-linecap: round;
28
+ }
29
+ .zoom>.center {
30
+ fill: #888;
31
+ stroke-width: 0;
32
+ }
33
+ </style>
34
+ <rect id="background" width="96" height="124" x="0" y="0" />
35
+
36
+ <g>
37
+ <path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
38
+ <path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
39
+ <path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
40
+ </g>
41
+ <g class="selected" transform="translate(0, 16)">
42
+ <path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
43
+ <path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
44
+ <path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
45
+ </g>
46
+
47
+ <text class="checkmark" x="55.5" y="28">&#10003;</text>
48
+
49
+ <g class="trash">
50
+ <path d="M 2,41 v 6 h 42 v -6 h -10.5 l -3,-3 h -15 l -3,3 z" />
51
+ <rect width="36" height="20" x="5" y="50" />
52
+ <rect width="36" height="42" x="5" y="50" rx="4" ry="4" />
53
+ </g>
54
+
55
+ <g class="zoom">
56
+ <circle r="11.5" cx="16" cy="108" />
57
+ <circle r="4.3" cx="16" cy="108" class="center" />
58
+ <path d="m 28,108 h3" />
59
+ <path d="m 1,108 h3" />
60
+ <path d="m 16,120 v3" />
61
+ <path d="m 16,93 v3" />
62
+ </g>
63
+
64
+ <g class="zoom">
65
+ <circle r="15" cx="48" cy="108" />
66
+ <path d="m 48,101.6 v12.8" />
67
+ <path d="m 41.6,108 h12.8" />
68
+ </g>
69
+
70
+ <g class="zoom">
71
+ <circle r="15" cx="80" cy="108" />
72
+ <path d="m 73.6,108 h12.8" />
73
+ </g>
74
+ </svg>