create-kaplay-game
Version:
CLI to scaffold an Electron+Vite+Kaplay game project.
153 lines (136 loc) • 4.65 kB
JavaScript
const inquirer = require("inquirer");
const fs = require("fs-extra");
const path = require("path");
const chalk = require("chalk");
const { execSync } = require("child_process");
async function main() {
console.log(chalk.cyan("\nKaplay Game Creator - Electron + Vite + Kaplay\n"));
// Support project name as CLI argument
const cliProjectName = process.argv[2];
const questions = [];
if (!cliProjectName) {
questions.push({
type: "input",
name: "projectName",
message: "Project name:",
validate: (input) => (input ? true : "Project name cannot be empty."),
});
}
questions.push(
{
type: "list",
name: "language",
message: "Choose language:",
choices: ["JavaScript", "TypeScript"],
},
{
type: "number",
name: "width",
message: "Window width:",
default: 800,
validate: (input) => (input > 0 ? true : "Width must be positive."),
},
{
type: "number",
name: "height",
message: "Window height:",
default: 600,
validate: (input) => (input > 0 ? true : "Height must be positive."),
}
);
const answers = await inquirer.prompt(questions);
const projectName = cliProjectName || answers.projectName;
const { language, width, height } = answers;
const templateDir = path.join(
__dirname,
"templates",
language === "JavaScript" ? "js" : "ts"
);
const targetDir =
projectName === "./"
? process.cwd()
: path.resolve(process.cwd(), projectName);
if (projectName !== "./" && fs.existsSync(targetDir)) {
console.log(chalk.red(`\nDirectory '${projectName}' already exists!`));
process.exit(1);
}
// Copy template files (do not overwrite existing files in ./)
await fs.copy(templateDir, targetDir, {
overwrite: false,
errorOnExist: false,
});
// Explicitly copy .tools folder (even if hidden)
const toolsSrc = path.join(templateDir, ".tools");
const toolsDest = path.join(targetDir, ".tools");
if (await fs.pathExists(toolsSrc)) {
await fs.copy(toolsSrc, toolsDest, {
overwrite: false,
errorOnExist: false,
});
}
// Replace window size placeholders in electron.js or electron.ts
const electronFile =
language === "JavaScript"
? path.join("src", "electron", "electron.js")
: path.join("src", "electron", "electron.ts");
const electronPath = path.join(targetDir, electronFile);
let electronContent = await fs.readFile(electronPath, "utf8");
electronContent = electronContent
.replace(/__KAPLAY_WIDTH__/g, width)
.replace(/__KAPLAY_HEIGHT__/g, height);
await fs.writeFile(electronPath, electronContent, "utf8");
// Update main field and clear script in package.json
const packageJsonPath = path.join(targetDir, "package.json");
let packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
packageJson.main = electronFile;
packageJson.scripts = packageJson.scripts || {};
packageJson.scripts.clear = "node .tools/clear.js";
await fs.writeFile(
packageJsonPath,
JSON.stringify(packageJson, null, 2),
"utf8"
);
// Ensure .tools/ is in .gitignore
const gitignorePath = path.join(targetDir, ".gitignore");
let gitignore = "";
if (await fs.pathExists(gitignorePath)) {
gitignore = await fs.readFile(gitignorePath, "utf8");
if (!gitignore.includes(".tools/")) {
gitignore += (gitignore.endsWith("\n") ? "" : "\n") + ".tools/\n";
await fs.writeFile(gitignorePath, gitignore, "utf8");
}
} else {
await fs.writeFile(gitignorePath, ".tools/\n", "utf8");
}
// Update canvas size in index.html
const htmlPath = path.join(targetDir, "index.html");
let htmlContent = await fs.readFile(htmlPath, "utf8");
htmlContent = htmlContent
.replace(/width="\d+"/, `width=\"${width}\"`)
.replace(/height="\d+"/, `height=\"${height}\"`);
await fs.writeFile(htmlPath, htmlContent, "utf8");
// Install dependencies
console.log(
chalk.green("\nInstalling dependencies... (this may take a minute)")
);
execSync("npm install", { cwd: targetDir, stdio: "inherit" });
console.log(
chalk.green(
`\nSuccess! Your Kaplay game is ready in '${
projectName === "./" ? "current directory" : projectName
}'.`
)
);
console.log(chalk.cyan(`\nTo get started:`));
if (projectName !== "./") {
console.log(chalk.white(` cd ${projectName}`));
}
if (language === "TypeScript") {
console.log(
chalk.white(" npm run build # (first time, to compile TypeScript)")
);
}
console.log(chalk.white(` npm run dev`));
}
main();