gamedev 0.0.4-alpha.1 → 0.0.4-alpha.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.
@@ -202,6 +202,58 @@ function resolveBuiltinScriptPath(filename) {
202
202
  return null
203
203
  }
204
204
 
205
+ function resolveBuiltinAssetPath(filename) {
206
+ const buildPath = path.join(__dirname, '..', 'build', 'world', 'assets', filename)
207
+ if (fs.existsSync(buildPath)) return buildPath
208
+ const srcPath = path.join(__dirname, '..', 'src', 'world', 'assets', filename)
209
+ if (fs.existsSync(srcPath)) return srcPath
210
+ return null
211
+ }
212
+
213
+ function collectAssetFilenames(value, out) {
214
+ if (!out) out = new Set()
215
+ if (typeof value === 'string') {
216
+ if (value.startsWith('asset://')) {
217
+ out.add(value.slice('asset://'.length))
218
+ } else if (value.startsWith('assets/')) {
219
+ out.add(value.slice('assets/'.length))
220
+ }
221
+ return out
222
+ }
223
+ if (Array.isArray(value)) {
224
+ for (const item of value) {
225
+ collectAssetFilenames(item, out)
226
+ }
227
+ return out
228
+ }
229
+ if (value && typeof value === 'object') {
230
+ for (const item of Object.values(value)) {
231
+ collectAssetFilenames(item, out)
232
+ }
233
+ }
234
+ return out
235
+ }
236
+
237
+ function toLocalAssetUrls(value) {
238
+ if (typeof value === 'string') {
239
+ if (value.startsWith('asset://')) {
240
+ return `assets/${value.slice('asset://'.length)}`
241
+ }
242
+ return value
243
+ }
244
+ if (Array.isArray(value)) {
245
+ return value.map(item => toLocalAssetUrls(item))
246
+ }
247
+ if (value && typeof value === 'object') {
248
+ const next = {}
249
+ for (const [key, item] of Object.entries(value)) {
250
+ next[key] = toLocalAssetUrls(item)
251
+ }
252
+ return next
253
+ }
254
+ return value
255
+ }
256
+
205
257
  function readBuiltinScript(template) {
206
258
  const scriptPath = resolveBuiltinScriptPath(template.scriptAsset)
207
259
  if (!scriptPath) {
@@ -296,16 +348,21 @@ export function createDefaultManifest() {
296
348
  export function scaffoldBuiltins({ rootDir, force = false, writeFile } = {}) {
297
349
  const report = { created: [], updated: [], skipped: [] }
298
350
  const appsDir = path.join(rootDir, 'apps')
351
+ const assetsDir = path.join(rootDir, 'assets')
299
352
  ensureDir(appsDir)
300
353
 
301
354
  const templates = [...BUILTIN_APP_TEMPLATES, SCENE_TEMPLATE]
355
+ const assetFiles = new Set()
356
+
302
357
  for (const template of templates) {
358
+ collectAssetFilenames(template.config, assetFiles)
303
359
  const appDir = path.join(appsDir, template.appName)
304
360
  ensureDir(appDir)
305
361
 
306
362
  const blueprintPath = path.join(appDir, `${template.fileBase}.json`)
307
363
  if (!fs.existsSync(blueprintPath) || force) {
308
- writeFileWithPolicy(blueprintPath, JSON.stringify(template.config, null, 2) + '\n', {
364
+ const localConfig = toLocalAssetUrls(template.config)
365
+ writeFileWithPolicy(blueprintPath, JSON.stringify(localConfig, null, 2) + '\n', {
309
366
  force,
310
367
  writeFile,
311
368
  report,
@@ -320,6 +377,34 @@ export function scaffoldBuiltins({ rootDir, force = false, writeFile } = {}) {
320
377
  }
321
378
  }
322
379
 
380
+ if (assetFiles.size) {
381
+ ensureDir(assetsDir)
382
+ for (const filename of assetFiles) {
383
+ const srcPath = resolveBuiltinAssetPath(filename)
384
+ if (!srcPath) {
385
+ throw new Error(`missing_builtin_asset:${filename}`)
386
+ }
387
+ const destPath = path.join(assetsDir, filename)
388
+ const exists = fs.existsSync(destPath)
389
+ if (exists && !force) {
390
+ report.skipped.push(destPath)
391
+ continue
392
+ }
393
+ const buffer = fs.readFileSync(srcPath)
394
+ if (writeFile) {
395
+ writeFile(destPath, buffer)
396
+ } else {
397
+ ensureDir(path.dirname(destPath))
398
+ fs.writeFileSync(destPath, buffer)
399
+ }
400
+ if (exists) {
401
+ report.updated.push(destPath)
402
+ } else {
403
+ report.created.push(destPath)
404
+ }
405
+ }
406
+ }
407
+
323
408
  return { report, manifest: createDefaultManifest() }
324
409
  }
325
410
 
package/bin/gamedev.mjs CHANGED
@@ -541,6 +541,9 @@ async function initCommand(args = []) {
541
541
  console.log(`↪️ Skipped ${skipped.length} existing file(s)`)
542
542
  }
543
543
 
544
+ const envResult = ensureEnvForStart()
545
+ if (!envResult.ok) return 1
546
+
544
547
  return 0
545
548
  }
546
549
 
@@ -25,14 +25,14 @@
25
25
  <meta name="apple-mobile-web-app-capable" content="yes" />
26
26
  <meta name="mobile-web-app-capable" content="yes" />
27
27
  <link rel="preload" href="/rubik.woff2" as="font" type="font/woff2" crossorigin />
28
- <link rel="stylesheet" type="text/css" href="/index.css?v=1768873891919" />
28
+ <link rel="stylesheet" type="text/css" href="/index.css?v=1768878465145" />
29
29
  <script>
30
30
  window.PARTICLES_PATH = '/particles-4YQR4CFO.js'
31
31
  </script>
32
32
  </head>
33
33
  <body>
34
34
  <div id="root"></div>
35
- <script src="/env.js?v=1768873891919"></script>
35
+ <script src="/env.js?v=1768878465145"></script>
36
36
  <script src="/admin-EJMJPJ7M.js" type="module"></script>
37
37
  </body>
38
38
  </html>
@@ -26,14 +26,14 @@
26
26
  <meta name="mobile-web-app-capable" content="yes" />
27
27
  <!-- <link rel='icon' href='/favicon.ico' /> -->
28
28
  <link rel="preload" href="/rubik.woff2" as="font" type="font/woff2" crossorigin />
29
- <link rel="stylesheet" type="text/css" href="/index.css?v=1768873891919" />
29
+ <link rel="stylesheet" type="text/css" href="/index.css?v=1768878465144" />
30
30
  <script>
31
31
  window.PARTICLES_PATH = '/particles-4YQR4CFO.js'
32
32
  </script>
33
33
  </head>
34
34
  <body>
35
35
  <div id="root"></div>
36
- <script src="/env.js?v=1768873891919"></script>
36
+ <script src="/env.js?v=1768878465144"></script>
37
37
  <script src="/index-RJRKEY6V.js" type="module"></script>
38
38
  </body>
39
39
  </html>