create-pixifact 0.1.3

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/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # create-pixifact
2
+
3
+ Create a Bun-first Pixifact game project.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ bun create pixifact my-game
9
+ cd my-game
10
+ bun install
11
+ bun run dev
12
+ ```
13
+
14
+ The generated project includes:
15
+
16
+ - `pixifact.project.json`
17
+ - a minimal Pixifact Scene pair
18
+ - Vite project scripts
19
+ - `pixifact` and `pixifact-cli` dependencies
20
+
21
+ ## Generated Scripts
22
+
23
+ ```bash
24
+ bun run compile:scenes
25
+ bun run dev
26
+ bun run build
27
+ ```
28
+
29
+ ## Requirements
30
+
31
+ - Bun
@@ -0,0 +1,11 @@
1
+ export interface CreatePixifactProjectOptions {
2
+ cwd?: string;
3
+ name: string;
4
+ template?: 'minimal';
5
+ }
6
+ export interface CreatePixifactProjectResult {
7
+ name: string;
8
+ root: string;
9
+ template: 'minimal';
10
+ }
11
+ export declare function createPixifactProject(options: CreatePixifactProjectOptions): Promise<CreatePixifactProjectResult>;
@@ -0,0 +1,68 @@
1
+ import { cp, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const defaultPort = 5177;
5
+ function packageDirectory() {
6
+ const currentFile = fileURLToPath(import.meta.url);
7
+ const sourceDirectory = path.basename(path.dirname(currentFile));
8
+ return sourceDirectory === 'src' || sourceDirectory === 'dist'
9
+ ? path.resolve(currentFile, '../..')
10
+ : path.resolve(currentFile, '..');
11
+ }
12
+ function templateDirectory(template) {
13
+ return path.join(packageDirectory(), 'templates', template);
14
+ }
15
+ function projectDisplayName(name) {
16
+ return name
17
+ .split(/[-_\s]+/)
18
+ .filter(Boolean)
19
+ .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
20
+ .join(' ');
21
+ }
22
+ async function directoryIsEmpty(target) {
23
+ try {
24
+ const targetStat = await stat(target);
25
+ if (!targetStat.isDirectory()) {
26
+ throw new Error('Target path exists and is not a directory.');
27
+ }
28
+ return (await readdir(target)).length === 0;
29
+ }
30
+ catch (error) {
31
+ if (error.code === 'ENOENT') {
32
+ return true;
33
+ }
34
+ throw error;
35
+ }
36
+ }
37
+ async function writeJson(filePath, value) {
38
+ await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
39
+ }
40
+ export async function createPixifactProject(options) {
41
+ const template = options.template ?? 'minimal';
42
+ const cwd = options.cwd ?? process.cwd();
43
+ const projectRoot = path.resolve(cwd, options.name);
44
+ if (!(await directoryIsEmpty(projectRoot))) {
45
+ throw new Error('Target directory is not empty.');
46
+ }
47
+ await mkdir(projectRoot, { recursive: true });
48
+ await cp(templateDirectory(template), projectRoot, { recursive: true });
49
+ const packageJsonPath = path.join(projectRoot, 'package.json');
50
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
51
+ packageJson.name = options.name;
52
+ await writeJson(packageJsonPath, packageJson);
53
+ const projectJsonPath = path.join(projectRoot, 'pixifact.project.json');
54
+ const projectJson = JSON.parse(await readFile(projectJsonPath, 'utf8'));
55
+ projectJson.name = projectDisplayName(options.name);
56
+ projectJson.run = {
57
+ command: 'bun',
58
+ args: ['run', 'dev'],
59
+ cwd: '.',
60
+ url: `http://127.0.0.1:${defaultPort}`,
61
+ };
62
+ await writeJson(projectJsonPath, projectJson);
63
+ return {
64
+ name: options.name,
65
+ root: projectRoot,
66
+ template,
67
+ };
68
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ import { createPixifactProject } from './createPixifactProject';
3
+ export { createPixifactProject };
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bun
2
+ import { createPixifactProject } from './createPixifactProject';
3
+ function usage() {
4
+ return [
5
+ 'Usage:',
6
+ ' bun create pixifact <project-name>',
7
+ '',
8
+ ].join('\n');
9
+ }
10
+ const name = process.argv[2];
11
+ if (!name || name === '--help' || name === '-h') {
12
+ process.stdout.write(usage());
13
+ process.exitCode = name ? 0 : 1;
14
+ }
15
+ else {
16
+ try {
17
+ const result = await createPixifactProject({ name });
18
+ process.stdout.write(`Created ${result.name} at ${result.root}\n`);
19
+ process.stdout.write(`Next: cd ${result.name} && bun install && bun run dev\n`);
20
+ }
21
+ catch (error) {
22
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
23
+ process.exitCode = 1;
24
+ }
25
+ }
26
+ export { createPixifactProject };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "create-pixifact",
3
+ "version": "0.1.3",
4
+ "description": "Create a Pixifact game project.",
5
+ "packageManager": "bun@1.3.13",
6
+ "type": "module",
7
+ "bin": {
8
+ "create-pixifact": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "templates/"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/hxg2050/pixifact.git",
17
+ "directory": "packages/create-pixifact"
18
+ },
19
+ "keywords": [
20
+ "pixifact",
21
+ "create-pixifact",
22
+ "game",
23
+ "pixijs",
24
+ "scene"
25
+ ],
26
+ "author": "youxia <243802688@qq.com>",
27
+ "license": "MIT",
28
+ "publishConfig": {
29
+ "registry": "https://registry.npmjs.org/"
30
+ },
31
+ "scripts": {
32
+ "build": "bunx --no-install tsc -p tsconfig.build.json"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^25.9.1",
36
+ "typescript": "^5.3.3"
37
+ }
38
+ }
@@ -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>Pixifact Game</title>
7
+ </head>
8
+ <body>
9
+ <div id="game"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "pixifact-minimal-game",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "compile:scenes": "pixifact compile-scenes --project-root .",
8
+ "dev": "bun run compile:scenes && vite . --host 127.0.0.1 --port 5177 --strictPort",
9
+ "build": "bun run compile:scenes && vite build . --config vite.config.ts"
10
+ },
11
+ "dependencies": {
12
+ "pixi.js": "8.18.1",
13
+ "pixifact": "^0.1.3"
14
+ },
15
+ "devDependencies": {
16
+ "pixifact-cli": "^0.1.3",
17
+ "typescript": "^5.3.3",
18
+ "vite": "^8.0.10"
19
+ }
20
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 1,
3
+ "name": "Pixifact Game",
4
+ "scenes": {
5
+ "mainMenu": "src/scenes/MainMenu.scene"
6
+ },
7
+ "run": {
8
+ "command": "bun",
9
+ "args": ["run", "dev"],
10
+ "cwd": ".",
11
+ "url": "http://127.0.0.1:5177"
12
+ }
13
+ }
@@ -0,0 +1,22 @@
1
+ import './styles.css';
2
+ import 'pixifact:scenes';
3
+ import { Application } from 'pixi.js';
4
+ import { MainMenu } from './scenes/MainMenu';
5
+
6
+ const root = document.querySelector<HTMLElement>('#game');
7
+ if (!root) {
8
+ throw new Error('Missing #game root.');
9
+ }
10
+
11
+ const app = new Application();
12
+ await app.init({
13
+ width: 960,
14
+ height: 540,
15
+ backgroundColor: 0x10131d,
16
+ antialias: true,
17
+ autoDensity: true,
18
+ resolution: Math.min(window.devicePixelRatio || 1, 2),
19
+ });
20
+ root.append(app.canvas);
21
+
22
+ app.stage.addChild(new MainMenu());
@@ -0,0 +1 @@
1
+ declare module 'pixifact:scenes' {}
@@ -0,0 +1,8 @@
1
+ <Scene name="MainMenu" width="960" height="540">
2
+ <Graphics id="background" shape="rect" width="960" height="540" fill="#10131d" />
3
+ <Graphics id="panel" shape="roundRect" x="260" y="148" width="440" height="244" radius="24" fill="#182033" strokeColor="#38bdf8" strokeWidth="2" strokeAlpha="0.72" />
4
+ <Text id="titleText" text="Pixifact Game" x="314" y="202" fontSize="44" fontWeight="700" fill="#f8fafc" />
5
+ <Text id="hintText" text="Edit src/scenes/MainMenu.scene, then run pixifact validate and compile." x="300" y="278" fontSize="18" fill="#cbd5e1" />
6
+ <Graphics id="startButtonBack" shape="roundRect" x="378" y="326" width="204" height="50" radius="14" fill="#2563eb" />
7
+ <Text id="startLabel" text="START" x="435" y="340" fontSize="20" fontWeight="700" fill="#ffffff" />
8
+ </Scene>
@@ -0,0 +1,29 @@
1
+ import { Container, Graphics, Text } from 'pixi.js';
2
+ import { createEvent, event, part, scene } from 'pixifact/compiler';
3
+
4
+ @scene()
5
+ export class MainMenu extends Container {
6
+ @part()
7
+ protected declare startButtonBack: Graphics;
8
+
9
+ @part()
10
+ protected declare startLabel: Text;
11
+
12
+ @event()
13
+ readonly start = createEvent();
14
+
15
+ onMounted() {
16
+ this.startButtonBack.eventMode = 'static';
17
+ this.startButtonBack.cursor = 'pointer';
18
+ this.startButtonBack.on('pointertap', () => {
19
+ this.startLabel.text = 'READY';
20
+ this.start.emit();
21
+ });
22
+ this.startButtonBack.on('pointerover', () => {
23
+ this.startButtonBack.tint = 0xc7d2fe;
24
+ });
25
+ this.startButtonBack.on('pointerout', () => {
26
+ this.startButtonBack.tint = 0xffffff;
27
+ });
28
+ }
29
+ }
@@ -0,0 +1,16 @@
1
+ html,
2
+ body,
3
+ #game {
4
+ width: 100%;
5
+ height: 100%;
6
+ margin: 0;
7
+ }
8
+
9
+ body {
10
+ overflow: hidden;
11
+ background: #10131d;
12
+ }
13
+
14
+ canvas {
15
+ display: block;
16
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Node",
6
+ "strict": true,
7
+ "experimentalDecorators": true,
8
+ "useDefineForClassFields": true,
9
+ "lib": ["ESNext", "DOM"],
10
+ "skipLibCheck": true
11
+ },
12
+ "include": ["src/**/*.ts"]
13
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vite';
2
+ import { pixifactScenesPlugin } from 'pixifact/compiler-node';
3
+
4
+ const projectRoot = new URL('.', import.meta.url);
5
+
6
+ export default defineConfig({
7
+ plugins: [
8
+ pixifactScenesPlugin({ projectRoot }),
9
+ ],
10
+ });