@origingame/create-game 0.1.0 → 0.2.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.
Files changed (58) hide show
  1. package/README.md +15 -7
  2. package/archetypes/README.md +4 -2
  3. package/archetypes/idle/gitignore +8 -0
  4. package/archetypes/idle/package.json +1 -1
  5. package/archetypes/idle/project.ogt +1 -1
  6. package/archetypes/match3/gitignore +8 -0
  7. package/archetypes/match3/package.json +1 -1
  8. package/archetypes/match3/project.ogt +1 -1
  9. package/archetypes/rhythm/gitignore +8 -0
  10. package/archetypes/rhythm/package.json +1 -1
  11. package/archetypes/rhythm/project.ogt +1 -1
  12. package/archetypes/roguelike/gitignore +8 -0
  13. package/archetypes/roguelike/package.json +1 -1
  14. package/archetypes/roguelike/project.ogt +1 -1
  15. package/archetypes/runner/gitignore +8 -0
  16. package/archetypes/runner/package.json +1 -1
  17. package/archetypes/runner/project.ogt +1 -1
  18. package/archetypes/third-person/gitignore +8 -0
  19. package/archetypes/third-person/package.json +1 -1
  20. package/archetypes/third-person/project.ogt +1 -1
  21. package/archetypes/topdown/gitignore +8 -0
  22. package/archetypes/topdown/package.json +1 -1
  23. package/archetypes/topdown/project.ogt +1 -1
  24. package/archetypes/tower-defense/gitignore +8 -0
  25. package/archetypes/tower-defense/package.json +1 -1
  26. package/archetypes/tower-defense/project.ogt +1 -1
  27. package/bin/create.ts +80 -16
  28. package/package.json +5 -4
  29. package/template/gitignore +8 -0
  30. package/template/package.json +1 -1
  31. package/template/project.ogt +1 -1
  32. package/template-2d/.origin/setup +14 -0
  33. package/template-2d/LICENSES.md +14 -0
  34. package/template-2d/README.md +39 -0
  35. package/template-2d/assets/audio/coin.wav +0 -0
  36. package/template-2d/assets/audio/jump.wav +0 -0
  37. package/template-2d/assets/fonts/OFL.txt +93 -0
  38. package/template-2d/assets/fonts/ui.ttf +0 -0
  39. package/template-2d/assets/fonts/ui.ttf.ogt +11 -0
  40. package/template-2d/assets/looks/origin-game-2d.ogt +12 -0
  41. package/template-2d/assets/maps/level.ogt +112 -0
  42. package/template-2d/assets/sprites/coin.ogt +11 -0
  43. package/template-2d/assets/sprites/coin.png +0 -0
  44. package/template-2d/assets/sprites/coin.png.ogt +7 -0
  45. package/template-2d/assets/sprites/courier.ogt +34 -0
  46. package/template-2d/assets/sprites/courier.png +0 -0
  47. package/template-2d/assets/sprites/courier.png.ogt +7 -0
  48. package/template-2d/assets/strings/en.ogt +11 -0
  49. package/template-2d/assets/tiles/city.ogt +17 -0
  50. package/template-2d/assets/tiles/city.png +0 -0
  51. package/template-2d/assets/tiles/city.png.ogt +7 -0
  52. package/template-2d/gitattributes +22 -0
  53. package/template-2d/gitignore +8 -0
  54. package/template-2d/package.json +18 -0
  55. package/template-2d/project.ogt +21 -0
  56. package/template-2d/src/main.ts +305 -0
  57. package/template-2d/tests/smoke.og.ts +60 -0
  58. package/template-2d/tsconfig.json +17 -0
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # @origingame/create-game
2
2
 
3
- Scaffolds an Origin Engine game from the project template (`templates/game`
4
- of the engine repository): `project.ogt`, `src/`, `assets/`, `tests/`,
3
+ Scaffolds an Origin Engine game from a project template of the engine
4
+ repository, the 3D template `templates/game` or the 2D starter
5
+ `templates/game-2d`: `project.ogt`, `src/`, `assets/`, `tests/`,
5
6
  `package.json` and `tsconfig.json`, with the game's name and id filled in.
6
7
 
