Add README, more examples and audio imports
This commit is contained in:
parent
a8bfe73321
commit
6405aedaa7
107
README.md
107
README.md
|
|
@ -1,14 +1,117 @@
|
||||||
# TS-Games
|
# TS-Games
|
||||||
|
|
||||||
To install dependencies:
|
Custom framework/build system for simple single-file TypeScript games.
|
||||||
|
|
||||||
|
## Installing dependencies
|
||||||
|
|
||||||
|
- Install bun (https://bun.sh/)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun install
|
bun install
|
||||||
```
|
```
|
||||||
|
|
||||||
To run:
|
## Make a game
|
||||||
|
|
||||||
|
- Create your game folder in [src/games](src/games)
|
||||||
|
- Create `src/games/<yourgame>/index.ts` with default exported function.
|
||||||
|
|
||||||
|
## Running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun start
|
bun start
|
||||||
```
|
```
|
||||||
|
Navigate to `http://localhost:3000` to see the list of your games.
|
||||||
|
Game rebuilds on each reload.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run build <project>
|
||||||
|
```
|
||||||
|
Will create `<project>.html` in `dist` folder.
|
||||||
|
|
||||||
|
Or to select project from list:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Bun ♥
|
||||||
|
- TypeScript
|
||||||
|
- Building into single `.html` file without any dependencies, all assets are inlined as data-urls.
|
||||||
|
- `src/games/<yourgame>/assets/favicon.ico` is used as page icon if present.
|
||||||
|
|
||||||
|
- TSX supported with [Preact](https://preactjs.com/), because it's lightweight.
|
||||||
|
|
||||||
|
- Import images as `HTMLImageElement`
|
||||||
|
- PNG & JPG
|
||||||
|
```typescript
|
||||||
|
import spritesheet from './assets/spritesheet.png';
|
||||||
|
console.log(spritesheet); // <img src="data:..." />
|
||||||
|
```
|
||||||
|
|
||||||
|
- Import audio as `HTMLAudioElement`
|
||||||
|
- WAV, MP3 & OGG
|
||||||
|
```typescript
|
||||||
|
import heal from './assets/heal.ogg';
|
||||||
|
console.log(heal); // <audio src="data:..." />
|
||||||
|
heal.play()
|
||||||
|
```
|
||||||
|
|
||||||
|
- Import css with [LigntningCSS](https://lightningcss.dev/)
|
||||||
|
- Regular CSS
|
||||||
|
```ts
|
||||||
|
import "./assets/styles.css";
|
||||||
|
```
|
||||||
|
|
||||||
|
- CSS modules is supported
|
||||||
|
```tsx
|
||||||
|
import styles from './assets/styles.module.css';
|
||||||
|
console.log(styles.awoo); // G7sddg_awoo
|
||||||
|
|
||||||
|
export default <div className={styles.root}></div>;
|
||||||
|
```
|
||||||
|
|
||||||
|
- Modern CSS features are transpiled
|
||||||
|
- Nested CSS
|
||||||
|
```css
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Vendor prefixed if needed
|
||||||
|
|
||||||
|
- Import fonts (see [example](src/common/assets/vga.font.css))
|
||||||
|
```ts
|
||||||
|
import "./assets/lcd.font.css";
|
||||||
|
```
|
||||||
|
|
||||||
|
- [AssemblyScript](https://www.assemblyscript.org/) support (TypeScript-like language compiled into WebAssembly)
|
||||||
|
- [Example](src/games/playground/awoo.wasm.ts)
|
||||||
|
- Triggered by file name `*.wasm.ts`
|
||||||
|
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
|
- Make sure you have `scp` installed (it most certainly is)
|
||||||
|
- Make `.env` file
|
||||||
|
```bash
|
||||||
|
PUBLISH_LOCATION=ssh.example.com:/var/www/games/
|
||||||
|
PUBLISH_URL=https://example.com/
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run build & publish
|
||||||
|
```bash
|
||||||
|
bun run build <project>
|
||||||
|
```
|
||||||
|
|
||||||
|
Or to select project from list:
|
||||||
|
```bash
|
||||||
|
bun run build
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { plugin, type BunPlugin } from "bun";
|
||||||
|
|
||||||
|
const audioPlugin: BunPlugin = {
|
||||||
|
name: "Audio loader",
|
||||||
|
async setup(build) {
|
||||||
|
build.onLoad({ filter: /\.(wav|mp3|ogg)$/ }, async (args) => {
|
||||||
|
const arrayBuffer = await Bun.file(args.path).arrayBuffer();
|
||||||
|
const ext = args.path.split('.').pop();
|
||||||
|
const buffer = Buffer.from(arrayBuffer);
|
||||||
|
const src = `data:audio/${ext};base64,${buffer.toString('base64')}`;
|
||||||
|
return {
|
||||||
|
contents: `
|
||||||
|
const audio = document.createElement('audio');
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
audio.oncanplay = resolve;
|
||||||
|
audio.onerror = () => reject(audio.error);
|
||||||
|
});
|
||||||
|
audio.src = (${JSON.stringify(src)});
|
||||||
|
|
||||||
|
await promise;
|
||||||
|
|
||||||
|
export default audio;
|
||||||
|
`,
|
||||||
|
loader: 'js',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
plugin(audioPlugin);
|
||||||
|
|
||||||
|
export default audioPlugin;
|
||||||
|
|
@ -10,6 +10,7 @@ const outDir = path.resolve(import.meta.dir, '..', '..', 'dist');
|
||||||
await fs.mkdir(outDir, { recursive: true });
|
await fs.mkdir(outDir, { recursive: true });
|
||||||
|
|
||||||
let game = process.argv[2];
|
let game = process.argv[2];
|
||||||
|
const publish = process.env.PUBLISH_LOCATION;
|
||||||
|
|
||||||
while (!await isGame(game)) {
|
while (!await isGame(game)) {
|
||||||
const answer = await inquirer.prompt([{
|
const answer = await inquirer.prompt([{
|
||||||
|
|
@ -28,7 +29,9 @@ if (!html) {
|
||||||
const filePath = path.resolve(outDir, `${game}.html`);
|
const filePath = path.resolve(outDir, `${game}.html`);
|
||||||
await Bun.write(filePath, html);
|
await Bun.write(filePath, html);
|
||||||
|
|
||||||
const result = await $`scp "${filePath}" "pabloid@games.pafnooty.ru:/var/www/games/${game}.html"`;
|
if (publish) {
|
||||||
if (result.exitCode === 0) {
|
const result = await $`scp "${filePath}" "${publish}${game}.html"`;
|
||||||
console.log(`Build successful: https://games.pafnooty.ru/${game}.html`);
|
if (result.exitCode === 0) {
|
||||||
|
console.log(`Build successful: ${process.env.PUBLISH_URL}${game}.html`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import fontPlugin from './fontPlugin';
|
||||||
import lightningcss from 'bun-lightningcss';
|
import lightningcss from 'bun-lightningcss';
|
||||||
|
|
||||||
import { getGames } from './isGame';
|
import { getGames } from './isGame';
|
||||||
|
import audioPlugin from './audioPlugin';
|
||||||
|
|
||||||
export async function buildHTML(game: string, production = false, portable = false) {
|
export async function buildHTML(game: string, production = false, portable = false) {
|
||||||
const html = await Bun.file(path.resolve(import.meta.dir, '..', 'assets', 'index.html')).text();
|
const html = await Bun.file(path.resolve(import.meta.dir, '..', 'assets', 'index.html')).text();
|
||||||
|
|
@ -22,6 +23,7 @@ export async function buildHTML(game: string, production = false, portable = fal
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
imagePlugin,
|
imagePlugin,
|
||||||
|
audioPlugin,
|
||||||
fontPlugin,
|
fontPlugin,
|
||||||
wasmPlugin({ production, portable }),
|
wasmPlugin({ production, portable }),
|
||||||
lightningcss(),
|
lightningcss(),
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,16 @@ declare module "*.jpg" {
|
||||||
declare module "*.jpeg" {
|
declare module "*.jpeg" {
|
||||||
const image: HTMLImageElement;
|
const image: HTMLImageElement;
|
||||||
export default image;
|
export default image;
|
||||||
|
}
|
||||||
|
declare module "*.wav" {
|
||||||
|
const audio: HTMLAudioElement;
|
||||||
|
export default audio;
|
||||||
|
}
|
||||||
|
declare module "*.mp3" {
|
||||||
|
const audio: HTMLAudioElement;
|
||||||
|
export default audio;
|
||||||
|
}
|
||||||
|
declare module "*.ogg" {
|
||||||
|
const audio: HTMLAudioElement;
|
||||||
|
export default audio;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BrickDisplay, type BrickDisplayImage } from "@common/display";
|
import { BrickDisplay } from "@common/display";
|
||||||
import { isPressed, updateKeys } from "@common/input";
|
import { isPressed, updateKeys } from "@common/input";
|
||||||
|
|
||||||
import spritesheetImage from './assets/spritesheet.png';
|
import spritesheetImage from './assets/spritesheet.png';
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,3 @@
|
||||||
|
export function awoo(a: i32, b: i32): void {
|
||||||
|
console.log((a * b).toString());
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { awoo } from "./awoo.wasm";
|
||||||
|
import { render } from "preact";
|
||||||
|
import attack from './assets/attack.wav';
|
||||||
|
|
||||||
|
export default function main() {
|
||||||
|
awoo(42, 69);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<button onClick={() => attack.play()}>
|
||||||
|
Attack
|
||||||
|
</button>,
|
||||||
|
document.body
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -28,5 +28,6 @@
|
||||||
"@common/*": ["./src/common/*"]
|
"@common/*": ["./src/common/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["./**/*.ts", "./**/*.tsx", "./node_modules/assemblyscript/std/portable/index.d.ts"],
|
"include": ["./**/*.ts", "./**/*.tsx", "./**/*.js", "./**/*.jsx", "./node_modules/assemblyscript/std/portable/index.d.ts"],
|
||||||
|
"exclude": ["./dist/**/*"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue