otherplane 0.1.0 → 0.1.1
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/otherplane.mjs +63 -25
- package/package.json +1 -1
package/bin/otherplane.mjs
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
readdirSync, statSync, mkdirSync, copyFileSync, cpSync, rmSync, existsSync, readFileSync, writeFileSync,
|
|
31
31
|
} from 'node:fs';
|
|
32
32
|
import { createServer } from 'node:http';
|
|
33
|
-
import { join, dirname } from 'node:path';
|
|
33
|
+
import { join, dirname, sep } from 'node:path';
|
|
34
34
|
import { fileURLToPath } from 'node:url';
|
|
35
35
|
import { createRequire } from 'node:module';
|
|
36
36
|
|
|
@@ -57,14 +57,56 @@ function resolveEngine() {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
const ENGINE = resolveEngine();
|
|
60
|
-
const PUBLIC = join(ENGINE, 'public');
|
|
61
60
|
const CONTENT_DIRS = ['rooms', 'worlds', 'music'];
|
|
62
61
|
const CONFIG_PATH = join(PROJECT, 'otherplane.config.json');
|
|
63
|
-
// Next writes its export into the engine dir; the deployable belongs in the
|
|
64
|
-
// PROJECT (the engine may be an installed package elsewhere). We copy it there.
|
|
65
|
-
const ENGINE_OUT = join(ENGINE, 'out');
|
|
66
62
|
const OUT = join(PROJECT, 'out');
|
|
67
63
|
|
|
64
|
+
// When installed, the engine lives inside node_modules — but Next/Turbopack won't
|
|
65
|
+
// transpile app source under node_modules. So for an installed engine we build a
|
|
66
|
+
// COPY staged outside it (in the project's .otherplane/), with its own real
|
|
67
|
+
// node_modules. In this repo's sibling layout we build in place.
|
|
68
|
+
const INSTALLED = ENGINE.split(sep).includes('node_modules');
|
|
69
|
+
let BUILD_ENGINE = ENGINE; // where Next actually runs
|
|
70
|
+
const publicDir = () => join(BUILD_ENGINE, 'public');
|
|
71
|
+
const engineOut = () => join(BUILD_ENGINE, 'out');
|
|
72
|
+
|
|
73
|
+
// Install the engine's deps into `dir` if missing (real node_modules, not a
|
|
74
|
+
// symlink — Turbopack can't resolve `next` through a symlinked node_modules).
|
|
75
|
+
function ensureDepsIn(dir) {
|
|
76
|
+
if (existsSync(join(dir, 'node_modules', 'next'))) return;
|
|
77
|
+
console.log('installing the engine’s dependencies (one-time per project, ~a minute)…');
|
|
78
|
+
run('npm', ['--prefix', dir, 'install', '--no-audit', '--no-fund']);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Pick where Next runs and make sure its deps are there.
|
|
82
|
+
// • sibling (this repo): build in place.
|
|
83
|
+
// • installed: the engine sits inside node_modules, but Next won't transpile app
|
|
84
|
+
// source under node_modules — so stage a copy in PROJECT/.otherplane/engine and
|
|
85
|
+
// install deps THERE (kept across builds; `otherplane clean` drops it).
|
|
86
|
+
function prepareEngine() {
|
|
87
|
+
if (!INSTALLED) { BUILD_ENGINE = ENGINE; ensureDepsIn(ENGINE); return; }
|
|
88
|
+
const work = join(PROJECT, '.otherplane', 'engine');
|
|
89
|
+
// Refresh source every run (cheap); keep node_modules (expensive) across builds.
|
|
90
|
+
if (existsSync(work)) {
|
|
91
|
+
for (const e of readdirSync(work)) {
|
|
92
|
+
if (e !== 'node_modules') rmSync(join(work, e), { recursive: true, force: true });
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
mkdirSync(work, { recursive: true });
|
|
96
|
+
}
|
|
97
|
+
cpSync(ENGINE, work, {
|
|
98
|
+
recursive: true,
|
|
99
|
+
filter: (src) => {
|
|
100
|
+
const rel = src.slice(ENGINE.length);
|
|
101
|
+
return !rel.startsWith(`${sep}node_modules`)
|
|
102
|
+
&& !rel.startsWith(`${sep}.next`)
|
|
103
|
+
&& !rel.startsWith(`${sep}out`);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
BUILD_ENGINE = work;
|
|
107
|
+
ensureDepsIn(work);
|
|
108
|
+
}
|
|
109
|
+
|
|
68
110
|
// Env passed to every engine (Next) invocation so it reads THIS project's config
|
|
69
111
|
// and content — not whatever happens to sit beside the engine dir.
|
|
70
112
|
const engineEnv = (extra = {}) => ({ ...process.env, OTHERPLANE_PROJECT: PROJECT, ...extra });
|
|
@@ -100,16 +142,9 @@ function syncDir(src, dest) {
|
|
|
100
142
|
}
|
|
101
143
|
|
|
102
144
|
function sync() {
|
|
103
|
-
for (const d of CONTENT_DIRS) syncDir(join(PROJECT, d), join(
|
|
145
|
+
for (const d of CONTENT_DIRS) syncDir(join(PROJECT, d), join(publicDir(), d));
|
|
104
146
|
}
|
|
105
147
|
|
|
106
|
-
// Install the engine's deps on first use (so `npx otherplane` / a global install
|
|
107
|
-
// works with no separate setup step). No-op once node_modules exists.
|
|
108
|
-
function ensureEngineDeps() {
|
|
109
|
-
if (existsSync(join(ENGINE, 'node_modules'))) return;
|
|
110
|
-
console.log('installing the engine’s dependencies (one-time, ~a minute)…');
|
|
111
|
-
run('npm', ['--prefix', ENGINE, 'install']);
|
|
112
|
-
}
|
|
113
148
|
|
|
114
149
|
// How many rooms the project actually has (a folder with a room.json).
|
|
115
150
|
function roomCount() {
|
|
@@ -124,7 +159,7 @@ function roomCount() {
|
|
|
124
159
|
function syncRoom(slug) {
|
|
125
160
|
const src = join(PROJECT, 'rooms', slug, 'room.json');
|
|
126
161
|
if (!existsSync(src)) return;
|
|
127
|
-
const destDir = join(
|
|
162
|
+
const destDir = join(publicDir(), 'rooms', slug);
|
|
128
163
|
mkdirSync(destDir, { recursive: true });
|
|
129
164
|
copyFileSync(src, join(destDir, 'room.json'));
|
|
130
165
|
}
|
|
@@ -353,7 +388,7 @@ function startEditServer() {
|
|
|
353
388
|
// (not spawnSync) so the writer's event loop keeps serving while Next runs.
|
|
354
389
|
function runEdit() {
|
|
355
390
|
const server = startEditServer();
|
|
356
|
-
const child = spawn('npm', ['--prefix',
|
|
391
|
+
const child = spawn('npm', ['--prefix', BUILD_ENGINE, 'run', 'edit'], {
|
|
357
392
|
stdio: 'inherit',
|
|
358
393
|
cwd: PROJECT,
|
|
359
394
|
env: engineEnv({ NEXT_PUBLIC_EDIT_API: `http://localhost:${EDIT_PORT}` }),
|
|
@@ -423,15 +458,15 @@ function buildEngine(base) {
|
|
|
423
458
|
console.error('no rooms yet — add one with `otherplane new` or create rooms/<slug>/room.json, then build.');
|
|
424
459
|
process.exit(1);
|
|
425
460
|
}
|
|
426
|
-
|
|
461
|
+
prepareEngine();
|
|
427
462
|
check();
|
|
428
463
|
sync();
|
|
429
|
-
run('npm', ['--prefix',
|
|
464
|
+
run('npm', ['--prefix', BUILD_ENGINE, 'run', 'build'], {
|
|
430
465
|
env: engineEnv(base != null ? { OTHERPLANE_BASE_PATH: base } : {}),
|
|
431
466
|
});
|
|
432
|
-
if (
|
|
467
|
+
if (engineOut() !== OUT) {
|
|
433
468
|
rmSync(OUT, { recursive: true, force: true });
|
|
434
|
-
cpSync(
|
|
469
|
+
cpSync(engineOut(), OUT, { recursive: true });
|
|
435
470
|
console.log(`✓ exported to ${OUT}`);
|
|
436
471
|
}
|
|
437
472
|
}
|
|
@@ -446,12 +481,12 @@ switch (cmd) {
|
|
|
446
481
|
sync();
|
|
447
482
|
break;
|
|
448
483
|
case 'dev':
|
|
449
|
-
|
|
484
|
+
prepareEngine();
|
|
450
485
|
sync();
|
|
451
|
-
run('npm', ['--prefix',
|
|
486
|
+
run('npm', ['--prefix', BUILD_ENGINE, 'run', 'dev'], { env: engineEnv() });
|
|
452
487
|
break;
|
|
453
488
|
case 'edit':
|
|
454
|
-
|
|
489
|
+
prepareEngine();
|
|
455
490
|
sync();
|
|
456
491
|
runEdit();
|
|
457
492
|
break;
|
|
@@ -469,11 +504,14 @@ switch (cmd) {
|
|
|
469
504
|
run('python3', ['-m', 'http.server', '8000'], { cwd: OUT });
|
|
470
505
|
break;
|
|
471
506
|
case 'clean':
|
|
507
|
+
// Remove build output in both layouts: the in-place engine (dev sibling), the
|
|
508
|
+
// staged copy (installed), and the project's out/.
|
|
472
509
|
rmSync(join(ENGINE, '.next'), { recursive: true, force: true });
|
|
473
|
-
rmSync(
|
|
510
|
+
rmSync(join(ENGINE, 'out'), { recursive: true, force: true });
|
|
511
|
+
for (const d of CONTENT_DIRS) rmSync(join(ENGINE, 'public', d), { recursive: true, force: true });
|
|
512
|
+
rmSync(join(PROJECT, '.otherplane'), { recursive: true, force: true });
|
|
474
513
|
rmSync(OUT, { recursive: true, force: true });
|
|
475
|
-
|
|
476
|
-
console.log('cleaned build output (.next, out) and the synced mirror');
|
|
514
|
+
console.log('cleaned build output (.next, out, .otherplane) and the synced mirror');
|
|
477
515
|
break;
|
|
478
516
|
case 'setup':
|
|
479
517
|
run('npm', ['--prefix', ENGINE, 'install']);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "otherplane",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A static site generator for walkable Gaussian-splat museums. Generate a 3D room per section, link rooms with doorways, publish a static walkable site.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gaussian-splatting",
|