7
8
  ```sh
@@ -9,13 +10,20 @@ bun packages/create/bin/create.ts my-game --name "My Game" # in the engine rep
9
10
  cd my-game && bun install && og cook && og run .
10
11
  ```
11
12
 
12
- `create [dir] [--name "Name"] [--id slug] [--archetype name] [--premise "one line"] [--look slug] [--force]`: the
13
+ `create [dir] [--name "Name"] [--id slug] [--profile 2d|3d] [--archetype name] [--premise "one line"] [--look slug] [--force]`: the
13
14
  id defaults to the name in lowercase-hyphen form (or the directory's name);
14
15
  a directory that is not empty is refused unless `--force` is given.
16
+ `--profile 2d` writes the 2D starter (a courier's platformer: sprites,
17
+ flipbooks, a tilemap with one-way ledges, 2D physics, a HUD and a pause
18
+ menu, one playtest), `--profile 3d` the 3D template; without the flag, a
19
+ premise that says 2D, platformer, side-scroller, metroidvania, pixel art,
20
+ sprites or tiles without saying 3D gets the 2D starter, anything else the
21
+ 3D template. The output's `Profile:` line says which and why.
15
22
  `--archetype` starts from a complete game of `templates/archetypes/`
16
- instead of the template: `runner`, `match3`, `topdown`, `tower-defense`,
23
+ instead of either template: `runner`, `match3`, `topdown`, `tower-defense`,
17
24
  `roguelike`, `idle`, `rhythm` or `third-person` (the published package carries them under
18
- `archetypes/`).
25
+ `archetypes/`); an archetype has its own profile, so `--profile` beside it
26
+ is refused.
19
27
 
20
28
  Every game gets its look: `assets/looks/<id>.ogt`, an `.ogt` of `type look`
21
29
  (og-taste §12 of the knowledge package) that `GameDesc.look` in the entry
@@ -42,8 +50,8 @@ is, what it extends and how to change it. For an archetype, a preset moves
42
50
  the frames its `references/` hold; create says so and how to record them
43
51
  again.
44
52
 
45
- The published package carries the template under `template/` and the style
46
- catalogue under `looks/`, copied by the `prepack` script
53
+ The published package carries the 3D template under `template/`, the 2D
54
+ starter under `template-2d/` and the style catalogue under `looks/`, copied by the `prepack` script
47
55
  (`scripts/pack-template.ts`); build output (`cooked/`,
48
56
  `dist/`, `node_modules/`) is never copied. The template's `gitattributes`
49
57
  (media through Git LFS) is written as the project's `.gitattributes`: under
@@ -1,8 +1,10 @@
1
1
  # Archetypes
2
2
 
3
3
  Complete games a Maker starts from, each a project like `templates/game`
4
- (`project.ogt`, `src/`, `assets/`, `tests/`, `package.json`,
5
- `tsconfig.json`) that `og run`, `og test` and `og build` take as is. They
4
+ and the 2D starter `templates/game-2d` (`project.ogt`, `src/`, `assets/`,
5
+ `tests/`, `package.json`, `tsconfig.json`) that `og run`, `og test` and
6
+ `og build` take as is; `npm create @origingame/game --archetype <name>`
7
+ writes one, with its own profile. They
6
8
  rebuild the platform's six Godot Discover prototypes on Origin Engine,
7
9
  keeping each prototype's premise and lessons and none of its code or art,
8
10
  and add a top-down room built for the engine's 2D and game-feel modules
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Spark Orb"
5
5
  id "idle"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "2d"
9
9
  tick 60
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Tile Swap"
5
5
  id "match3"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "2d"
9
9
  tick 60
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Three-Lane Beat"
5
5
  id "rhythm"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "2d"
9
9
  tick 60
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Lamp Dive"
5
5
  id "roguelike"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "2d"
9
9
  tick 60
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Runner"
5
5
  id "runner"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "2d"
9
9
  tick 60
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Ember Vale"
5
5
  id "third-person"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "3d"
9
9
  tick 60
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Tomb Room"
5
5
  id "topdown"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "2d"
9
9
  tick 60
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -3,7 +3,7 @@ version 1
3
3
  ---
4
4
  name "Path Guard"
5
5
  id "tower-defense"
