castle-web-cli 0.4.0 → 0.4.2

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 (158) hide show
  1. package/dist/api.d.ts +53 -5
  2. package/dist/api.js +42 -15
  3. package/dist/config.d.ts +2 -0
  4. package/dist/config.js +25 -11
  5. package/dist/get-deck.d.ts +3 -0
  6. package/dist/get-deck.js +64 -0
  7. package/dist/ide-client.d.ts +1 -0
  8. package/dist/ide-client.js +537 -0
  9. package/dist/ide.d.ts +16 -0
  10. package/dist/ide.js +546 -0
  11. package/dist/index.js +84 -57
  12. package/dist/init.d.ts +3 -1
  13. package/dist/init.js +170 -24
  14. package/dist/localPaths.d.ts +6 -0
  15. package/dist/localPaths.js +33 -0
  16. package/dist/login.js +1 -1
  17. package/dist/preview.d.ts +4 -1
  18. package/dist/preview.js +63 -41
  19. package/dist/save-deck.d.ts +2 -0
  20. package/dist/{push.js → save-deck.js} +66 -5
  21. package/dist/serve.d.ts +2 -0
  22. package/dist/serve.js +293 -22
  23. package/kits/basic-2d/.prettierrc +8 -0
  24. package/kits/basic-2d/CLAUDE.md +131 -0
  25. package/kits/basic-2d/behaviors/Camera.jsx +43 -0
  26. package/kits/basic-2d/behaviors/Collider.jsx +71 -0
  27. package/kits/basic-2d/behaviors/Drawing.jsx +139 -0
  28. package/kits/basic-2d/behaviors/Layout.jsx +16 -0
  29. package/kits/basic-2d/drawings/floor.drawing +70 -0
  30. package/kits/basic-2d/editors/App.jsx +152 -0
  31. package/kits/basic-2d/editors/CodeEditor.jsx +112 -0
  32. package/kits/basic-2d/editors/DrawingEditor.jsx +222 -0
  33. package/kits/basic-2d/editors/FileBrowser.jsx +143 -0
  34. package/kits/basic-2d/editors/PlayOnly.jsx +21 -0
  35. package/kits/basic-2d/editors/SceneEditor.jsx +1012 -0
  36. package/kits/basic-2d/editors/behaviorRegistry.js +24 -0
  37. package/kits/basic-2d/editors/editorHistory.js +52 -0
  38. package/kits/basic-2d/engine/ScenePlayer.jsx +83 -0
  39. package/kits/basic-2d/engine/SceneUI.jsx +67 -0
  40. package/kits/basic-2d/engine/TouchControls.jsx +136 -0
  41. package/kits/basic-2d/engine/autoInspector.jsx +51 -0
  42. package/kits/basic-2d/engine/files.js +62 -0
  43. package/kits/basic-2d/engine/scene.js +420 -0
  44. package/kits/basic-2d/engine/ui.jsx +344 -0
  45. package/kits/basic-2d/engine/ui.module.css +928 -0
  46. package/kits/basic-2d/eslint.config.js +50 -0
  47. package/kits/basic-2d/index.html +11 -0
  48. package/kits/basic-2d/main.jsx +10 -0
  49. package/kits/basic-2d/package-lock.json +2706 -0
  50. package/kits/basic-2d/package.json +41 -0
  51. package/kits/basic-2d/scenes/main.scene +108 -0
  52. package/kits/basic-2d/vite.config.js +1 -0
  53. package/kits/basic-2d-frozen/.prettierrc +8 -0
  54. package/kits/basic-2d-frozen/CLAUDE.md +131 -0
  55. package/kits/basic-2d-frozen/behaviors/Camera.jsx +43 -0
  56. package/kits/basic-2d-frozen/behaviors/Collider.jsx +71 -0
  57. package/kits/basic-2d-frozen/behaviors/Drawing.jsx +139 -0
  58. package/kits/basic-2d-frozen/behaviors/Layout.jsx +16 -0
  59. package/kits/basic-2d-frozen/drawings/floor.drawing +70 -0
  60. package/kits/basic-2d-frozen/editors/App.jsx +152 -0
  61. package/kits/basic-2d-frozen/editors/CodeEditor.jsx +112 -0
  62. package/kits/basic-2d-frozen/editors/DrawingEditor.jsx +222 -0
  63. package/kits/basic-2d-frozen/editors/FileBrowser.jsx +143 -0
  64. package/kits/basic-2d-frozen/editors/PlayOnly.jsx +21 -0
  65. package/kits/basic-2d-frozen/editors/SceneEditor.jsx +1012 -0
  66. package/kits/basic-2d-frozen/editors/behaviorRegistry.js +24 -0
  67. package/kits/basic-2d-frozen/editors/editorHistory.js +52 -0
  68. package/kits/basic-2d-frozen/engine/ScenePlayer.jsx +83 -0
  69. package/kits/basic-2d-frozen/engine/SceneUI.jsx +67 -0
  70. package/kits/basic-2d-frozen/engine/TouchControls.jsx +136 -0
  71. package/kits/basic-2d-frozen/engine/autoInspector.jsx +51 -0
  72. package/kits/basic-2d-frozen/engine/files.js +62 -0
  73. package/kits/basic-2d-frozen/engine/scene.js +420 -0
  74. package/kits/basic-2d-frozen/engine/ui.jsx +344 -0
  75. package/kits/basic-2d-frozen/engine/ui.module.css +928 -0
  76. package/kits/basic-2d-frozen/eslint.config.js +50 -0
  77. package/kits/basic-2d-frozen/index.html +11 -0
  78. package/kits/basic-2d-frozen/main.jsx +10 -0
  79. package/kits/basic-2d-frozen/package-lock.json +2706 -0
  80. package/kits/basic-2d-frozen/package.json +41 -0
  81. package/kits/basic-2d-frozen/scenes/main.scene +108 -0
  82. package/kits/basic-2d-frozen/vite.config.js +1 -0
  83. package/kits/rpg-2d/.prettierrc +8 -0
  84. package/kits/rpg-2d/behaviors/Camera.tsx +52 -0
  85. package/kits/rpg-2d/behaviors/Collider.tsx +98 -0
  86. package/kits/rpg-2d/behaviors/Dialog.tsx +184 -0
  87. package/kits/rpg-2d/behaviors/Drawing.tsx +161 -0
  88. package/kits/rpg-2d/behaviors/Friend.tsx +45 -0
  89. package/kits/rpg-2d/behaviors/Layout.tsx +29 -0
  90. package/kits/rpg-2d/behaviors/PlayerController.tsx +255 -0
  91. package/kits/rpg-2d/behaviors/Portal.tsx +60 -0
  92. package/kits/rpg-2d/behaviors/QuestLog.tsx +90 -0
  93. package/kits/rpg-2d/behaviors/SaveMenu.tsx +123 -0
  94. package/kits/rpg-2d/behaviors/Tilemap.tsx +90 -0
  95. package/kits/rpg-2d/drawings/bld-home.drawing +8136 -0
  96. package/kits/rpg-2d/drawings/env-crate.drawing +509 -0
  97. package/kits/rpg-2d/drawings/env-fence.drawing +536 -0
  98. package/kits/rpg-2d/drawings/env-flower-bed.drawing +607 -0
  99. package/kits/rpg-2d/drawings/env-fountain.drawing +2622 -0
  100. package/kits/rpg-2d/drawings/env-hedge.drawing +601 -0
  101. package/kits/rpg-2d/drawings/env-house-blue.drawing +1 -0
  102. package/kits/rpg-2d/drawings/env-house-green.drawing +1 -0
  103. package/kits/rpg-2d/drawings/env-tree-oak.drawing +1540 -0
  104. package/kits/rpg-2d/drawings/env-tree-pine.drawing +1315 -0
  105. package/kits/rpg-2d/drawings/floor.drawing +70 -0
  106. package/kits/rpg-2d/drawings/fx-sparkle.drawing +926 -0
  107. package/kits/rpg-2d/drawings/npc-juno-idle-down.drawing +1099 -0
  108. package/kits/rpg-2d/drawings/npc-juno-walk-down.drawing +4177 -0
  109. package/kits/rpg-2d/drawings/npc-opal-idle-down.drawing +1099 -0
  110. package/kits/rpg-2d/drawings/npc-opal-walk-down.drawing +4177 -0
  111. package/kits/rpg-2d/drawings/player-idle-down.drawing +1070 -0
  112. package/kits/rpg-2d/drawings/player-idle-left.drawing +1070 -0
  113. package/kits/rpg-2d/drawings/player-idle-right.drawing +1070 -0
  114. package/kits/rpg-2d/drawings/player-idle-up.drawing +1070 -0
  115. package/kits/rpg-2d/drawings/player-walk-down.drawing +4148 -0
  116. package/kits/rpg-2d/drawings/player-walk-left.drawing +4148 -0
  117. package/kits/rpg-2d/drawings/player-walk-right.drawing +4148 -0
  118. package/kits/rpg-2d/drawings/player-walk-up.drawing +4148 -0
  119. package/kits/rpg-2d/editors/App.tsx +163 -0
  120. package/kits/rpg-2d/editors/CodeEditor.tsx +120 -0
  121. package/kits/rpg-2d/editors/DrawingEditor.tsx +278 -0
  122. package/kits/rpg-2d/editors/FileBrowser.tsx +191 -0
  123. package/kits/rpg-2d/editors/PlayOnly.tsx +26 -0
  124. package/kits/rpg-2d/editors/SceneEditor.tsx +1093 -0
  125. package/kits/rpg-2d/editors/behaviorRegistry.ts +33 -0
  126. package/kits/rpg-2d/editors/editorHistory.ts +75 -0
  127. package/kits/rpg-2d/editors/editorProps.ts +10 -0
  128. package/kits/rpg-2d/engine/ScenePlayer.tsx +130 -0
  129. package/kits/rpg-2d/engine/SceneUI.tsx +74 -0
  130. package/kits/rpg-2d/engine/TouchControls.tsx +157 -0
  131. package/kits/rpg-2d/engine/autoInspector.tsx +111 -0
  132. package/kits/rpg-2d/engine/drawing.ts +81 -0
  133. package/kits/rpg-2d/engine/files.ts +215 -0
  134. package/kits/rpg-2d/engine/scene.ts +484 -0
  135. package/kits/rpg-2d/engine/ui.module.css +928 -0
  136. package/kits/rpg-2d/engine/ui.tsx +483 -0
  137. package/kits/rpg-2d/eslint.config.js +46 -0
  138. package/kits/rpg-2d/index.html +11 -0
  139. package/kits/rpg-2d/main.tsx +14 -0
  140. package/kits/rpg-2d/package-lock.json +3149 -0
  141. package/kits/rpg-2d/package.json +46 -0
  142. package/kits/rpg-2d/scenes/main.scene +203 -0
  143. package/kits/rpg-2d/tsconfig.json +17 -0
  144. package/kits/rpg-2d/vite-env.d.ts +7 -0
  145. package/kits/rpg-2d/vite.config.js +1 -0
  146. package/package.json +27 -5
  147. package/AGENTS.md +0 -24
  148. package/dist/push.d.ts +0 -1
  149. package/src/api.ts +0 -160
  150. package/src/bundle.ts +0 -28
  151. package/src/config.ts +0 -36
  152. package/src/index.ts +0 -110
  153. package/src/init.ts +0 -71
  154. package/src/login.ts +0 -24
  155. package/src/preview.ts +0 -93
  156. package/src/push.ts +0 -118
  157. package/src/serve.ts +0 -128
  158. package/tsconfig.json +0 -13
