Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4dbebfc

Browse files
committedMay 10, 2024·
Initial documentation site.
GitOrigin-RevId: 124562564c369aaf5b61c50e9e2d7d8482643b6f
1 parent 8ce93c4 commit 4dbebfc

18 files changed

+3839
-165
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ares/src/generated/*
1212
ares/vite.config.ts.timestamp-*
1313
artemis/prisma/pothos-types.ts
1414
coverage
15+
docs/vocs.config.tsx.timestamp-*
1516
electron/demo
1617
electron/log-output
1718
electron/offline

‎README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<p align="center">
44
<a href="https://athenacrisis.com">
5-
<img alt="Athena Crisis Logo" src="./deimos/public/athena-crisis.svg" style="width: 70%;" />
5+
<img alt="Athena Crisis Logo" src="./docs/content/public/athena-crisis.svg" style="width: 70%;" />
66
</a>
77
</p>
88

@@ -36,7 +36,7 @@ pnpm install && pnpm dev:setup
3636
pnpm dev
3737
```
3838
39-
Visit [localhost:3002](http://localhost:3002/) to see the landing page.
39+
Visit [localhost:3003](http://localhost:3003/) to see the docs page.
4040

4141
## Packages
4242

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Immutable Data Structures
2+
3+
All game related data structures and algorithms in Athena Crisis are "headless" and can run on the client, server, or during build time. Map and game state is represented using [_immutable persistent data structures_](https://roberterdin.github.io/2017/09/immutable-persistent-data-structures). Immutable means that instead of directly changing the game state, any action like moving or attacking a unit returns a new game state object. Persistent refers to reusing all data that doesn't change between two game states. These two concepts together make it easy to keep many game states around, make it fast to check whether changes happened between two states, and is memory efficient.
4+
5+
Imagine a basic game state with a map that is three fields wide and one field high. The game state can be represented with an array, where each field either has a unit or not:
6+
7+
```tsx
8+
const state = [unit, null, null];
9+
```
10+
11+
Many games use an imperative model. When you want to move the unit from one position to another, you might make a change like this:
12+
13+
```tsx
14+
state[2] = state[0];
15+
state[0] = null;
16+
```
17+
18+
This directly modifies the existing state object. It now becomes hard to know what the game state was before, which can cause problems when other operations still think they are operating on a previous version of the game state. It also makes it harder to compare what changed with a state transition.
19+
20+
Let's look at the same example with an immutable model:
21+
22+
```tsx
23+
const state = [unit, null, null];
24+
const newState = [null, null, unit];
25+
```
26+
27+
At the core, instead of mutating the game state, we create a completely new game state object each time with the immutable model. Note that the unit, assuming its an instance of a `Unit` class, did not change. However, when you are moving a unit in Athena Crisis, it has to be marked as "moved". In the imperative version, it might look like this:
28+
29+
```tsx
30+
const state = [unit, null, null];
31+
const unit = state[0];
32+
unit.moved = true;
33+
state[2] = unit;
34+
state[0] = null;
35+
```
36+
37+
The immutable version could look something like this:
38+
39+
```tsx
40+
class Unit {
41+
move() {
42+
return this.copy({
43+
moved: true,
44+
});
45+
}
46+
}
47+
48+
const state = [unit, null, null];
49+
const newState = [null, null, unit.move()];
50+
```
51+
52+
The imperative version is faster and memory efficient. However, if another part of the codebase is holding on to the unit, it might not know that the unit has moved, or it might not expect the unit object to be mutated. This can lead to hard to find bugs, especially when there are many variables and state changes involved. The immutable version is slower and uses more memory, especially when many things change at once. The downsides can be limited by using persistent data structures, which re-use as much data as possible between two game states.
53+
54+
In a real world example, you might be storing unit positions in a [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) data structure which is expensive to copy each time a change is made. The immutable `Map` data structure from [Immutable.js](https://immutable-js.com/), which we released as a standalone package called [`@nkzw/immutable-map`](https://github.com/nkzw-tech/immutable-map), makes use of structral sharing to make copying cheap. It works similar to git commits, where only the changes are stored and the rest is shared between two game states. Due to this, _the immutable model can be more memory efficient and sometimes even faster than the imperative model_.
55+
56+
_These advantages make immutable state models ideal for turn-based strategy games like Athena Crisis._
57+
58+
:::info[Note]
59+
Immutable.js has fallen out of favor in recent years. Its meta-programming and code size slow down app start, and many of its data structures are less relevant today. However, to our knowledge, there is no better and faster alternative of an immutable `Map` data structures in JavaScript. We published our own package that only includes `Map`, and we are welcome to contributions to speed up the package.
60+
:::
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# The `MapData` Class
2+
3+
[`MapData`](https://github.com/nkzw-tech/athena-crisis/blob/main/athena/MapData.tsx)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Core Concepts – Overview
2+
3+
This section dives into the core concepts of the codebase to give you a high-level overview of how Athena Crisis works. The technical walkthroughs primarily cover these three top level folders in the repository:
4+
5+
- [`athena`](https://github.com/nkzw-tech/athena-crisis/tree/main/athena) → Data structures and algorithms for manipulating _map_ state (_client/server_).
6+
- [`apollo`](https://github.com/nkzw-tech/athena-crisis/tree/main/apollo) → Data structures and algorithms for manipulating _game_ state (_client/server_).
7+
- [`hera`](https://github.com/nkzw-tech/athena-crisis/tree/main/hera) → Game engine and rendering (_client_).
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Getting Started
2+
3+
Athena Crisis is a modern retro turn-based strategy game developed by [Nakazawa Tech](https://nkzw.tech) and published by [Null](https://null.com). The source code of Athena Crisis is licensed under the [MIT License](https://github.com/nkzw-tech/athena-crisis/blob/main/LICENSE.md) and can be used to improve Athena Crisis, build additional tools, study game development with JavaScript or create entirely new turn-based strategy games.
4+
5+
This documentation website is aimed at explaining the core architecture and provides playgrounds to try out various parts of the codebase. To get started, you can clone the codebase using `git`:
6+
7+
```bash
8+
git clone git://github.com/nkzw-tech/athena-crisis.git
9+
```
10+
11+
Athena Crisis requires [Node.js](https://nodejs.org/en/download/package-manager) and the latest major version of [`pnpm`](https://pnpm.io/installation). After installing the latest versions, you can get started quickly with these commands:
12+
13+
```bash
14+
pnpm install && pnpm dev:setup
15+
pnpm dev
16+
```
17+
18+
The above commands set up the repository. After they complete, you can visit [localhost:3003](http://localhost:3003/) to run the local version of this documentation website.
19+
20+
If you prefer video content, check out [How NOT to Build a Video Game](https://www.youtube.com/watch?v=m8SmXOTM8Ec) to get an overview of the tech behind Athena Crisis. If you have questions, feel free to [join us on Discord](https://discord.gg/2VBCCep7Fk).

‎docs/content/pages/index.mdx

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
layout: landing
3+
---
4+
5+
import { HomePage } from 'vocs/components';
6+
7+
<HomePage.Root>
8+
<img alt="Athena Crisis logo" src="/athena-crisis.svg" />
9+
<HomePage.Tagline>Open Source Docs & Playground</HomePage.Tagline>
10+
<HomePage.Description>
11+
This is a description of my documentation website.
12+
</HomePage.Description>
13+
<HomePage.Buttons>
14+
<HomePage.Button href="/getting-started" variant="accent">
15+
Getting Started
16+
</HomePage.Button>
17+
<HomePage.Button href="https://github.com/nkzw-tech/athena-crisis">
18+
GitHub
19+
</HomePage.Button>
20+
</HomePage.Buttons>
21+
</HomePage.Root>

‎docs/content/public/FiraCode.woff2

101 KB
Binary file not shown.
3.09 KB
Loading
File renamed without changes.

‎docs/content/public/favicon.ico

510 Bytes
Binary file not shown.

‎docs/content/public/favicon.png

306 Bytes
Loading

‎docs/content/styles.css

Whitespace-only changes.

‎docs/package.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@deities/docs",
3+
"version": "0.0.1",
4+
"private": true,
5+
"description": "Athena Crisis Open Source Docs & Playground",
6+
"repository": {
7+
"type": "git",
8+
"url": "git://github.com/nkzw-tech/athena-crisis.git"
9+
},
10+
"author": "Christoph Nakazawa <christoph.pojer@gmail.com>",
11+
"type": "module",
12+
"scripts": {
13+
"build": "vocs build",
14+
"dev": "vocs dev --port 3003",
15+
"preview": "vocs preview"
16+
},
17+
"dependencies": {
18+
"@types/react": "^18.3.1",
19+
"dunkel-theme": "^1.7.1",
20+
"licht-theme": "^1.7.1",
21+
"react": "19.0.0-canary-fd0da3eef-20240404",
22+
"react-dom": "19.0.0-canary-fd0da3eef-20240404",
23+
"vocs": "^1.0.0-alpha.49"
24+
}
25+
}

‎docs/vocs.config.tsx

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { readFileSync } from 'node:fs';
2+
import React from 'react';
3+
import { defineConfig } from 'vocs';
4+
5+
const Licht = JSON.parse(
6+
readFileSync('./node_modules/licht-theme/licht.json', 'utf8'),
7+
);
8+
const Dunkel = JSON.parse(
9+
readFileSync('./node_modules/dunkel-theme/dunkel.json', 'utf8'),
10+
);
11+
12+
export default defineConfig({
13+
basePath: '/open-source',
14+
description: 'Open Source Docs & Playground',
15+
editLink: {
16+
pattern:
17+
'https://github.com/nkzw-tech/athena-crisis/tree/main/docs/content/pages/:path',
18+
text: 'Edit on GitHub',
19+
},
20+
font: {
21+
mono: {
22+
google: 'Fira Code',
23+
},
24+
},
25+
head: (
26+
<>
27+
<link href="/apple-touch-icon.png" rel="apple-touch-icon" />
28+
</>
29+
),
30+
iconUrl: '/favicon.png',
31+
markdown: {
32+
code: {
33+
themes: {
34+
dark: Dunkel,
35+
light: Licht,
36+
},
37+
},
38+
},
39+
ogImageUrl:
40+
'https://vocs.dev/api/og?logo=%logo&title=%title&description=%description',
41+
rootDir: './content',
42+
sidebar: [
43+
{
44+
link: '/getting-started',
45+
text: 'Getting Started',
46+
},
47+
{
48+
items: [
49+
{
50+
link: '/core-concepts/overview',
51+
text: 'Overview',
52+
},
53+
{
54+
link: '/core-concepts/immutable-data-structures',
55+
text: 'Immutable Data Structures',
56+
},
57+
{
58+
link: '/core-concepts/map-data',
59+
text: 'MapData ',
60+
},
61+
],
62+
text: 'Core Concepts',
63+
},
64+
],
65+
socials: [
66+
{
67+
icon: 'github',
68+
link: 'https://github.com/nkzw-tech/athena-crisis',
69+
},
70+
{
71+
icon: 'discord',
72+
link: 'https://discord.gg/2VBCCep7Fk',
73+
},
74+
{
75+
icon: 'x',
76+
link: 'https://twitter.com/TheAthenaCrisis',
77+
},
78+
],
79+
theme: {
80+
accentColor: '#c3217f',
81+
},
82+
title: 'Athena Crisis',
83+
});

‎package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"repository": {
66
"type": "git",
7-
"url": "git://github.com/nkzw-tech/athena-crisis-universe.git"
7+
"url": "git://github.com/nkzw-tech/athena-crisis.git"
88
},
99
"author": "Christoph Nakazawa <christoph.pojer@gmail.com>",
1010
"type": "module",
@@ -17,10 +17,11 @@
1717
"build:docker-server": "RELEASE_ID=$(git rev-parse --short HEAD) docker buildx build --load -f Dockerfile --platform=linux/amd64 --tag athena-crisis --build-arg RELEASE_ID=$RELEASE_ID .",
1818
"build:offline": "rm -rf ./dist/offline && pnpm vite build --outDir ../dist/offline -c ./offline/vite.config.ts ./offline",
1919
"build:server": "./build-server",
20-
"build:splash": "rm -rf ./dist/deimos && pnpm vite build --outDir ../dist/deimos -c ./deimos/vite.config.ts ./deimos/",
20+
"build:splash": "rm -rf ./dist/deimos && pnpm vite build --outDir ../dist/deimos -c ./deimos/vite.config.ts ./deimos/ && pnpm build:docs",
21+
"build:docs": "cd docs && pnpm build --outDir ../../dist/deimos/open-source",
2122
"build:steam-i18n": "rm -rf ./dist/steami18n && node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./ares/scripts/translateStorepage.js",
2223
"codegen": "node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./codegen/generate-all.tsx",
23-
"dev": "node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./deimos/deimos.tsx",
24+
"dev": "cd docs && pnpm dev",
2425
"dev:setup": "pnpm prisma generate && pnpm relay && pnpm codegen && pnpm fbt",
2526
"dev:update-deps": "rm -rf pnpm-lock.yaml node_modules/ **/node_modules && pnpm dev:setup",
2627
"disable-canvas": "jq '.pnpm.neverBuiltDependencies = [\"canvas\"]' package.json > package-canvas.json && mv package-canvas.json package.json && git restore pnpm-lock.yaml",

‎pnpm-lock.yaml

+3,612-160
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎pnpm-workspace.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ packages:
77
- 'codegen'
88
- 'deimos'
99
- 'dionysus'
10+
- 'docs'
1011
- 'eslint-plugin'
1112
- 'fixtures'
1213
- 'hephaestus'

0 commit comments

Comments
 (0)
Please sign in to comment.