6
- engine "0.1.0"
6
+ engine "0.2.0"
7
7
  entry "src/main.ts"
8
8
  profile "2d"
9
9
  tick 60
package/bin/create.ts CHANGED
@@ -2,13 +2,16 @@
2
2
  // `npm create @origingame/game` (and `bun create`): scaffolds the Origin
3
3
  // Engine project template (templates/game) into a directory, naming the game.
4
4
  //
5
- // create [dir] [--name "Name"] [--id slug] [--archetype runner|match3|...]
5
+ // create [dir] [--name "Name"] [--id slug] [--profile 2d|3d] [--archetype runner|match3|...]
6
6
  // [--premise "one line"] [--look <slug>] [--force]
7
7
  //
8
- // The template comes from ./template/ in the published package (prepack:
9
- // scripts/pack-template.ts) or ../../templates/game in the engine repository;
10
- // an archetype (a complete small game to start from) from ./archetypes/<name>/
11
- // or ../../templates/archetypes/<name>/.
8
+ // The template comes from ./template/ (the 3D template, templates/game) or
9
+ // ./template-2d/ (the 2D starter, templates/game-2d) in the published
10
+ // package (prepack: scripts/pack-template.ts), or from ../../templates/ in
11
+ // the engine repository; an archetype (a complete small game to start from)
12
+ // from ./archetypes/<name>/ or ../../templates/archetypes/<name>/. The 2D
13
+ // starter is written for --profile 2d, or for a premise that says 2D
14
+ // (platformer, side-scroller, metroidvania, pixel art) without saying 3D.
12
15
  //
13
16
  // Every game gets its look, `assets/looks/<id>.ogt`, named by GameDesc.look
14
17
  // in the entry: it extends the style catalogue's preset given by --look, or
