create-spud 0.0.1 → 0.1.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/example/demo.html CHANGED
@@ -6,6 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>game_name</title>
8
8
  <style>
9
+ /* fonts_face_css */
9
10
  canvas {
10
11
  position: fixed;
11
12
  inset: 0;
@@ -6,6 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>game_name</title>
8
8
  <style>
9
+ /* fonts_face_css */
9
10
  canvas {
10
11
  position: fixed;
11
12
  inset: 0;
package/example/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # game_name
2
2
 
3
- # Getting started
3
+ ## Getting started
4
4
 
5
5
  Useful scripts:
6
6
 
@@ -24,14 +24,15 @@ bun run dev:demo
24
24
  bun run build
25
25
  ```
26
26
 
27
- # Resources:
27
+ ## Resources:
28
28
 
29
29
  - **Game assets**
30
30
  - [itch.io game assets](https://itch.io/game-assets)
31
31
 
32
32
  - **Audio**
33
- - [sfxr.me sfx generator](https://pro.sfxr.me/)
33
+ - [sfxr.me sfx generator](https://pro.sfxr.me/) and [bfxr](https://www.bfxr.net/)
34
34
  - [OpenGameArt cc0 sound effects](https://opengameart.org/art-search-advanced?keys=&title=&field_art_tags_tid_op=or&field_art_tags_tid=&name=&field_art_type_tid%5B%5D=13&field_art_licenses_tid%5B%5D=4)
35
+ - [Free sfx](https://www.freesfx.co.uk/)
35
36
 
36
37
  - **Animation**
37
38
  - [easings.net](https://easings.net/)
@@ -39,10 +40,12 @@ bun run build
39
40
  - **Sprites & pixel art**
40
41
  - [Aseprite](https://www.aseprite.org/)
41
42
  - [Pixel planet generator (itch.io)](https://deep-fold.itch.io/pixel-planet-generator)
43
+ - [Paint of Persia](https://dunin.itch.io/ptop)
42
44
 
43
45
  - **Fonts**
44
46
  - [Google Fonts](https://fonts.google.com/)
45
47
  - [Font Squirrel](https://www.fontsquirrel.com/)
48
+ - [Font Library](https://fontlibrary.org/)
46
49
 
47
50
  - **Documentation for dev tools & APIs used in this project**
48
51
  - [Vite docs](https://vite.dev/)
@@ -13,7 +13,6 @@ const canvas = document.createElement("canvas");
13
13
  document.body.appendChild(canvas);
14
14
 
15
15
  const ctx = canvas.getContext("2d", { alpha: false })!;
16
- /* pixel_art_image_smoothing */
17
16
 
18
17
  let lastFrameTime = 0;
19
18
  let timeToProcessPhysics = 0;
@@ -21,17 +21,12 @@ export function draw(state: State, ctx: CanvasRenderingContext2D) {
21
21
  y: height / 2,
22
22
  };
23
23
 
24
+ /* pixel_art_image_smoothing */
25
+
24
26
  // clear out the background
25
27
  ctx.fillStyle = "#0b0d1a";
26
28
  ctx.fillRect(0, 0, width, height);
27
29
 
28
- // write some text
29
- ctx.fillStyle = "white";
30
- ctx.textAlign = "center";
31
- ctx.textBaseline = "middle";
32
- ctx.font = "32px sans-serif";
33
- ctx.fillText("hello, gamer", center.x, center.y);
34
-
35
30
  // draw an orbiting circle
36
31
  const moon = {
37
32
  radius: 30,
@@ -44,4 +39,11 @@ export function draw(state: State, ctx: CanvasRenderingContext2D) {
44
39
  },
45
40
  };
46
41
  /* moon_sprite_draw */
42
+
43
+ // write some text
44
+ ctx.fillStyle = "white";
45
+ ctx.textAlign = "center";
46
+ ctx.textBaseline = "middle";
47
+ /* fonts_ctx_font */
48
+ ctx.fillText("hello, gamer", center.x, center.y);
47
49
  }
@@ -16,7 +16,6 @@ const canvas = document.createElement("canvas");
16
16
  document.body.appendChild(canvas);
17
17
 
18
18
  const ctx = canvas.getContext("2d", { alpha: false })!;
19
- /* pixel_art_image_smoothing */
20
19
 
21
20
  let lastFrameTime = 0;
22
21
  let timeToProcessPhysics = 0;
@@ -30,12 +30,13 @@ export function drawSprite(
30
30
  frameIndex: number,
31
31
  x: number,
32
32
  y: number,
33
+ scale = 1,
33
34
  ) {
34
35
  const frame = frameIndex % sheet.frameCount;
35
36
  const sourceX = frame * sheet.frameWidthPx;
36
37
  const sourceY = 0;
37
- const drawWidthPx = sheet.frameWidthPx;
38
- const drawHeightPx = sheet.frameHeightPx;
38
+ const drawWidthPx = sheet.frameWidthPx * scale;
39
+ const drawHeightPx = sheet.frameHeightPx * scale;
39
40
 
40
41
  // see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
41
42
  ctx.drawImage(
package/index.ts CHANGED
@@ -7,7 +7,12 @@ import kebabcase from "lodash.kebabcase";
7
7
 
8
8
  intro("It's spud time.");
9
9
 
10
- const Feature = { Audio: "Audio", PixelArt: "PixelArt" } as const;
10
+ const Feature = {
11
+ Audio: "Audio",
12
+ Fonts: "Fonts",
13
+ PixelArt: "PixelArt",
14
+ } as const;
15
+
11
16
  type Feature = (typeof Feature)[keyof typeof Feature];
12
17
 
13
18
  const { rawGameName, features, shouldContinue } = await group(
@@ -23,10 +28,11 @@ const { rawGameName, features, shouldContinue } = await group(
23
28
  features: () =>
24
29
  multiselect({
25
30
  message: "Features",
26
- initialValues: [Feature.Audio],
31
+ initialValues: [],
27
32
  required: false,
28
33
  options: [
29
34
  { label: "Audio", value: Feature.Audio },
35
+ { label: "Fonts", value: Feature.Fonts },
30
36
  { label: "Pixel art", value: Feature.PixelArt },
31
37
  ],
32
38
  }),
@@ -91,6 +97,8 @@ async function copyDir(
91
97
  if (entry.isDirectory()) {
92
98
  if (entry.name === "node_modules" || entry.name === "dist") continue;
93
99
  if (entry.name === "audio" && !replacements.features.includes(Feature.Audio)) continue;
100
+ if (entry.name === "fonts" && !replacements.features.includes(Feature.Fonts)) continue;
101
+ if (entry.name === "images" && !replacements.features.includes(Feature.PixelArt)) continue;
94
102
  await copyDir(sourcePath, destPath, replacements);
95
103
  continue;
96
104
  }
@@ -123,9 +131,9 @@ async function copyDir(
123
131
  replacements.features.includes(Feature.PixelArt) ? "image-rendering: pixelated;\n" : "",
124
132
  )
125
133
  .replaceAll(
126
- "/* pixel_art_image_smoothing */\n",
134
+ " /* pixel_art_image_smoothing */\n",
127
135
  replacements.features.includes(Feature.PixelArt)
128
- ? "ctx.imageSmoothingEnabled = false;\n"
136
+ ? " // ensure sharp edges for scaled pixel art\n ctx.imageSmoothingEnabled = false;\n"
129
137
  : "",
130
138
  )
131
139
  .replaceAll(
@@ -138,6 +146,18 @@ async function copyDir(
138
146
  "/* audio_import */\n",
139
147
  replacements.features.includes(Feature.Audio) ? 'import { sfx } from "./audio";\n' : "",
140
148
  )
149
+ .replaceAll(
150
+ " /* fonts_face_css */\n",
151
+ replacements.features.includes(Feature.Fonts)
152
+ ? ` @font-face {
153
+ font-family: 'Atari';
154
+ font-display: block;
155
+ src: url('/src/assets/fonts/atari.ttf') format('truetype');
156
+ }
157
+
158
+ `
159
+ : "",
160
+ )
141
161
  .replaceAll(
142
162
  " /* moon_sprite_draw */\n",
143
163
  replacements.features.includes(Feature.PixelArt)
@@ -158,6 +178,12 @@ async function copyDir(
158
178
  });
159
179
  `
160
180
  : " /* handle inputs and update state */\n",
181
+ )
182
+ .replaceAll(
183
+ "/* fonts_ctx_font */",
184
+ replacements.features.includes(Feature.Fonts)
185
+ ? 'ctx.font = "48px Atari";'
186
+ : 'ctx.font = "48px sans-serif";',
161
187
  );
162
188
  await Bun.write(destPath, replaced);
163
189
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-spud",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
4
  "bin": {
5
5
  "create-spud": "./index.ts"
6
6
  },
package/readme.md CHANGED
@@ -8,17 +8,32 @@ The quickest way to set up and scaffold a [spud](https://spud.gg) game.
8
8
  bun create spud
9
9
  ```
10
10
 
11
+ ![demo](demo.svg)
12
+
11
13
  ## What gets created
12
14
 
13
15
  - A new folder named after your game
14
- - A ready-to-run spud game project based on the `example/` template
16
+ - A ready-to-run minimal spud game project
17
+
18
+ ## Automatically set up for you
19
+
20
+ - A working [Vite](https://vite.dev) + [TypeScript](https://www.typescriptlang.org) project with [hot module replacement](https://vite.dev/guide/features#hot-module-replacement) (no config needed)
21
+ - Canvas setup with [DPI-aware scaling](https://web.dev/articles/canvas-hidipi)
22
+ - Fixed‑timestep update loop + variable-rate render loop ready to edit
23
+ - Static asset import handling through [Vite](https://vite.dev/guide/assets#importing-asset-as-url) and [image optimization](https://github.com/FatehAK/vite-plugin-image-optimizer)
24
+ - `index.html` and `demo.html` entry points with scripts ready to run
25
+ - _(Demo mode is a non-interactive gameplay example, providing your potential players a preview into your actual game. Spud favors realistic self-playing demos over pre-recorded trailers.)_
26
+ - Gamepad integration with the [spud API (npm)](https://www.npmjs.com/package/@spud.gg/api)
27
+ - Optional:
28
+ - Audio examples (low-latency [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Using_Web_Audio_API) sfx and [streaming background music](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement)) with [autoplay best practices](https://developer.chrome.com/blog/web-audio-autoplay) for web games.
29
+ - Pixel‑art mode (example sprite sheet, image smoothing disabled)
15
30
 
16
31
  ## Requirements
17
32
 
18
33
  - [Bun](https://bun.com/) (runtime + package manager)
19
34
 
20
35
  <details>
21
- <summary><strong>Bun installation guide</strong></summary>
36
+ <summary><strong>Installation guide</strong></summary>
22
37
 
23
38
  1. Install Bun ([docs](https://bun.com/docs/installation)):
24
39
 
@@ -33,3 +48,8 @@ curl -fsSL https://bun.sh/install | bash
33
48
  ## Notes
34
49
 
35
50
  - This CLI is Bun-only. If you try to run it with Node (`npx create spud`, for example), that won't work.
51
+
52
+ <!--
53
+ TODO
54
+ - add hmr hints for Vite to cleanup / reinit the raf loops and keep game state reloadable.
55
+ -->