Here is the complete solution to port your Node.js LPC Virtual Machine into a
standalone browser environment.
To achieve this cleanly, the solution is split into two files:
template.html: The static frontend shell containing the CSS, UI, and the
runtime shims (require, fs, sys.stdout, etc.).
build_web.js: The Node.js compiler script that recursively reads the VM
directories, bundles the source code, strips out the Node-specific terminal
logic from harness.js, and injects everything into the HTML template.
1. The HTML Template (template.html)
This file contains the retro-terminal styling, the Virtual File System (VFS)
shims, the require() stub, and the bootstrap logic that initializes the VM
when the page loads.
==
2. The Build Script (build_web.js)
This script crawls the target directories, packages all standard Node.js and
LPC files into a dictionary, patches out the Node-specific process.argv loop
in harness.js, and outputs the finished index.html.
==
const fs = require('fs');
const path = require('path');
function walkSync(dir, filelist = []) {
if (!fs.existsSync(dir)) return filelist;
fs.readdirSync(dir).forEach(file => {
const filepath = path.join(dir, file);
if (fs.statSync(filepath).isDirectory()) {
filelist = walkSync(filepath, filelist);
} else {
filelist.push(filepath);
}
});
return filelist;
}
console.log("Packaging LPC VM...");
let vfs = {};
const dirsToScan = ['core', 'efuns.d', 'gamelib', 'tests'];
/ Recursively map required directories
dirsToScan.forEach(dir => {
walkSync(dir).forEach(file => {
// Normalize paths for VFS dictionary (POSIX format internally)
let key = file.split(path.sep).join('/');
vfs[key] = fs.readFileSync(file, 'utf8');
console.log(` -> Cached: ${key}`);
});
});
/ Cache global dependencies
if (fs.existsSync('efuns.js')) {
vfs['efuns.js'] = fs.readFileSync('efuns.js', 'utf8');
}
if (fs.existsSync('harness.js')) {
let harnessSrc = fs.readFileSync('harness.js', 'utf8');
// AST / Module Patch: Swap out the auto-executing runVM() call
// so it safely exports the GDCompiler class to our browser CommonJS shim!
harnessSrc = harnessSrc.replace(/^runVM\(\);/m, 'module.exports =
GDCompiler;');
vfs['harness.js'] = harnessSrc;
}
/ Generate the final static HTML bundle
if (!fs.existsSync('template.html')) {
console.error("ERROR: template.html is missing. Cannot build frontend.");
process.exit(1);
}
let templateData = fs.readFileSync('template.html', 'utf8');
const vfsInjectionString = `window.__VFS = ${JSON.stringify(vfs)};`;
const finalHtml = templateData.replace('/* VFS_INJECTION_POINT */',
vfsInjectionString);
fs.writeFileSync('index.html', finalHtml);
console.log("n SUCCESS: index.html has been generated. Open it in a browser to
use the REPL.");
==
Usage Instructions
Ensure both build_web.js and template.html reside in your ~/Downloads/Remote/LP
C/GEM directory.
Run node build_web.js.
Open index.html in your web browser.