@@ -28,9 +31,16 @@ export const SKIPPED = new Set(["cooked", "dist", "node_modules", "og-out", ".og
28
31
  * Template files stored under another name and renamed in the scaffold: the
29
32
  * template's Git attributes route media through LFS in a game's repository,
30
33
  * but as `.gitattributes` they would do the same in the engine repository,
31
- * which stores the template's media as plain blobs.
34
+ * which stores the template's media as plain blobs; and `.gitignore`, which
35
+ * npm drops from every tarball, so the published package carries it as
36
+ * `gitignore` (scripts/pack-template.ts renames it at pack; the engine
37
+ * repository keeps the dotted name, and a copy taken from there scaffolds
38
+ * the same).
32
39
  */
33
- export const RENAMED: ReadonlyMap<string, string> = new Map([["gitattributes", ".gitattributes"]]);
40
+ export const RENAMED: ReadonlyMap<string, string> = new Map([
41
+ ["gitattributes", ".gitattributes"],
42
+ ["gitignore", ".gitignore"],
43
+ ]);
34
44
 
35
45
  export interface CreateOptions {
36
46
  readonly dir: string;
@@ -39,6 +49,8 @@ export interface CreateOptions {
39
49
  readonly force?: boolean;
40
50
  /** Start from an archetype (`runner`, `match3`, `topdown`, `tower-defense`, `roguelike`, `idle`, `rhythm`, `third-person`: templates/archetypes/README.md) instead of the project template. */
41
51
  readonly archetype?: string;
52
+ /** The template's profile: `2d` writes the 2D starter (templates/game-2d), `3d` the 3D template (templates/game). Unset, a premise that says 2D picks `2d`; else `3d`. Not for an archetype, which has its own. */
53
+ readonly profile?: Profile;
42
54
  /** The template directory; found next to this file when omitted. */
43
55
  readonly template?: string;
44
56
  /** A style catalogue slug the game's look extends (og-taste §12). */
@@ -61,11 +73,22 @@ export interface CreatedLook {
61
73
  readonly chosen: "flag" | "premise" | "template" | "none";
62
74
  }
63
75
 
76
+ /** A project's profile (`project.ogt`'s `profile` line): 2D or 3D. */
77
+ export type Profile = "2d" | "3d";
78
+
79
+ /** The profile the game was written in, and how it was chosen. */
80
+ export interface CreatedProfile {
81
+ readonly value: Profile;
82
+ /** `flag` for --profile, `premise` for a premise that says 2D, `archetype` for an archetype's own, `template` for the 3D template by default. */
83
+ readonly chosen: "flag" | "premise" | "archetype" | "template";
84
+ }
85
+
64
86
  export interface Created {
65
87
  readonly dir: string;
66
88
  readonly name: string;
67
89
  readonly id: string;
68
90
  readonly files: readonly string[];
91
+ readonly profile: CreatedProfile;
69
92
  readonly look: CreatedLook;
70
93
  /** What the game's author should know, such as reference frames a look will move. */
71
94
  readonly notes: readonly string[];
@@ -157,8 +180,30 @@ function title(id: string): string {
157
180
  .join(" ");
158
181
  }
159
182
 
160
- /** The template this copy of the package scaffolds. */
161
- export function templateDir(archetype?: string): string {
183
+ /** Words of a premise that say the game is 2D (platformer, side-scroller, metroidvania, pixel art, sprites, tiles). */
184
+ const TWO_D = new Set(["platformer", "platforming", "side-scroller", "side-scrolling", "sidescroller", "sidescrolling", "scroller", "metroidvania", "pixel", "pixel-art", "pixelart", "sprite", "tilemap", "tile", "8bit", "16bit", "1bit"]);
185
+ const THREE_D = new Set(["third-person", "first-person", "fps", "voxel", "lowpoly", "low-poly"]);
186
+
187
+ /**
188
+ * The profile a premise asks for: `2d` when it uses a 2D word (TWO_D, or
189
+ * `2D` itself) and no 3D word (THREE_D, or `3D`), else null: the template's
190
+ * own, 3D, applies.
191
+ */
192
+ export function premiseProfile(premise: string): Profile | null {
193
+ const asked = new Set(words(premise));
194
+ const says = (w: string) => new RegExp(`(^|[^a-z0-9])${w}($|[^a-z0-9])`, "i").test(premise);
195
+ if (says("3d") || [...THREE_D].some((w) => asked.has(w))) return null;
196
+ return says("2d") || [...TWO_D].some((w) => asked.has(w)) ? "2d" : null;
197
+ }
198
+
199
+ /** The `profile "2d"` line of a project manifest; `3d` when it has none. */
200
+ function profileOf(dir: string): Profile {
201
+ const m = /^profile[ \t]+"(2d|3d)"/m.exec(readFileSync(join(dir, "project.ogt"), "utf8"));
202
+ return m?.[1] === "2d" ? "2d" : "3d";
203
+ }
204
+
205
+ /** The template this copy of the package scaffolds: the archetype's, or the project template of a profile (3D unless `2d`). */
206
+ export function templateDir(archetype?: string, profile: Profile = "3d"): string {
162
207
  const here = dirname(fileURLToPath(import.meta.url));
163
208
  if (archetype !== undefined) {
164
209
  const roots = [join(here, "..", "archetypes"), join(here, "..", "..", "..", "templates", "archetypes")];
@@ -168,10 +213,12 @@ export function templateDir(archetype?: string): string {
168
213
  const known = roots.filter(existsSync).flatMap((r) => readdirSync(r).filter((d) => existsSync(join(r, d, "project.ogt"))));
169
214
  throw new Error(`no archetype '${archetype}': choose one of ${[...new Set(known)].sort().join(", ") || "(none shipped)"}`);
170
215
  }
171
- for (const candidate of [join(here, "..", "template"), join(here, "..", "..", "..", "templates", "game")]) {
216
+ const packed = profile === "2d" ? "template-2d" : "template";
217
+ const source = profile === "2d" ? "game-2d" : "game";
218
+ for (const candidate of [join(here, "..", packed), join(here, "..", "..", "..", "templates", source)]) {
172
219
  if (existsSync(join(candidate, "project.ogt"))) return candidate;
173
220
  }
174
- throw new Error(`no project template next to ${here}: expected ../template (published package) or ../../../templates/game (engine repository)`);
221
+ throw new Error(`no ${profile} project template next to ${here}: expected ../${packed} (published package) or ../../../templates/${source} (engine repository)`);
175
222
  }
176
223
 
177
224
  function ogtString(value: string): string {
@@ -315,8 +362,16 @@ export function create(options: CreateOptions): Created {
315
362
  throw new Error(`${dir} is not empty; pick an empty directory, or pass --force to write the template over it`);
316
363
  }
317
364
  }
365
+ if (options.profile !== undefined && options.archetype !== undefined) {
366
+ throw new Error(`--profile and --archetype together: an archetype has its own profile (${options.archetype}); drop one`);
367
+ }
318
368
  const choice = chooseStyle(options);
319
- const template = options.template ?? templateDir(options.archetype);
369
+ const asked = options.profile ?? (options.premise !== undefined ? premiseProfile(options.premise) : null);
370
+ const template = options.template ?? templateDir(options.archetype, asked ?? "3d");
371
+ const profile: CreatedProfile = {
372
+ value: profileOf(template),
373
+ chosen: options.archetype !== undefined ? "archetype" : options.profile !== undefined ? "flag" : asked !== null ? "premise" : "template",
374
+ };
320
375
  const list = files(template);
321
376
  const written: string[] = [];
322
377
  mkdirSync(dir, { recursive: true });
@@ -335,7 +390,7 @@ export function create(options: CreateOptions): Created {
335
390
  writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
336
391
  }
337
392
  const { look, notes } = writeLook(dir, name, id, choice, written);
338
- return { dir, name, id, files: written, look, notes };
393
+ return { dir, name, id, files: written, profile, look, notes };
339
394
  }
340
395
 
341
396
  /**
@@ -420,12 +475,13 @@ function writeLook(dir: string, name: string, id: string, choice: ReturnType<typ
420
475
  return { look, notes };
421
476
  }
422
477
 
423
- const USAGE = `usage: create [dir] [--name "Name"] [--id slug] [--archetype name] [--premise "one line"] [--look slug] [--force]
478
+ const USAGE = `usage: create [dir] [--name "Name"] [--id slug] [--profile 2d|3d] [--archetype name] [--premise "one line"] [--look slug] [--force]
424
479
 
425
480
  Scaffolds an Origin Engine game into dir (default: ./origin-game).
426
481
  --name the game's display name (default: from the id or the directory)
427
482
  --id the game's id, lowercase-hyphen (default: from the name)
428
- --archetype start from a complete archetype game (runner, match3, topdown, tower-defense, roguelike, idle, rhythm, third-person) instead of the template
483
+ --profile 2d writes the 2D starter (a platformer: sprites, tilemap, 2D physics), 3d the 3D template (default: 2d for a premise that says 2D, platformer, side-scroller, metroidvania or pixel art without saying 3D; else 3d)
484
+ --archetype start from a complete archetype game (runner, match3, topdown, tower-defense, roguelike, idle, rhythm, third-person) instead of the template; it has its own profile
429
485
  --premise the game in one line (genre, mood, setting, audience): its look extends the style catalogue's best match (asked for on a terminal when neither this nor --look is given)
430
486
  --look the style catalogue slug the look extends (og-taste §12), such as anime-cel-3d or 16bit-pixel
431
487
  --no-prompt never ask for the premise
@@ -437,6 +493,7 @@ function main(argv: string[]): number {
437
493
  let id: string | undefined;
438
494
  let force = false;
439
495
  let archetype: string | undefined;
496
+ let profile: Profile | undefined;
440
497
  let premise: string | undefined;
441
498
  let look: string | undefined;
442
499
  let ask = true;
@@ -451,7 +508,11 @@ function main(argv: string[]): number {
451
508
  else if (a === "--id") id = value();
452
509
  else if (a === "--force") force = true;
453
510
  else if (a === "--archetype") archetype = value();
454
- else if (a === "--premise") premise = value();
511
+ else if (a === "--profile") {
512
+ const v = value();
513
+ if (v !== "2d" && v !== "3d") throw new Error(`--profile ${v}: use 2d or 3d. ${USAGE}`);
514
+ profile = v;
515
+ } else if (a === "--premise") premise = value();
455
516
  else if (a === "--look") look = value();
456
517
  else if (a === "--no-prompt") ask = false;
457
518
  else if (a === "-h" || a === "--help") {
@@ -469,13 +530,16 @@ function main(argv: string[]): number {
469
530
  ...(name ? { name } : {}),
470
531
  ...(id ? { id } : {}),
471
532
  ...(archetype ? { archetype } : {}),
533
+ ...(profile ? { profile } : {}),
472
534
  ...(premise ? { premise } : {}),
473
535
  ...(look ? { look } : {}),
474
536
  force,
475
537
  });
476
538
  const shown = relative(process.cwd(), made.dir) || ".";
477
539
  const style = made.look.extends ? `extends ${made.look.extends}${made.look.chosen === "premise" ? " (from the premise)" : made.look.chosen === "flag" ? " (--look)" : ""}` : "extends no preset";
540
+ const how = { flag: " (--profile)", premise: " (from the premise)", archetype: ` (the ${archetype} archetype's)`, template: "" }[made.profile.chosen];
478
541
  console.log(`Created ${made.name} (${made.id}) in ${shown}: ${made.files.length} files.
542
+ Profile: ${made.profile.value}${how}.
479
543
  Look: ${made.look.file}, ${style}; README.md says how to change it.${made.notes.map((n) => `\nNote: ${n}`).join("")}
480
544
 
481
545
  Next:
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@origingame/create-game",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Scaffolds an Origin Engine game from the project template: npm create @origingame/game.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/fran0220/origin-engine.git",
8
+ "url": "git+https://github.com/originai-game/origin-engine.git",
9
9
  "directory": "packages/create"
10
10
  },
11
- "homepage": "https://github.com/fran0220/origin-engine#readme",
11
+ "homepage": "https://github.com/originai-game/origin-engine#readme",
12
12
  "bugs": {
13
- "url": "https://github.com/fran0220/origin-engine/issues"
13
+ "url": "https://github.com/originai-game/origin-engine/issues"
14
14
  },
15
15
  "publishConfig": {
16
16
  "access": "public"
@@ -22,6 +22,7 @@
22
22
  "files": [
23
23
  "bin",
24
24
  "template",
25
+ "template-2d",
25
26
  "archetypes",
26
27
  "looks",
27
28
  "README.md"
@@ -0,0 +1,8 @@
1
+ # og cook output: rebuilt from assets/, never committed.
2
+ cooked/
3
+ # og build output.
4
+ dist/
5
+ # og run and og test output, and og's bundled entry.
6
+ og-out/
7
+ .og/
8
+ node_modules/
@@ -13,6 +13,6 @@
13
13
  "test": "og test ."
14
14
  },
15
15
  "dependencies": {
16
- "@origingame/engine": "0.1.0"
16
+ "@origingame/engine": "0.2.0"
17
17
  }
18
18
  }
@@ -7,7 +7,7 @@ version 1
7
7
  name "Origin Game"
8
8
  id "origin-game"
9
9
  # The engine this game is written against (design §9: upgrades are explicit).
10
- engine "0.1.0"
10
+ engine "0.2.0"
11
11
  entry "src/main.ts"
12
12
  # 2d (orthographic camera, sprites, 2D physics) or 3d.
13
13
  profile "3d"
@@ -0,0 +1,14 @@
1
+ #!/bin/sh
2
+ # Prepares this Game's cloud sandbox snapshot: Origin runs it once per
3
+ # snapshot build, in the checkout, without a terminal, for at most 20 minutes,
4
+ # and saves the result for new sandboxes of the Game. Keep it idempotent; it
5
+ # never receives credentials. Only ignored output is kept: node_modules/ and
6
+ # cooked/ (og cook is incremental, so a new sandbox starts cooked).
7
+ set -eu
8
+ if [ -f bun.lock ]; then bun install --frozen-lockfile; else bun install; fi
9
+ og="${ORIGIN_OG_BIN:-og}"
10
+ if ! command -v "$og" >/dev/null 2>&1; then
11
+ echo "no og on this executor class; the first og run cooks instead"
12
+ exit 0
13
+ fi
14
+ "$og" cook .
@@ -0,0 +1,14 @@
1
+ # Asset licences
2
+
3
+ Nothing in this project is downloaded: the art and sounds are the engine's
4
+ runner archetype's (`templates/archetypes/runner`, drawn and synthesised by
5
+ its `tools/make-assets.py`), and the rest is written by hand.
6
+
7
+ | File | Licence | Origin |
8
+ |---|---|---|
9
+ | `assets/sprites/courier.png`, `assets/sprites/coin.png` and their `.ogt` | CC0 1.0 | self-made: the runner archetype's courier and coin |
10
+ | `assets/tiles/city.png` | CC0 1.0 | self-made: the runner archetype's city tileset |
11
+ | `assets/tiles/city.ogt`, `assets/maps/level.ogt` | CC0 1.0 | self-made, written by hand |
12
+ | `assets/audio/jump.wav`, `assets/audio/coin.wav` | CC0 1.0 | self-made: the runner archetype's synthesised tones |
13
+ | `assets/fonts/ui.ttf` | SIL Open Font License 1.1 (`assets/fonts/OFL.txt`) | Noto Sans SC Regular, subset to Latin-1 by the runner archetype from the project template's `assets/fonts/NotoSansSC-Regular-subset.ttf` |
14
+ | `assets/looks/*.ogt`, `assets/strings/*.ogt`, every other `.ogt` | CC0 1.0 | self-made, written by hand |
@@ -0,0 +1,39 @@
1
+ # The 2D starter
2
+
3
+ What `npm create @origingame/game` writes for a 2D game (`--profile 2d`, or
4
+ a premise that says 2D, platformer, side-scroller, metroidvania or pixel
5
+ art): the smallest whole 2D Origin Engine project. A courier runs and jumps
6
+ the rooftops of one level, takes coins, jumps up through one-way ledges and
7
+ lands on them, loses a life in the pit and clears the level at the far
8
+ wall; Escape (or the HUD's Pause) opens the pause menu.
9
+
10
+ ```sh
11
+ og run . # headless with the probe; og dev . reloads on save
12
+ og test . # tests/smoke.og.ts
13
+ og build . # the play page
14
+ ```
15
+
16
+ ## What it demonstrates, and the skills it exercises
17
+
18
+ | Part | Where | Skill |
19
+ |---|---|---|
20
+ | The project in the 2D profile: an orthographic camera, sprites, 2D physics | `project.ogt`, `start` in `src/main.ts` | og-game §2, §8 |
21
+ | A hand-written tilemap over a tileset: a parallax skyline, roofs that collide, ledges on their own collider layer (`colliderLayers 2`) that the controller makes one-way | `assets/maps/level.ogt`, `assets/tiles/city.ogt` | og-game §8 (the grammar) |
22
+ | A flipbook sheet, its clips numbered in file order and checked against the code | `assets/sprites/courier.ogt`, `CLIP`, `checkClips` | og-game §8 |
23
+ | og.PlatformerController: run, jump (held for the full height), coyote time, the jump buffer, one-way ledges, Down to drop | `Control`, the hero in `start` | og-game §13; og-feel §12 |
24
+ | The map's objects: the spawn, the coins, the goal | `start`, `Pickups` | og-game §8 |
25
+ | Input on the press's tick: keys, a pad, the HUD's touch controls on a phone | `Control`, `Hud` | og-feel §1; og-ui §5 |
26
+ | The UI kit's platformer HUD and pause menu, every word from the string table | `Hud`, `assets/strings/en.ogt` | og-ui §1, §6; og-i18n §1 |
27
+ | A camera that follows with a dead zone and look-ahead | og.Follow2D on the hero | og-feel §8 |
28
+ | The frame's art direction as data: a look extending the 16bit-pixel preset | `assets/looks/origin-game-2d.ogt` (a created game's is `<id>.ogt`) | og-taste §1, §12 |
29
+ | A playtest that asserts on dumps, never on the code | `tests/smoke.og.ts` | og-build §3, §4 |
30
+
31
+ What a game made from it changes first: the art (the courier and the city
32
+ are the runner archetype's, `templates/archetypes/runner/tools/make-assets.py`
33
+ draws them), the level (`assets/maps/level.ogt`, or a Tiled `.tmj` beside
34
+ it, og-game §8), the controller's tunables (og-feel §12) and what the map's
35
+ objects mean. The 2D archetypes (`templates/archetypes/`) are whole games
36
+ to start from instead: a runner, a top-down room, match-3, a roguelike,
37
+ tower defence, an idle game and a rhythm game.
38
+
39
+ Asset licences: `LICENSES.md`.