hytopia 0.3.14 → 0.3.16
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/bin/scripts.js
CHANGED
@@ -3,10 +3,36 @@
|
|
3
3
|
const { execSync } = require('child_process');
|
4
4
|
const fs = require('fs');
|
5
5
|
const path = require('path');
|
6
|
+
const readline = require('readline');
|
6
7
|
|
8
|
+
// Store command-line flags
|
9
|
+
const flags = {};
|
10
|
+
|
11
|
+
// Main function to handle command execution
|
7
12
|
(async () => {
|
8
13
|
const command = process.argv[2];
|
9
|
-
|
14
|
+
|
15
|
+
// Parse command-line flags
|
16
|
+
parseCommandLineFlags();
|
17
|
+
|
18
|
+
// Execute the appropriate command
|
19
|
+
const commandHandlers = {
|
20
|
+
'init': init,
|
21
|
+
'init-mcp': initMcp
|
22
|
+
};
|
23
|
+
|
24
|
+
const handler = commandHandlers[command];
|
25
|
+
if (handler) {
|
26
|
+
handler();
|
27
|
+
} else {
|
28
|
+
displayAvailableCommands(command);
|
29
|
+
}
|
30
|
+
})();
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Parses command-line flags in the format --flag value
|
34
|
+
*/
|
35
|
+
function parseCommandLineFlags() {
|
10
36
|
for (let i = 3; i < process.argv.length; i += 2) {
|
11
37
|
if (i % 2 === 1) { // Odd indices are flags
|
12
38
|
const flag = process.argv[i].replace('--', '');
|
@@ -14,65 +40,202 @@ const path = require('path');
|
|
14
40
|
flags[flag] = value;
|
15
41
|
}
|
16
42
|
}
|
43
|
+
}
|
17
44
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
* `bunx hytopia init my-project-name`
|
26
|
-
*/
|
27
|
-
if (command === 'init') {
|
28
|
-
const destDir = process.cwd();
|
29
|
-
|
30
|
-
// Grab the latest dependencies
|
31
|
-
execSync('bun init --yes');
|
32
|
-
execSync('bun add hytopia@latest');
|
33
|
-
execSync('bun add @hytopia.com/assets');
|
34
|
-
|
35
|
-
// Initialize project with latest HYTOPIA SDK
|
36
|
-
console.log('🔧 Initializing project with latest HYTOPIA SDK...');
|
37
|
-
|
38
|
-
if (flags.template) {
|
39
|
-
// Init from example template
|
40
|
-
console.log(`🖨️ Initializing project with examples template "${flags.template}"...`);
|
41
|
-
|
42
|
-
const templateDir = path.join(destDir, 'node_modules', 'hytopia', 'examples', flags.template);
|
43
|
-
|
44
|
-
if (!fs.existsSync(templateDir)) {
|
45
|
-
console.error(`Examples template ${flags.template} does not exist in the examples directory, could not initialize project! Tried directory: ${templateDir}`);
|
46
|
-
return;
|
47
|
-
}
|
48
|
-
|
49
|
-
fs.cpSync(templateDir, destDir, { recursive: true });
|
50
|
-
|
51
|
-
execSync('bun install');
|
52
|
-
} else {
|
53
|
-
// Init from boilerplate
|
54
|
-
console.log('🧑💻 Initializing project with boilerplate...');
|
45
|
+
/**
|
46
|
+
* Displays available commands when an unknown command is entered
|
47
|
+
*/
|
48
|
+
function displayAvailableCommands(command) {
|
49
|
+
console.log('Unknown command: ' + command);
|
50
|
+
console.log('Supported commands: init, init-mcp');
|
51
|
+
}
|
55
52
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
53
|
+
/**
|
54
|
+
* Creates a readline interface for user input
|
55
|
+
*/
|
56
|
+
function createReadlineInterface() {
|
57
|
+
return readline.createInterface({
|
58
|
+
input: process.stdin,
|
59
|
+
output: process.stdout
|
60
|
+
});
|
61
|
+
}
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Init command
|
65
|
+
*
|
66
|
+
* Initializes a new HYTOPIA project. Accepting an optional
|
67
|
+
* project name as an argument.
|
68
|
+
*
|
69
|
+
* @example
|
70
|
+
* `bunx hytopia init my-project-name`
|
71
|
+
*/
|
72
|
+
function init() {
|
73
|
+
const destDir = process.cwd();
|
74
|
+
|
75
|
+
// Install dependencies
|
76
|
+
installProjectDependencies();
|
77
|
+
|
78
|
+
// Initialize project with latest HYTOPIA SDK
|
79
|
+
console.log('🔧 Initializing project with latest HYTOPIA SDK...');
|
80
|
+
|
81
|
+
if (flags.template) {
|
82
|
+
initFromTemplate(destDir);
|
83
|
+
} else {
|
84
|
+
initFromBoilerplate(destDir);
|
85
|
+
}
|
86
|
+
|
87
|
+
// Copy assets into project, not overwriting existing files
|
88
|
+
copyAssets(destDir);
|
89
|
+
|
90
|
+
// Display success message
|
91
|
+
displayInitSuccessMessage();
|
92
|
+
|
93
|
+
// Prompt for MCP setup
|
94
|
+
promptForMcpSetup();
|
95
|
+
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
|
99
|
+
/**
|
100
|
+
* Installs required dependencies for a new project
|
101
|
+
*/
|
102
|
+
function installProjectDependencies() {
|
103
|
+
execSync('bun init --yes');
|
104
|
+
execSync('bun add hytopia@latest');
|
105
|
+
execSync('bun add @hytopia.com/assets');
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Initializes a project from a template
|
110
|
+
*/
|
111
|
+
function initFromTemplate(destDir) {
|
112
|
+
console.log(`🖨️ Initializing project with examples template "${flags.template}"...`);
|
113
|
+
|
114
|
+
const templateDir = path.join(destDir, 'node_modules', 'hytopia', 'examples', flags.template);
|
60
115
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
path.join(destDir, 'assets'),
|
65
|
-
{ recursive: true, force: false }
|
66
|
-
);
|
67
|
-
|
68
|
-
// Done, lfg!
|
69
|
-
console.log('--------------------------------');
|
70
|
-
console.log('🚀 Hytopia project initialized successfully!');
|
71
|
-
console.log('💡 Start your development server with `bun --watch index.ts`!');
|
72
|
-
console.log('🎮 After you start your development server, play by opening your browser and visiting: https://play.hytopia.com/?join=localhost:8080')
|
116
|
+
if (!fs.existsSync(templateDir)) {
|
117
|
+
console.error(`❌ Examples template ${flags.template} does not exist in the examples directory, could not initialize project!`);
|
118
|
+
console.error(` Tried directory: ${templateDir}`);
|
73
119
|
return;
|
74
120
|
}
|
121
|
+
|
122
|
+
fs.cpSync(templateDir, destDir, { recursive: true });
|
123
|
+
execSync('bun install');
|
124
|
+
}
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Initializes a project from the default boilerplate
|
128
|
+
*/
|
129
|
+
function initFromBoilerplate(destDir) {
|
130
|
+
console.log('🧑💻 Initializing project with boilerplate...');
|
131
|
+
const srcDir = path.join(__dirname, '..', 'boilerplate');
|
132
|
+
fs.cpSync(srcDir, destDir, { recursive: true });
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Copies assets to the project directory
|
137
|
+
*/
|
138
|
+
function copyAssets(destDir) {
|
139
|
+
fs.cpSync(
|
140
|
+
path.join(destDir, 'node_modules', '@hytopia.com', 'assets'),
|
141
|
+
path.join(destDir, 'assets'),
|
142
|
+
{ recursive: true, force: false }
|
143
|
+
);
|
144
|
+
}
|
145
|
+
|
146
|
+
/**
|
147
|
+
* Displays success message after project initialization
|
148
|
+
*/
|
149
|
+
function displayInitSuccessMessage() {
|
150
|
+
logDivider();
|
151
|
+
console.log('✅ HYTOPIA PROJECT INITIALIZED SUCCESSFULLY!');
|
152
|
+
console.log(' ');
|
153
|
+
console.log('💡 1. Start your development server with: bun --watch index.ts');
|
154
|
+
console.log('🎮 2. Play your game by opening: https://play.hytopia.com/?join=localhost:8080');
|
155
|
+
logDivider();
|
156
|
+
}
|
157
|
+
|
158
|
+
/**
|
159
|
+
* Prompts the user to set up MCP
|
160
|
+
*/
|
161
|
+
function promptForMcpSetup() {
|
162
|
+
console.log('📋 OPTIONAL: HYTOPIA MCP SETUP');
|
163
|
+
console.log(' ');
|
164
|
+
console.log('The HYTOPIA MCP enables Cursor and Claude Code editors to access');
|
165
|
+
console.log('HYTOPIA-specific capabilities, providing significantly better AI');
|
166
|
+
console.log('assistance and development experience for this HYTOPIA project.');
|
167
|
+
console.log(' ');
|
168
|
+
|
169
|
+
const rl = createReadlineInterface();
|
75
170
|
|
76
|
-
|
77
|
-
|
171
|
+
rl.question('Would you like to initialize the HYTOPIA MCP for this project? (y/n): ', (answer) => {
|
172
|
+
rl.close();
|
173
|
+
|
174
|
+
if (answer.trim().toLowerCase() === 'y') {
|
175
|
+
initMcp();
|
176
|
+
} else {
|
177
|
+
logDivider();
|
178
|
+
console.log('🎉 You\'re all set! Your HYTOPIA project is ready to use.');
|
179
|
+
logDivider();
|
180
|
+
}
|
181
|
+
});
|
182
|
+
}
|
183
|
+
|
184
|
+
/**
|
185
|
+
* Initializes the MCP for the selected editors
|
186
|
+
*/
|
187
|
+
function initMcp() {
|
188
|
+
const rl = createReadlineInterface();
|
189
|
+
|
190
|
+
logDivider();
|
191
|
+
console.log('🤖 HYTOPIA MCP SETUP');
|
192
|
+
console.log('Please select your code editor:');
|
193
|
+
console.log(' 1. Cursor');
|
194
|
+
console.log(' 2. Claude Code');
|
195
|
+
console.log(' 3. Both');
|
196
|
+
console.log(' 4. None / Cancel');
|
197
|
+
|
198
|
+
rl.question('Enter your selection (1-4): ', (answer) => {
|
199
|
+
const selection = parseInt(answer.trim());
|
200
|
+
|
201
|
+
if (isNaN(selection) || selection < 1 || selection > 4) {
|
202
|
+
console.log('❌ Invalid selection. Please run `bunx hytopia init-mcp` again and select a number between 1 and 4.');
|
203
|
+
rl.close();
|
204
|
+
return;
|
205
|
+
}
|
206
|
+
|
207
|
+
if ([1, 2, 3].includes(selection)) { logDivider(); }
|
208
|
+
|
209
|
+
if (selection === 1 || selection === 3) {
|
210
|
+
initEditorMcp('Cursor', 'cursor');
|
211
|
+
}
|
212
|
+
|
213
|
+
if (selection === 2 || selection === 3) {
|
214
|
+
initEditorMcp('Claude Code', 'claude');
|
215
|
+
}
|
216
|
+
|
217
|
+
rl.close();
|
218
|
+
|
219
|
+
if ([1, 2, 3].includes(selection)) {
|
220
|
+
console.log('🎉 You\'re all set! Your HYTOPIA project is ready to use.');
|
221
|
+
logDivider();
|
222
|
+
}
|
223
|
+
});
|
224
|
+
}
|
225
|
+
|
226
|
+
/**
|
227
|
+
* Initializes MCP for a specific editor
|
228
|
+
*/
|
229
|
+
function initEditorMcp(editorName, editorFlag) {
|
230
|
+
console.log(`🔧 Initializing HYTOPIA MCP for ${editorName}...`);
|
231
|
+
execSync(`bunx topia-mcp@latest init ${editorFlag}`);
|
232
|
+
console.log(`✅ ${editorName} MCP initialized successfully!`);
|
233
|
+
logDivider();
|
234
|
+
}
|
78
235
|
|
236
|
+
/**
|
237
|
+
* Prints a divider line for better console output readability
|
238
|
+
*/
|
239
|
+
function logDivider() {
|
240
|
+
console.log('--------------------------------');
|
241
|
+
}
|
@@ -34,9 +34,9 @@ and also configure additional buttons for mobile compatibility.
|
|
34
34
|
</script>
|
35
35
|
|
36
36
|
<!--
|
37
|
-
HYTOPIA allows you to build completely custom UI
|
37
|
+
HYTOPIA allows you to build completely custom UI using HTML, CSS and Javascript.
|
38
38
|
You can build simple UIs, to highly complex ones. UI capabilities are as powerful
|
39
|
-
as building a
|
39
|
+
as building a regular web page - there are close to no limitations on what is possible.
|
40
40
|
|
41
41
|
Remember, HYTOPIA sandboxes your UI & UI scripts, so external network requests or
|
42
42
|
other unsafe actions likely won't work as you expect in production.
|
@@ -60,7 +60,7 @@ and also configure additional buttons for mobile compatibility.
|
|
60
60
|
|
61
61
|
/*
|
62
62
|
We can use the body.mobile class to detect if we're on a mobile device.
|
63
|
-
HYTOPIA will always add this class to the body element when running on a mobile device.
|
63
|
+
The HYTOPIA game client will always add this class to the body element when running on a mobile device.
|
64
64
|
*/
|
65
65
|
body.mobile .mobile-controls { /* If this css selector matches because we're on mobile, show the mobile controls */
|
66
66
|
display: flex;
|
@@ -34,9 +34,9 @@ and also configure additional buttons for mobile compatibility.
|
|
34
34
|
</script>
|
35
35
|
|
36
36
|
<!--
|
37
|
-
HYTOPIA allows you to build completely custom UI
|
37
|
+
HYTOPIA allows you to build completely custom UI using HTML, CSS and Javascript.
|
38
38
|
You can build simple UIs, to highly complex ones. UI capabilities are as powerful
|
39
|
-
as building a
|
39
|
+
as building a regular web page - there are close to no limitations on what is possible.
|
40
40
|
|
41
41
|
Remember, HYTOPIA sandboxes your UI & UI scripts, so external network requests or
|
42
42
|
other unsafe actions likely won't work as you expect in production.
|
@@ -60,7 +60,7 @@ and also configure additional buttons for mobile compatibility.
|
|
60
60
|
|
61
61
|
/*
|
62
62
|
We can use the body.mobile class to detect if we're on a mobile device.
|
63
|
-
HYTOPIA will always add this class to the body element when running on a mobile device.
|
63
|
+
The HYTOPIA game client will always add this class to the body element when running on a mobile device.
|
64
64
|
*/
|
65
65
|
body.mobile .mobile-controls { /* If this css selector matches because we're on mobile, show the mobile controls */
|
66
66
|
display: flex;
|