@iruka-edu/create-iruka-game 1.0.0

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/dist/index.cjs ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/index.ts
27
+ var import_fs_extra = __toESM(require("fs-extra"), 1);
28
+ var import_node_path = __toESM(require("path"), 1);
29
+ var import_prompts = __toESM(require("prompts"), 1);
30
+ var import_node_child_process = require("child_process");
31
+ var import_picocolors = __toESM(require("picocolors"), 1);
32
+ async function init() {
33
+ console.log(import_picocolors.default.cyan("\u{1F680} Iruka Game Starter CLI"));
34
+ const response = await (0, import_prompts.default)([
35
+ // 1. Hỏi tên project
36
+ {
37
+ type: "text",
38
+ name: "projectName",
39
+ message: "T\xEAn th\u01B0 m\u1EE5c game:",
40
+ initial: "my-iruka-game"
41
+ },
42
+ // 2. [MỚI] Hỏi loại Template
43
+ {
44
+ type: "select",
45
+ name: "templateType",
46
+ message: "Ch\u1ECDn lo\u1EA1i Project:",
47
+ choices: [
48
+ {
49
+ title: "Basic Phaser (Phaser.js only)",
50
+ description: "Nh\u1EC7, d\xF9ng @iruka-edu/game-core. Ph\xF9 h\u1EE3p game \u0111\u01A1n gi\u1EA3n.",
51
+ value: "basic-phaser"
52
+ },
53
+ {
54
+ title: "React + Phaser (Recommended)",
55
+ description: "M\u1EA1nh m\u1EBD, d\xF9ng @iruka-edu/mini-game-sdk. D\u1EC5 l\xE0m UI.",
56
+ value: "react-phaser"
57
+ }
58
+ ],
59
+ initial: 1
60
+ },
61
+ // 3. Hỏi Token
62
+ {
63
+ type: "password",
64
+ // Ẩn token khi nhập
65
+ name: "token",
66
+ message: "Nh\u1EADp GitHub Token (\u0111\u1EC3 c\xE0i \u0111\u1EB7t SDK):",
67
+ validate: (value) => value.length < 10 ? "Token kh\xF4ng h\u1EE3p l\u1EC7" : true
68
+ }
69
+ ]);
70
+ const { projectName, templateType, token } = response;
71
+ if (!projectName || !templateType || !token) process.exit(1);
72
+ const root = import_node_path.default.join(process.cwd(), projectName);
73
+ const templateDir = import_node_path.default.resolve(__dirname, `../templates/${templateType}`);
74
+ if (!import_fs_extra.default.existsSync(templateDir)) {
75
+ console.error(import_picocolors.default.red(`\u274C Kh\xF4ng t\xECm th\u1EA5y template: ${templateType}`));
76
+ process.exit(1);
77
+ }
78
+ if (import_fs_extra.default.existsSync(root)) {
79
+ console.error(import_picocolors.default.red(`\u274C Th\u01B0 m\u1EE5c ${projectName} \u0111\xE3 t\u1ED3n t\u1EA1i!`));
80
+ process.exit(1);
81
+ }
82
+ console.log(
83
+ import_picocolors.default.blue(`
84
+ \u{1F4C2} \u0110ang kh\u1EDFi t\u1EA1o project t\u1EEB template: ${templateType}...`)
85
+ );
86
+ import_fs_extra.default.copySync(templateDir, root);
87
+ const pkgPath = import_node_path.default.join(root, "package.json");
88
+ const pkg = import_fs_extra.default.readJsonSync(pkgPath);
89
+ pkg.name = projectName;
90
+ import_fs_extra.default.writeJsonSync(pkgPath, pkg, { spaces: 2 });
91
+ console.log(import_picocolors.default.blue("\u{1F511} \u0110ang c\u1EA5u h\xECnh x\xE1c th\u1EF1c..."));
92
+ const npmrcContent = `
93
+ @iruka-edu:registry=https://npm.pkg.github.com
94
+ //npm.pkg.github.com/:_authToken=${token}
95
+ `;
96
+ import_fs_extra.default.writeFileSync(import_node_path.default.join(root, ".npmrc"), npmrcContent.trim());
97
+ console.log(import_picocolors.default.blue("\u{1F4E6} \u0110ang c\xE0i \u0111\u1EB7t th\u01B0 vi\u1EC7n..."));
98
+ try {
99
+ const userAgent = process.env.npm_config_user_agent || "";
100
+ const pkgManager = userAgent.startsWith("pnpm") ? "pnpm" : "npm";
101
+ (0, import_node_child_process.execSync)(`${pkgManager} install`, { cwd: root, stdio: "inherit" });
102
+ (0, import_node_child_process.execSync)("git init", { cwd: root, stdio: "ignore" });
103
+ console.log(import_picocolors.default.green(`
104
+ \u2705 Th\xE0nh c\xF4ng! Game ${templateType} \u0111\xE3 s\u1EB5n s\xE0ng.`));
105
+ console.log(`
106
+ \u{1F449} Ch\u1EA1y l\u1EC7nh sau \u0111\u1EC3 b\u1EAFt \u0111\u1EA7u:
107
+ `);
108
+ console.log(import_picocolors.default.cyan(` cd ${projectName}`));
109
+ console.log(import_picocolors.default.cyan(` ${pkgManager} run dev`));
110
+ } catch (error) {
111
+ console.error(import_picocolors.default.red("\u274C L\u1ED7i c\xE0i \u0111\u1EB7t. Ki\u1EC3m tra l\u1EA1i Token."));
112
+ }
113
+ }
114
+ init().catch((e) => console.error(e));
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@iruka-edu/create-iruka-game",
3
+ "version": "1.0.0",
4
+ "description": "Create Iruka mini game (React + Phaser template)",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "create-iruka-game": "dist/index.cjs"
9
+ },
10
+ "scripts": {
11
+ "build": "tsup src/index.ts --format cjs --clean",
12
+ "dev": "tsup src/index.ts --format cjs --watch"
13
+ },
14
+ "dependencies": {
15
+ "fs-extra": "^11.3.3",
16
+ "picocolors": "^1.1.1",
17
+ "prompts": "^2.4.2"
18
+ },
19
+ "devDependencies": {
20
+ "@types/fs-extra": "^11.0.4",
21
+ "@types/prompts": "^2.4.9",
22
+ "tsup": "^8.0.0",
23
+ "typescript": "^5.5.0"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "templates"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "registry": "https://registry.npmjs.org/"
32
+ }
33
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Basic Phaser Game</title>
7
+ </head>
8
+ <body>
9
+ <div id="game-container"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "basic-phaser-template",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build"
9
+ },
10
+ "dependencies": {
11
+ "phaser": "^3.60.0",
12
+ "@iruka-edu/game-core": "latest"
13
+ },
14
+ "devDependencies": {
15
+ "typescript": "^5.0.0",
16
+ "vite": "^4.0.0"
17
+ }
18
+ }
@@ -0,0 +1,30 @@
1
+ import Phaser from "phaser";
2
+
3
+ class DemoScene extends Phaser.Scene {
4
+ constructor() {
5
+ super("DemoScene");
6
+ }
7
+
8
+ preload() {
9
+ // Preload assets here
10
+ }
11
+
12
+ create() {
13
+ this.add
14
+ .text(400, 300, "Iruka Basic Phaser Template", {
15
+ fontSize: "32px",
16
+ color: "#00ff00",
17
+ })
18
+ .setOrigin(0.5);
19
+ }
20
+ }
21
+
22
+ const config: Phaser.Types.Core.GameConfig = {
23
+ type: Phaser.AUTO,
24
+ width: 800,
25
+ height: 600,
26
+ scene: DemoScene,
27
+ parent: "game-container",
28
+ };
29
+
30
+ new Phaser.Game(config);
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "node",
9
+ "allowImportingTsExtensions": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "noEmit": true,
13
+ "strict": true,
14
+ "noUnusedLocals": true,
15
+ "noUnusedParameters": true,
16
+ "noImplicitReturns": true,
17
+ "allowJs": true,
18
+ "checkJs": false,
19
+ "esModuleInterop": true,
20
+ "forceConsistentCasingInFileNames": true
21
+ },
22
+ "include": ["src"]
23
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vite";
2
+
3
+ export default defineConfig({
4
+ server: {
5
+ port: 3000,
6
+ },
7
+ });
@@ -0,0 +1,28 @@
1
+ # **IRUKA_GAME_NAME**
2
+
3
+ An Iruka mini game built with React + Phaser.
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ pnpm install
10
+
11
+ # Start development server
12
+ pnpm dev
13
+
14
+ # Build for production
15
+ pnpm build
16
+ ```
17
+
18
+ ## Update SDK
19
+
20
+ ```bash
21
+ pnpm up @iruka-edu/mini-game-sdk
22
+ ```
23
+
24
+ ## Check SDK version
25
+
26
+ ```bash
27
+ pnpm sdk:check
28
+ ```
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>__IRUKA_GAME_NAME__</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,5 @@
1
+ {
2
+ "game_id": "__IRUKA_GAME_ID__",
3
+ "game_name": "__IRUKA_GAME_NAME__",
4
+ "game_version": "0.0.1"
5
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "react-phaser-template",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build"
9
+ },
10
+ "dependencies": {
11
+ "react": "^18.2.0",
12
+ "react-dom": "^18.2.0",
13
+ "phaser": "^3.60.0",
14
+ "@iruka-edu/mini-game-sdk": "latest"
15
+ },
16
+ "devDependencies": {
17
+ "@types/react": "^18.0.0",
18
+ "@types/react-dom": "^18.0.0",
19
+ "@vitejs/plugin-react": "^4.0.0",
20
+ "typescript": "^5.0.0",
21
+ "vite": "^4.0.0"
22
+ }
23
+ }
@@ -0,0 +1,5 @@
1
+ import pkg from "../package.json" with { type: "json" };
2
+
3
+ const v = pkg.dependencies?.["@iruka/mini-game-sdk"];
4
+ console.log(`[Iruka] SDK dependency: @iruka/mini-game-sdk = ${v || "missing"}`);
5
+ console.log(`[Iruka] Tip: run "pnpm up @iruka/mini-game-sdk" to update.`);
@@ -0,0 +1,24 @@
1
+ import { BaseGame, type GameRuntimeConfig } from "@iruka/mini-game-sdk";
2
+
3
+ export class MyGame extends BaseGame {
4
+ private score = 0;
5
+
6
+ async onInit(cfg: GameRuntimeConfig) {
7
+ super.onInit(cfg);
8
+ const root = document.getElementById("game-root")!;
9
+ root.innerHTML = `
10
+ <div style="padding:24px;font:16px/1.4 system-ui">
11
+ <h2>🐳 __IRUKA_GAME_NAME__</h2>
12
+ <p>Locale: ${cfg.locale} • Difficulty: ${cfg.difficulty}</p>
13
+ <button id="btn-score">+1 điểm</button>
14
+ </div>
15
+ `;
16
+ document.getElementById("btn-score")?.addEventListener("click", () => {
17
+ this.score++;
18
+ (window as any).__irukaBridge?.score?.(this.score, 1);
19
+ this.telemetry({ type: "score", data: { score: this.score } });
20
+ });
21
+ }
22
+ }
23
+
24
+ export const createGame = () => new MyGame();
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import {
4
+ IrukaGameHost,
5
+ createIframeBridge,
6
+ type HostCommand,
7
+ } from "@iruka-edu/mini-game-sdk";
8
+ import { createGame } from "./MyGame";
9
+
10
+ const bridge = createIframeBridge((cmd: HostCommand) => {
11
+ console.log("[Hub→Game]", cmd);
12
+ }, "*");
13
+ (window as any).__irukaBridge = bridge;
14
+
15
+ const App = () => (
16
+ <IrukaGameHost
17
+ createGame={createGame}
18
+ config={{
19
+ runtime: "iframe-html",
20
+ locale: "vi",
21
+ difficulty: 2,
22
+ seed: 123,
23
+ player: { userId: "demo" },
24
+ hubApi: {} as any,
25
+ }}
26
+ />
27
+ );
28
+
29
+ createRoot(document.getElementById("root")!).render(<App />);
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2022", "DOM"],
6
+ "jsx": "react-jsx",
7
+ "moduleResolution": "Bundler",
8
+ "strict": true,
9
+ "skipLibCheck": true
10
+ },
11
+ "include": ["src"]
12
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ base: "./",
7
+ });