create-cubeforge-game 0.0.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/index.js ADDED
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/index.ts
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ import * as readline from "readline";
7
+ function prompt(question) {
8
+ return new Promise((resolve2) => {
9
+ const rl = readline.createInterface({
10
+ input: process.stdin,
11
+ output: process.stdout
12
+ });
13
+ rl.question(question, (answer) => {
14
+ rl.close();
15
+ resolve2(answer.trim());
16
+ });
17
+ });
18
+ }
19
+ function copyTemplateDir(src, dest, projectName) {
20
+ if (!fs.existsSync(dest)) {
21
+ fs.mkdirSync(dest, { recursive: true });
22
+ }
23
+ const entries = fs.readdirSync(src, { withFileTypes: true });
24
+ for (const entry of entries) {
25
+ const srcPath = path.join(src, entry.name);
26
+ const destName = entry.name.endsWith(".template") ? entry.name.slice(0, -".template".length) : entry.name;
27
+ const destPath = path.join(dest, destName);
28
+ if (entry.isDirectory()) {
29
+ copyTemplateDir(srcPath, destPath, projectName);
30
+ } else {
31
+ const content = fs.readFileSync(srcPath, "utf8");
32
+ const replaced = content.replaceAll("{{PROJECT_NAME}}", projectName);
33
+ fs.writeFileSync(destPath, replaced, "utf8");
34
+ }
35
+ }
36
+ }
37
+ async function main() {
38
+ let projectName = process.argv[2];
39
+ if (!projectName) {
40
+ projectName = await prompt("Project name: ");
41
+ }
42
+ if (!projectName) {
43
+ process.stderr.write(`Error: project name is required.
44
+ `);
45
+ process.exit(1);
46
+ }
47
+ const targetDir = path.resolve(process.cwd(), projectName);
48
+ if (fs.existsSync(targetDir)) {
49
+ process.stderr.write(`Error: directory "${projectName}" already exists.
50
+ `);
51
+ process.exit(1);
52
+ }
53
+ const templatesDir = path.join(import.meta.dirname, "..", "templates", "default");
54
+ process.stdout.write(`
55
+ Creating new Cubeforge game in ${targetDir}...
56
+ `);
57
+ copyTemplateDir(templatesDir, targetDir, projectName);
58
+ process.stdout.write(`
59
+ Done! Your project "${projectName}" is ready.
60
+ `);
61
+ process.stdout.write(`
62
+ Next steps:
63
+ `);
64
+ process.stdout.write(` cd ${projectName}
65
+ `);
66
+ process.stdout.write(` npm install # or bun install
67
+ `);
68
+ process.stdout.write(` npm run dev # or bun dev
69
+
70
+ `);
71
+ }
72
+ main().catch((err) => {
73
+ process.stderr.write(`Unexpected error: ${String(err)}
74
+ `);
75
+ process.exit(1);
76
+ });
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "create-cubeforge-game",
3
+ "version": "0.0.1",
4
+ "description": "Scaffold a new Cubeforge game project",
5
+ "bin": {
6
+ "create-cubeforge-game": "./bin/index.js"
7
+ },
8
+ "scripts": {
9
+ "build": "bun build ./bin/index.ts --outfile bin/index.js --target node"
10
+ },
11
+ "publishConfig": {
12
+ "bin": {
13
+ "create-cubeforge-game": "./bin/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "bin/index.js",
18
+ "templates"
19
+ ],
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/1homsi/cubeforge"
24
+ }
25
+ }
@@ -0,0 +1,13 @@
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>{{PROJECT_NAME}}</title>
7
+ <style>* { margin: 0; padding: 0; box-sizing: border-box; } body { background: #000; display: flex; justify-content: center; align-items: center; min-height: 100vh; }</style>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview"
9
+ },
10
+ "dependencies": {
11
+ "@cubeforge/react": "latest",
12
+ "react": "^18.0.0",
13
+ "react-dom": "^18.0.0"
14
+ },
15
+ "devDependencies": {
16
+ "@types/react": "^18.3.0",
17
+ "@types/react-dom": "^18.3.0",
18
+ "@vitejs/plugin-react": "^4.0.0",
19
+ "typescript": "^5.4.0",
20
+ "vite": "^5.0.0"
21
+ }
22
+ }
@@ -0,0 +1,17 @@
1
+ import { useState } from 'react'
2
+ import { Game, World, Camera2D } from '@cubeforge/react'
3
+ import { Player } from './components/Player'
4
+ import { Ground } from './components/Ground'
5
+
6
+ export function App() {
7
+ const [gameKey] = useState(0)
8
+ return (
9
+ <Game key={gameKey} width={800} height={500} gravity={980}>
10
+ <World background="#87ceeb">
11
+ <Camera2D followEntity="player" smoothing={0.85} />
12
+ <Player x={100} y={300} />
13
+ <Ground x={400} y={480} width={800} height={40} />
14
+ </World>
15
+ </Game>
16
+ )
17
+ }
@@ -0,0 +1,12 @@
1
+ import { Entity, Transform, Sprite, RigidBody, BoxCollider } from '@cubeforge/react'
2
+ interface GroundProps { x: number; y: number; width: number; height: number }
3
+ export function Ground({ x, y, width, height }: GroundProps) {
4
+ return (
5
+ <Entity tags={['ground']}>
6
+ <Transform x={x} y={y} />
7
+ <Sprite width={width} height={height} color="#37474f" />
8
+ <RigidBody isStatic />
9
+ <BoxCollider width={width} height={height} />
10
+ </Entity>
11
+ )
12
+ }
@@ -0,0 +1,22 @@
1
+ import { Entity, Transform, Sprite, RigidBody, BoxCollider, Script } from '@cubeforge/react'
2
+ import { usePlatformerController } from '@cubeforge/react'
3
+ import { useEntity } from '@cubeforge/react'
4
+
5
+ function PlayerInner() {
6
+ const id = useEntity()
7
+ usePlatformerController(id, { speed: 220, jumpForce: -520, maxJumps: 2 })
8
+ return null
9
+ }
10
+
11
+ interface PlayerProps { x: number; y: number }
12
+ export function Player({ x, y }: PlayerProps) {
13
+ return (
14
+ <Entity id="player" tags={['player']}>
15
+ <Transform x={x} y={y} />
16
+ <Sprite width={32} height={48} color="#4fc3f7" />
17
+ <RigidBody />
18
+ <BoxCollider width={32} height={48} />
19
+ <PlayerInner />
20
+ </Entity>
21
+ )
22
+ }
@@ -0,0 +1,4 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import { App } from './App'
4
+ createRoot(document.getElementById('root')!).render(<StrictMode><App /></StrictMode>)
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "jsx": "react-jsx"
9
+ },
10
+ "include": ["src"]
11
+ }
@@ -0,0 +1,3 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ export default defineConfig({ plugins: [react()] })