@@ -0,0 +1,191 @@
1
+ import type { CSSProperties } from 'react';
2
+ import React, { useState } from 'react';
3
+ import { basename } from '../engine/files';
4
+ import type { FileMap } from '../engine/files';
5
+ import { cx, Icon, SheetGrabHandle, styles, useMobileSheet } from '../engine/ui';
6
+
7
+ type FileNodeData = {
8
+ type: 'file';
9
+ name: string;
10
+ path: string;
11
+ };
12
+
13
+ type DirectoryNodeData = {
14
+ type: 'directory';
15
+ name: string;
16
+ path: string;
17
+ children: TreeNode[];
18
+ childMap?: Map<string, TreeNode>;
19
+ };
20
+
21
+ type TreeNode = FileNodeData | DirectoryNodeData;
22
+
23
+ export function FileBrowser({
24
+ files,
25
+ selectedPath,
26
+ onSelect,
27
+ sheetOpen = false,
28
+ onSheetOpenChange,
29
+ }: {
30
+ files: FileMap;
31
+ selectedPath: string;
32
+ onSelect: (path: string) => void;
33
+ sheetOpen?: boolean;
34
+ onSheetOpenChange?: (next: boolean) => void;
35
+ }) {
36
+ const tree = buildFileTree(Object.keys(files));
37
+ const [expanded, setExpanded] = useState<Set<string>>(() => new Set(collectDirectoryPaths(tree)));
38
+ const sheet = useMobileSheet({
39
+ snap: sheetOpen ? 'high' : 'hidden',
40
+ baseClassName: styles.fileBrowser,
41
+ onTransition: (direction) => {
42
+ if (direction !== 'up') onSheetOpenChange?.(false);
43
+ },
44
+ });
45
+
46
+ function toggle(path: string): void {
47
+ setExpanded((current) => {
48
+ const next = new Set(current);
49
+ if (next.has(path)) next.delete(path);
50
+ else next.add(path);
51
+ return next;
52
+ });
53
+ }
54
+
55
+ return (
56
+ <aside {...sheet.rootProps}>
57
+ <div {...sheet.grabProps}>
58
+ <SheetGrabHandle label="Files" hint={basename(selectedPath)} />
59
+ </div>
60
+ <div className={styles.fileBrowserHeader}>
61
+ <div>
62
+ <div className={styles.fileBrowserTitle}>Deck Files</div>
63
+ </div>
64
+ </div>
65
+ <div className={styles.fileTree}>
66
+ {tree.children.map((node) => (
67
+ <FileNode
68
+ key={node.path}
69
+ node={node}
70
+ depth={0}
71
+ expanded={expanded}
72
+ selectedPath={selectedPath}
73
+ onSelect={onSelect}
74
+ onToggle={toggle}
75
+ />
76
+ ))}
77
+ </div>
78
+ </aside>
79
+ );
80
+ }
81
+
82
+ function FileNode({
83
+ node,
84
+ depth,
85
+ expanded,
86
+ selectedPath,
87
+ onSelect,
88
+ onToggle,
89
+ }: {
90
+ node: TreeNode;
91
+ depth: number;
92
+ expanded: Set<string>;
93
+ selectedPath: string;
94
+ onSelect: (path: string) => void;
95
+ onToggle: (path: string) => void;
96
+ }) {
97
+ const depthStyle = { '--file-depth': depth } as CSSProperties;
98
+
99
+ if (node.type === 'directory') {
100
+ const isExpanded = expanded.has(node.path);
101
+ return (
102
+ <div className={styles.fileBranch}>
103
+ <button
104
+ className={styles.fileDirRow}
105
+ style={depthStyle}
106
+ onClick={() => onToggle(node.path)}>
107
+ <span className={styles.fileDisclosure}>
108
+ <Icon name={isExpanded ? 'chevron-down' : 'chevron-right'} />
109
+ </span>
110
+ <span>{node.name}</span>
111
+ </button>
112
+ {isExpanded ? (
113
+ <div>
114
+ {node.children.map((child) => (
115
+ <FileNode
116
+ key={child.path}
117
+ node={child}
118
+ depth={depth + 1}
119
+ expanded={expanded}
120
+ selectedPath={selectedPath}
121
+ onSelect={onSelect}
122
+ onToggle={onToggle}
123
+ />
124
+ ))}
125
+ </div>
126
+ ) : null}
127
+ </div>
128
+ );
129
+ }
130
+
131
+ // File rows nest under their directory header: extra left padding so
132
+ // file text sits to the right of the parent directory header.
133
+ const fileRowStyle: CSSProperties = {
134
+ ...depthStyle,
135
+ paddingLeft: `calc(9px + ${depth} * 16px + 7px)`,
136
+ };
137
+
138
+ return (
139
+ <button
140
+ className={cx(styles.fileRow, selectedPath === node.path && styles.fileRowSelected)}
141
+ style={fileRowStyle}
142
+ onClick={() => onSelect(node.path)}>
143
+ <span>{basename(node.path)}</span>
144
+ </button>
145
+ );
146
+ }
147
+
148
+ function buildFileTree(paths: string[]): DirectoryNodeData {
149
+ const root: DirectoryNodeData = {
150
+ type: 'directory',
151
+ name: '',
152
+ path: '',
153
+ children: [],
154
+ childMap: new Map(),
155
+ };
156
+ for (const path of paths) {
157
+ const parts = path.split('/');
158
+ let parent = root;
159
+ for (let index = 0; index < parts.length; index++) {
160
+ const name = parts[index];
161
+ const nodePath = parts.slice(0, index + 1).join('/');
162
+ const isFile = index === parts.length - 1;
163
+ if (!parent.childMap?.has(name)) {
164
+ const node: TreeNode = isFile
165
+ ? { type: 'file', name, path: nodePath }
166
+ : { type: 'directory', name, path: nodePath, children: [], childMap: new Map() };
167
+ parent.childMap?.set(name, node);
168
+ parent.children.push(node);
169
+ }
170
+ const child = parent.childMap?.get(name);
171
+ if (!child || child.type !== 'directory') break;
172
+ parent = child;
173
+ }
174
+ }
175
+ pruneChildMaps(root);
176
+ return root;
177
+ }
178
+
179
+ function pruneChildMaps(node: TreeNode): void {
180
+ if (node.type !== 'directory') return;
181
+ for (const child of node.children) pruneChildMaps(child);
182
+ delete node.childMap;
183
+ }
184
+
185
+ function collectDirectoryPaths(node: TreeNode): string[] {
186
+ if (node.type !== 'directory') return [];
187
+ return [
188
+ ...(node.path ? [node.path] : []),
189
+ ...node.children.flatMap((child) => collectDirectoryPaths(child)),
190
+ ];
191
+ }
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { initialFiles, normalizeDrawing, parseJsonFile } from '../engine/files';
3
+ import type { DrawingData } from '../engine/files';
4
+ import type { SceneData } from '../engine/scene';
5
+ import { ScenePlayer } from '../engine/ScenePlayer';
6
+ import { behaviorClasses } from './behaviorRegistry';
7
+
8
+ // Play-mode entry point. Intentionally thin: it locates the start scene and
9
+ // hands it to the engine's `ScenePlayer`, which owns the runtime and input.
10
+ // Deck/game logic belongs in `scenes/` and `behaviors/`, not here.
11
+ export function PlayOnly() {
12
+ const sceneText = initialFiles['scenes/main.scene'] ?? '';
13
+ const { value: sceneData } = parseJsonFile<SceneData>('scenes/main.scene', sceneText);
14
+ if (!sceneData) return null;
15
+
16
+ const drawings: Record<string, DrawingData> = {};
17
+ for (const [path, text] of Object.entries(initialFiles)) {
18
+ if (!path.endsWith('.drawing')) continue;
19
+ const parsed = parseJsonFile<unknown>(path, text);
20
+ if (parsed.value) drawings[path] = normalizeDrawing(parsed.value);
21
+ }
22
+
23
+ return (
24
+ <ScenePlayer sceneData={sceneData} drawings={drawings} behaviorClasses={behaviorClasses} />
25
+ );
26
+ }