Fixed content loading issue
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 36m50s

This commit is contained in:
thepaperpilot 2024-06-18 02:32:30 -05:00
parent 994f1a11f9
commit 14a570c17b
69 changed files with 586 additions and 121 deletions

2
Garden

@ -1 +1 @@
Subproject commit 49fc0dbf27573e378d7295b87936e324cb82b17b
Subproject commit 842bf5c6f540a6e7dc80d2bdab7ed4fee52262a3

View file

@ -1,5 +1,6 @@
const fs = require("fs");
const path = require("path");
const wordCounting = require("word-counting");
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);
@ -22,6 +23,16 @@ function toSlug(string) {
return string.toLowerCase().replaceAll(' ', '-');
}
function moveImportStatementUp(filePath, times = 1) {
let data = fs.readFileSync(filePath).toString();
const fd = fs.openSync(filePath, "w+");
for (let i = 0; i < times; i++) {
data = data.replace(/'\.\.\//g, '\'');
}
fs.writeSync(fd, data);
fs.closeSync(fd);
}
(async () => {
const blockRefs = {};
const blockLinks = {};
@ -93,10 +104,14 @@ function toSlug(string) {
});
pageLinks["NOW"] = "/now/index";
await walk("./garden-output/logseq-pages", (dir, file, resolve) => {
await walk("./garden-output/logseq-pages", async (dir, file, resolve) => {
const filePath = path.resolve(dir, file);
let data = fs.readFileSync(filePath).toString();
// Count word counts with a special set of transformations that should make it more accurate
const strippedData = data.replace(/---\n[\S\s]*\n---/gm, '').replaceAll(/.*::.*/g, '').replaceAll(/\[([^\]]*)\]\(.*\)/g, '$1');
const wc = wordCounting(strippedData).wordsCount;
// Replace youtube embeds
data = data.replaceAll(
/{{video https:\/\/(?:www\.)?youtube\.com\/watch\?v=(.*)}}/g,
@ -132,6 +147,10 @@ function toSlug(string) {
data = data.replaceAll(
/logseq:\/\/graph\/Garden\?page=([^\)]*)/g,
(_, page) => `${pageLinks[page.replaceAll('%20', ' ')]})`);
// Wrap images
data = data.replaceAll(
/!\[([^\]]*)\]\(([^\)]*)\)/g,
(_, title, src) => `<div class="img-container"><img src="${src}" title="${title}"/></div>`)
// Add tags and references
const title = path.basename(file, ".md");
if (title in tagged) {
@ -152,11 +171,11 @@ function toSlug(string) {
}
// Fix links to /now
data = data.replace('NOW', '/now')
// Add title to the top
data = data.replaceAll('___', '/');
// Add header to the top
const relPath = path.relative("./garden-output/logseq-pages", path.resolve(...filePath.split("___"))).replaceAll(/%3F/gi, '').replace('what-is-content-', 'what-is-content').replace('.md', '/index.md');
data = data.replaceAll(
/---\n\n/gm,
`prev: false\nnext: false\n---\n# ${data.match(/title: "(.+)"/)[1]}\n\n`);
`prev: false\nnext: false\n---\n<script setup>\nimport { data } from '${path.relative(path.resolve("site", relPath), path.resolve("site", "git.data.ts")).replaceAll('\\', '/')}';\nimport { useData } from 'vitepress';\nconst pageData = useData();\n</script>\n<h1 class="p-name">${data.match(/title: "(.+)"/)[1]}</h1>\n<p>${wc} words, ~${Math.round(wc / 183)} minute read. <span v-html="data[\`site/\${pageData.page.value.relativePath}\`]" /></p>\n<hr/>\n\n`);
const fd = fs.openSync(filePath, "w+");
fs.writeSync(fd, data);
@ -183,6 +202,7 @@ function toSlug(string) {
// Copy the guide-to-incrementals pages to the old locations so links don't break
fs.mkdirSync('./site/guide-to-incrementals');
fs.copyFileSync('./site/garden/guide-to-incrementals/index.md', './site/guide-to-incrementals/index.md');
moveImportStatementUp('./site/guide-to-incrementals/index.md');
fs.mkdirSync('./site/guide-to-incrementals/design');
fs.mkdirSync('./site/guide-to-incrementals/design/criticism');
fs.copyFileSync('./site/garden/guide-to-incrementals/navigating-criticism/index.md', './site/guide-to-incrementals/design/criticism/index.md');
@ -201,6 +221,7 @@ function toSlug(string) {
fs.mkdirSync('./site/now');
fs.renameSync('./site/garden/now/index.md', './site/now/index.md');
moveImportStatementUp('./site/now/index.md');
// Build changelog
fs.mkdirSync("./site/changelog");

View file

@ -6,9 +6,6 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
const fs = require("fs");
const path = require("path");
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);
const filePath = path.resolve("./Garden/logseq/config.edn");
const data = fs.readFileSync(filePath).toString();
let favorites = [];
@ -16,13 +13,10 @@ for (const match of data.matchAll(/:favorites \["([^\]]+)"\]/g)) {
favorites = match[1].split("\" \"").map(page => ({ text: page, link: `/garden/${page.toLowerCase().replaceAll(' ', '-')}` }));
}
module.exports = {
export default {
lang: "en-US",
title: 'The Paper Pilot',
description: 'The Paper Pilot\'s Digital Garden',
// Solves content sometimes not updating correctly when navigating between links,
// but at the cost of local search, the "on this page" section, etc.
// mpa: true,
appearance: false,
vite: {
ssr: {
@ -47,18 +41,6 @@ module.exports = {
],
lastUpdated: false,
cleanUrls: 'with-subfolders',
async transformHtml(code, id, context) {
if (context.page.startsWith("garden") && fs.existsSync("site/" + context.page)) {
const wc = wordCounting(code, { isHtml: true }).wordsCount;
const pageStart = code.indexOf("</h1>");
const firstCommit = (await exec(`git log -n 1 --diff-filter=A --format="<a href='https://code.incremental.social/thepaperpilot/pages/commit/%H' title='%ad'><time class='dt-published' datetime='%ad'>%ar</time></a>" site/${context.page}`)).stdout;
const lastCommit = (await exec(`git log -n 1 --diff-filter=M --format="<a href='https://code.incremental.social/thepaperpilot/pages/commit/%H' title='%ad'><time class='dt-updated' datetime='%ad'>%ar</time></a>" site/${context.page}`)).stdout;
const header = code.slice(0, pageStart < 0 ? 0 : pageStart + 5).replace('<h1 ', '<article class="h-entry"><h1 class="p-name" ');
code = header + `<p>${wc} words, ~${Math.round(wc / 183)} minute read. Planted ${firstCommit}.${lastCommit ? ` Last tended to ${lastCommit}.` : ''}</p><hr/><div class="e-content">` + code.slice(pageStart + 5).replace('</main>', '</div></article></main>');
code = code.replaceAll(/<img[^<>]*<\/img>|<img[^<>]*>(?!<\/img)/g, text => `<div class="img-container">${text}</div>`);
}
return code;
},
themeConfig: {
search: {
provider: 'local',
@ -90,5 +72,10 @@ module.exports = {
{ text: "/now", link: "/now" },
{ text: "Changelog", link: "/changelog" }
]
},
contentProps: {
class: {
"h-entry": true
}
}
}

View file

@ -409,6 +409,7 @@ a.title {
width: var(--vp-sidebar-width) !important;
margin-left: max(-15px, calc((100% - (var(--vp-layout-max-width) - 60px)) / 2)) !important;
max-height: 40vh;
transition-duration: 0s !important;
}
.VPLocalNavOutlineDropdown {
@ -427,6 +428,7 @@ a.title {
padding: 0 !important;
margin-left: max(-15px, calc((100% - (var(--vp-layout-max-width) - 60px)) / 2)) !important;
max-height: 40vh;
overflow-y: auto;
}
.VPDoc .aside-container {
@ -560,8 +562,7 @@ hr {
}
table {
margin: 0 !important;
margin-top: 30px !important;
margin: 30px 0 !important;
}
#app .vp-doc tr {

View file

@ -1,4 +1,4 @@
import DefaultTheme from 'vitepress/theme';
import DefaultTheme from 'vitepress/theme-without-fonts';
import Layout from './Layout.vue';
export default {

View file

@ -6,7 +6,14 @@ title: "ActivityPub"
prev: false
next: false
---
# ActivityPub
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">ActivityPub</h1>
<p>8 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Fediverse](/garden/fediverse/index.md)

View file

@ -6,7 +6,14 @@ title: "Advent Incremental"
prev: false
next: false
---
# Advent Incremental
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Advent Incremental</h1>
<p>104 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [My Projects](/garden/my-projects/index.md), [Profectus](/garden/profectus/index.md)

View file

@ -5,7 +5,14 @@ title: "Artificial Intelligence"
prev: false
next: false
---
# Artificial Intelligence
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Artificial Intelligence</h1>
<p>101 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Command Palettes](/garden/command-palettes/index.md)

View file

@ -7,7 +7,14 @@ title: "ATProto"
prev: false
next: false
---
# ATProto
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">ATProto</h1>
<p>31 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Fediverse](/garden/fediverse/index.md)

View file

@ -6,7 +6,14 @@ title: "Babble Buds"
prev: false
next: false
---
# Babble Buds
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Babble Buds</h1>
<p>113 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [My Projects](/garden/my-projects/index.md)

View file

@ -6,7 +6,14 @@ title: "Capture the Citadel"
prev: false
next: false
---
# Capture the Citadel
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Capture the Citadel</h1>
<p>39 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [My Projects](/garden/my-projects/index.md)
@ -14,4 +21,4 @@ A 3D VR re-envisioning of a Slay the Spire-style game by Anthony Lawn and Grant
For more details, visit [Grant's page on the game](https://grantcbarbee.github.io/conquer-the-citadel.html).
![screenshot.png](/garden/screenshot_1717381273245_0.png)
<div class="img-container"><img src="/garden/screenshot_1717381273245_0.png" title="screenshot.png"/></div>

View file

@ -5,7 +5,14 @@ title: "Chat Glue"
prev: false
next: false
---
# Chat Glue
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Chat Glue</h1>
<p>23 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Commune](/garden/commune/index.md), [The Small Web](/garden/the-small-web/index.md)

View file

@ -5,7 +5,14 @@ title: "Chronological"
prev: false
next: false
---
# Chronological
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Chronological</h1>
<p>73 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Digital Gardens](/garden/digital-gardens/index.md), [Freeform vs Chronological Dichotomy](/garden/freeform-vs-chronological-dichotomy/index.md), [The Small Web](/garden/the-small-web/index.md)

View file

@ -5,7 +5,14 @@ title: "Cinny"
prev: false
next: false
---
# Cinny
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Cinny</h1>
<p>3 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Incremental Social](/garden/incremental-social/index.md)

View file

@ -5,7 +5,14 @@ title: "Command Palettes"
prev: false
next: false
---
# Command Palettes
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Command Palettes</h1>
<p>117 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
Command palettes are a design pattern where apps expose functionality through a search bar

View file

@ -5,7 +5,14 @@ title: "Commune"
prev: false
next: false
---
# Commune
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Commune</h1>
<p>144 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Federated Identity](/garden/federated-identity/index.md), [Fedi v2](/garden/fedi-v2/index.md), [/now](/now/index), [Webrings](/garden/webrings/index.md), [Weird](/garden/weird/index.md)

View file

@ -5,7 +5,14 @@ title: "Davey Wreden"
prev: false
next: false
---
# Davey Wreden
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Davey Wreden</h1>
<p>37 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Ivy Road](/garden/ivy-road/index.md), [The Beginner's Guide](/garden/the-beginner-s-guide/index.md)

View file

@ -6,7 +6,14 @@ title: "Decentralized"
prev: false
next: false
---
# Decentralized
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Decentralized</h1>
<p>80 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Commune](/garden/commune/index.md), [Fedi v2](/garden/fedi-v2/index.md), [Matrix](/garden/matrix/index.md), [Social Media](/garden/social-media/index.md)

View file

@ -6,7 +6,14 @@ title: "Dice Armor"
prev: false
next: false
---
# Dice Armor
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Dice Armor</h1>
<p>963 words, ~5 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Babble Buds](/garden/babble-buds/index.md)
@ -18,39 +25,39 @@ Dice Armor is a game that started development as a semester-long project by a te
The build available here was created for showing off at the end of the semester, and as such has some buttons present to make the game easier to skip parts of the game to see all the content: You start with all the dice in the game already in the shop, there's a button to give yourself free money to buy these dice with, and in the duel, there are buttons to force a win or a loss, which can be used to skip the tutorial (not recommended for first-time players).
![Tutorial](/garden/da2_1717378483173_0.png)
<div class="img-container"><img src="/garden/da2_1717378483173_0.png" title="Tutorial"/></div>
Dice Armor is a dice dueling game. Players can use abilities, flip dice, and attack each other to win in a dice game that puts chance into the hands of the players. This is what the dueling scene looks like, with a tutorial cutscene happening on top to guide the player through the basics. Also, all the dice are constructed dynamically, using quaternion math to figure out the placement of each component relative to the face it is going on. The die in the middle has one of the player' and opponents' portraits on each of its sides.
![Editors](/garden/editors_1717378509527_0.png)
<div class="img-container"><img src="/garden/editors_1717378509527_0.png" title="Editors"/></div>
For many of the objects I've created, I've made scriptable objects so that game designers can add and modify them easily. Additionally, I would create custom inspectors for the objects to help make them as easy to understand and edit as possible. The opponent's artificial intelligence is made up of many strategies, in a prioritized list. When it is the opponents' turn they go through each strategy and check if they can be run, and if so then the opponent performs the strategy and starts back over at the top of the list of strategies. The + sign under the list of strategies opens an organized dropdown of all the various strategies.
![Simulator](/garden/simulator_1717378525890_0.jpg)
<div class="img-container"><img src="/garden/simulator_1717378525890_0.jpg" title="Simulator"/></div>
In addition to custom inspector code, I've created new tools for the editor for our game designers to use. This is a duel simulator that will take two opponents and simulate an arbitrary number of duels between them, and output the results and summarize them for you, much much quicker than manually going through the duels, even with an absurdly high timeScale. This will become incredibly useful in making balance changes and testing new dice against existing sets. This is a screenshot of it in edit mode, but in play mode it removes the "Dueling Managers" field and will use whatever the current duel balance settings are, allowing for the GDs to test freely in play mode without worrying about undoing all their changes afterward.
![da1.png](/garden/da1_1717378469912_0.png)
<div class="img-container"><img src="/garden/da1_1717378469912_0.png" title="da1.png"/></div>
I created the Babble Buds puppet editor and ported the rendering library I wrote for it to C# so it could be used in Unity. Dice Armor has a full campaign using cutscenes made using the Babble Buds cutscene editor, taking advantage of its support for custom commands and fields to control things like talking, giving the player dice and money, starting duels, and controlling player progression through the story.
![Action Wheel](/garden/da6_1717379962786_0.png)
<div class="img-container"><img src="/garden/da6_1717379962786_0.png" title="Action Wheel"/></div>
When a cutscene ends, its final command is to either start a duel or set the next cutscene in the story. In the latter case, there is an additional field for what to call the next cutscene, and what location it takes place. The cutscene is then added to the player's save file, and when they visit the city locations are greyed out until they have at least one action to do there. Each location has a dynamically populated action wheel with a custom range of acceptable angles.
![Shop](/garden/da7_1717379991458_0.png)
<div class="img-container"><img src="/garden/da7_1717379991458_0.png" title="Shop"/></div>
The dice shop is dynamically populated by a list of dice available to the player, which can be changed during cutscenes, and is checked against the dice owned by the player to generate sold-out indicators. On the left, the player can choose to filter the options down to a single dice effect, which also updates the "Buy All" button to buy only all the dice in the current filter.
![Inventory](/garden/da8_1717380011914_0.png)
<div class="img-container"><img src="/garden/da8_1717380011914_0.png" title="Inventory"/></div>
The inventory works most the same as the shop, but for equipping dice. It also allows you to drag individual dice or entire sets to the equipped dice glyph. While dragging it will highlight all the slots the new dice will be equipped into.
![Dice Rolling](/garden/da3_1717380046653_0.png)
<div class="img-container"><img src="/garden/da3_1717380046653_0.png" title="Dice Rolling"/></div>
The dice rolling uses the physics engine and detects once the dice have stopped moving, then determines which side is face up based on which of the normals is closest to straight up. It flags the die as cocked if that smallest angle is above a threshold. The dice sink into the table when not rolling to not interfere with any dice that are rolling.
![Missile Storm](/garden/da9_1717380177060_0.png)
<div class="img-container"><img src="/garden/da9_1717380177060_0.png" title="Missile Storm"/></div>
During certain events like winning the game or having the face of a die broken, the players' portraits will flash an emotion for a second. After winning, a random living die from the winning player is chosen to play their "finisher move", a flashy and dramatic effect to end the game. Shown is the arcane mechana's finisher, "Missile Storm".

View file

@ -6,7 +6,14 @@ title: "Digital Gardens"
prev: false
next: false
---
# Digital Gardens
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Digital Gardens</h1>
<p>63 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Chronological](/garden/chronological/index.md), [Commune](/garden/commune/index.md), [Garden-RSS](/garden/garden-rss/index.md), [The Cozy Web](/garden/the-cozy-web/index.md), [The Small Web](/garden/the-small-web/index.md)

View file

@ -6,7 +6,14 @@ title: "Federated Identity"
prev: false
next: false
---
# Federated Identity
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Federated Identity</h1>
<p>68 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Commune](/garden/commune/index.md), [Fedi v2](/garden/fedi-v2/index.md), [Weird](/garden/weird/index.md)

View file

@ -5,7 +5,14 @@ title: "Fedi v2"
prev: false
next: false
---
# Fedi v2
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Fedi v2</h1>
<p>1274 words, ~7 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Social Media](/garden/social-media/index.md), [Weird](/garden/weird/index.md)

View file

@ -7,7 +7,14 @@ title: "Fediverse"
prev: false
next: false
---
# Fediverse
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Fediverse</h1>
<p>29 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [ATProto](/garden/atproto/index.md), [Decentralized](/garden/decentralized/index.md), [Fedi v2](/garden/fedi-v2/index.md), [Incremental Social](/garden/incremental-social/index.md), [Mbin](/garden/mbin/index.md), [Weird](/garden/weird/index.md)

View file

@ -5,7 +5,14 @@ title: "Forgejo"
prev: false
next: false
---
# Forgejo
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Forgejo</h1>
<p>5 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Incremental Social](/garden/incremental-social/index.md)

View file

@ -5,7 +5,14 @@ title: "Freeform vs Chronological Dichotomy"
prev: false
next: false
---
# Freeform vs Chronological Dichotomy
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Freeform vs Chronological Dichotomy</h1>
<p>10 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Chronological](/garden/chronological/index.md), [Freeform](/garden/freeform/index.md)

View file

@ -5,7 +5,14 @@ title: "Freeform"
prev: false
next: false
---
# Freeform
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Freeform</h1>
<p>46 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Commune](/garden/commune/index.md), [Digital Gardens](/garden/digital-gardens/index.md), [Freeform vs Chronological Dichotomy](/garden/freeform-vs-chronological-dichotomy/index.md), [Garden-RSS](/garden/garden-rss/index.md), [The Small Web](/garden/the-small-web/index.md)

View file

@ -6,7 +6,14 @@ title: "Game Dev Tree"
prev: false
next: false
---
# Game Dev Tree
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Game Dev Tree</h1>
<p>34 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [My Projects](/garden/my-projects/index.md)

View file

@ -5,7 +5,14 @@ title: "Garden-RSS"
prev: false
next: false
---
# Garden-RSS
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Garden-RSS</h1>
<p>59 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Freeform](/garden/freeform/index.md), [The Small Web](/garden/the-small-web/index.md), [This Knowledge Hub](/garden/this-knowledge-hub/index.md)

View file

@ -1,11 +1,18 @@
---
public: "true"
slug: "guide-to-incrementals/appeal-to-developers"
title: "Guide to Incrementals/Appeal to Developers"
slug: "guide-to-incrementals___appeal-to-developers"
title: "Guide to Incrementals___Appeal to Developers"
prev: false
next: false
---
# Guide to Incrementals/Appeal to Developers
<script setup>
import { data } from '../../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Guide to Incrementals___Appeal to Developers</h1>
<p>636 words, ~3 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
There are a lot of developers in the incremental games community - the genre seems to draw them in, and convert a lot of players _into_ developers. Let's explore the reasons why this genre appeals to developers.

View file

@ -1,11 +1,18 @@
---
public: "true"
slug: "guide-to-incrementals/appeal-to-players"
title: "Guide to Incrementals/Appeal to Players"
slug: "guide-to-incrementals___appeal-to-players"
title: "Guide to Incrementals___Appeal to Players"
prev: false
next: false
---
# Guide to Incrementals/Appeal to Players
<script setup>
import { data } from '../../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Guide to Incrementals___Appeal to Players</h1>
<p>2400 words, ~13 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
This is something that has been discussed and analyzed by many people, and to some extent, I feel like everything that can be said on the topic already has. However, a lot of these analyses are from the perspective of those with not as much experience and involvement within the genre as I'd argue would be necessary for a fully contextualized answer. I recently watched a video about Vampire Survivors, which has since been taken down due to drawing negative attention, which made me think about some interesting arguments about what games _are_, and what makes them _good_. The video's argument that "Vampire Survivors is not a video game" mirrors a claim by the developer of Cookie Clicker that his games are ["non-games"](https://www.polygon.com/2013/9/30/4786780/the-cult-of-the-cookie-clicker-when-is-a-game-not-a-game). Using Vampire Survivors and the video made on it as a framework, I'll be answering why incremental games appeal to players. Since the video has been taken down, I'll do my best to contextualize and generalize the arguments of the video without requiring the reader to watch it. For what it's worth, while I disagreed with the video I actually liked a lot of the way it went about thinking about games, and I consider this a continuation of that discussion.

View file

@ -1,11 +1,18 @@
---
public: "true"
slug: "guide-to-incrementals/defining-the-genre"
title: "Guide to Incrementals/Defining the Genre"
slug: "guide-to-incrementals___defining-the-genre"
title: "Guide to Incrementals___Defining the Genre"
prev: false
next: false
---
# Guide to Incrementals/Defining the Genre
<script setup>
import { data } from '../../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Guide to Incrementals___Defining the Genre</h1>
<p>3429 words, ~19 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
Video games are placed into genres for a variety of reasons. They can give a mental shorthand to set the player's expectations up, they can help a game market itself by its similarities to other, already popular games, and honestly, people just love categorization for its own sake. For this guide, it's important to define the genre so it is clear what games it's even talking about.

View file

@ -5,7 +5,14 @@ title: "Guide to Incrementals"
prev: false
next: false
---
# Guide to Incrementals
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Guide to Incrementals</h1>
<p>251 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
This is a comprehensive guide to Incremental Games, a genre of video games. It will explore defining the genre, why it's appealing, and how to design and build your own incremental game. Along the way will be ~~interactive examples~~, snippets from other creators, and relevant material to contextualize everything.

View file

@ -1,11 +1,18 @@
---
public: "true"
slug: "guide-to-incrementals/navigating-criticism"
title: "Guide to Incrementals/Navigating Criticism"
slug: "guide-to-incrementals___navigating-criticism"
title: "Guide to Incrementals___Navigating Criticism"
prev: false
next: false
---
# Guide to Incrementals/Navigating Criticism
<script setup>
import { data } from '../../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Guide to Incrementals___Navigating Criticism</h1>
<p>747 words, ~4 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
Developing games is fun and exciting and teaches a lot of wonderful skills - I enthusiastically encourage anyone with an interest in game development to try it out - and incremental games are a wonderful way to get started. However, there are many challenges young and inexperienced developers have to face, and I think the hardest one - harder than coding, debugging, balancing, etc. - is handling criticism. When you put your heart and soul into a game it is natural to feel very vulnerable. While I think there's a lot communities can do to ensure they're welcoming, positive and constructive with their criticisms, inevitably you will eventually read some, and potentially a lot, of comments that can deeply affect you. No one is immune to this, from young incremental game developers to the largest content creators you can think of. That's why it's important to be able to process and navigate criticism, because ultimately collecting feedback is essential to the journey to becoming a better developer. On this page, we'll explore how to embrace criticism, grow from it, and continue to post your games publicly with confidence.

View file

@ -1,11 +1,18 @@
---
public: "true"
slug: "guide-to-incrementals/what-is-content-"
title: "Guide to Incrementals/What is Content?"
slug: "guide-to-incrementals___what-is-content-"
title: "Guide to Incrementals___What is Content?"
prev: false
next: false
---
# Guide to Incrementals/What is Content?
<script setup>
import { data } from '../../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Guide to Incrementals___What is Content?</h1>
<p>2092 words, ~11 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
If you've been in the incremental games community for any amount of time, you'll quickly find the number one thing players want is _content_. They want as much of it as possible! The most popular incremental games have tons of content, so they just keep stretching on and on and on, introducing mechanic after mechanic, and players love it. In fact, players seem to value the _amount_ of content over the quality of any _specific_ content. However, there's a bit of a lack of understanding concerning _what_ content is, and I'd like to explore what counts as content, and how we measure it. As a baseline definition, I think "content" can just be described as the parts of the game that engage the player, but to truly understand it we need to contextualize what that means and how it affects the gameplay experience.

View file

@ -5,7 +5,14 @@ title: "Incremental Social"
prev: false
next: false
---
# Incremental Social
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Incremental Social</h1>
<p>20 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Federated Identity](/garden/federated-identity/index.md), [/now](/now/index), [Webrings](/garden/webrings/index.md)

View file

@ -6,7 +6,14 @@ title: "Ivy Road"
prev: false
next: false
---
# Ivy Road
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Ivy Road</h1>
<p>6 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Davey Wreden](/garden/davey-wreden/index.md), [Wanderstop](/garden/wanderstop/index.md)

View file

@ -6,7 +6,14 @@ title: "Kronos"
prev: false
next: false
---
# Kronos
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Kronos</h1>
<p>60 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [V-ecs](/garden/v-ecs/index.md)

View file

@ -5,7 +5,14 @@ title: "Life is Strange"
prev: false
next: false
---
# Life is Strange
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Life is Strange</h1>
<p>654 words, ~4 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
A series of narrative driven video games with a focus on player choices
@ -17,8 +24,8 @@ Playthroughs I enjoyed:
- [Laura Kate](https://www.youtube.com/playlist?list=PLD0NeEbRY7VR3Vl35qtQyexV9edtlkODU)
- [Jesse and Dodger](https://www.youtube.com/playlist?list=PLFx-KViPXIkFWTwFCBku5KNgv_rsmPh-r)
- I got a shirt they made for this series signed by Jesse at PAX South 2017
- ![6346b024-885e-45e0-9df6-5ee0311133f7.png](/garden/6346b024-885e-45e0-9df6-5ee0311133f7_1718332409063_0.png)
- ![ce7b2612-2ddb-423e-82eb-95c2ed08c4da.png](/garden/ce7b2612-2ddb-423e-82eb-95c2ed08c4da_1718332277410_0.png)
- <div class="img-container"><img src="/garden/6346b024-885e-45e0-9df6-5ee0311133f7_1718332409063_0.png" title="6346b024-885e-45e0-9df6-5ee0311133f7.png"/></div>
- <div class="img-container"><img src="/garden/ce7b2612-2ddb-423e-82eb-95c2ed08c4da_1718332277410_0.png" title="ce7b2612-2ddb-423e-82eb-95c2ed08c4da.png"/></div>
- [LiS Voice Actors](https://www.youtube.com/watch?v=zvQmqdnFkZA)
Around the start of Haley and I's relationship, we'd play through LiS1 on projectors in our's classrooms

View file

@ -5,7 +5,14 @@ title: "Logseq"
prev: false
next: false
---
# Logseq
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Logseq</h1>
<p>3 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Command Palettes](/garden/command-palettes/index.md), [This Knowledge Hub](/garden/this-knowledge-hub/index.md)

View file

@ -5,7 +5,14 @@ title: "Matrix"
prev: false
next: false
---
# Matrix
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Matrix</h1>
<p>2 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Cinny](/garden/cinny/index.md), [Commune](/garden/commune/index.md), [Synapse](/garden/synapse/index.md)

View file

@ -5,7 +5,14 @@ title: "Mbin"
prev: false
next: false
---
# Mbin
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Mbin</h1>
<p>12 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Incremental Social](/garden/incremental-social/index.md)

View file

@ -6,7 +6,14 @@ title: "MTX"
prev: false
next: false
---
# MTX
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">MTX</h1>
<p>10 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Premium Currency](/garden/premium-currency/index.md), [Video Game Monetization](/garden/video-game-monetization/index.md)

View file

@ -5,7 +5,14 @@ title: "My Personal Website"
prev: false
next: false
---
# My Personal Website
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">My Personal Website</h1>
<p>10 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [The Small Web](/garden/the-small-web/index.md)

View file

@ -6,7 +6,14 @@ title: "My Projects"
prev: false
next: false
---
# My Projects
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">My Projects</h1>
<p>72 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tagged by: [Advent Incremental](/garden/advent-incremental/index.md), [Babble Buds](/garden/babble-buds/index.md), [Capture the Citadel](/garden/capture-the-citadel/index.md), [Dice Armor](/garden/dice-armor/index.md), [Game Dev Tree](/garden/game-dev-tree/index.md), [Incremental Social](/garden/incremental-social/index.md), [Kronos](/garden/kronos/index.md), [Opti-Speech](/garden/opti-speech/index.md), [Planar Pioneers](/garden/planar-pioneers/index.md), [Profectus](/garden/profectus/index.md), [V-ecs](/garden/v-ecs/index.md)

View file

@ -6,7 +6,14 @@ title: "Nostr"
prev: false
next: false
---
# Nostr
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Nostr</h1>
<p>8 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Fediverse](/garden/fediverse/index.md)

View file

@ -5,7 +5,14 @@ title: "Open Source"
prev: false
next: false
---
# Open Source
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Open Source</h1>
<p>25 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Advent Incremental](/garden/advent-incremental/index.md), [Cinny](/garden/cinny/index.md), [Commune](/garden/commune/index.md), [Dice Armor](/garden/dice-armor/index.md), [Forgejo](/garden/forgejo/index.md), [Game Dev Tree](/garden/game-dev-tree/index.md), [Logseq](/garden/logseq/index.md), [Mbin](/garden/mbin/index.md), [Planar Pioneers](/garden/planar-pioneers/index.md), [Profectus](/garden/profectus/index.md), [Synapse](/garden/synapse/index.md), [Vitepress](/garden/vitepress/index.md), [Weird](/garden/weird/index.md)

View file

@ -6,7 +6,14 @@ title: "Opti-Speech"
prev: false
next: false
---
# Opti-Speech
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Opti-Speech</h1>
<p>312 words, ~2 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [My Projects](/garden/my-projects/index.md)
@ -16,7 +23,7 @@ In college I continued development on the Opti-Speech project, originally built
The Optispeech project involves designing and testing a real-time tongue model that can be viewed in a transparent head while a subject talks — for the purposes of treating speech errors and teaching foreign language sounds. This work has been conducted in partnership with Vulintus and with support from the National Institutes of Health (NIH).
![system-architecture-600.jpg](/garden/system-architecture-600_1717384793933_0.jpg)
<div class="img-container"><img src="/garden/system-architecture-600_1717384793933_0.jpg" title="system-architecture-600.jpg"/></div>
<iframe width="560" height="315" src="https://www.youtube.com/embed/9uHqIRs7ZjM" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen style="display: block; margin: auto;"></iframe>
@ -30,10 +37,10 @@ This video shows an American talker learning a novel sound not found in English.
As the sole programmer at UT Dallas Speech Production Lab at the time, my changes involved updating to a more modern version of Unity, improving the interface, in general cleaning up tech debt so it can more easily support new features, and added support for additional EMA systems, namely the Carstens AG501.
![new-interface.png](/garden/new-interface_1717384734845_0.png)
<div class="img-container"><img src="/garden/new-interface_1717384734845_0.png" title="new-interface.png"/></div>
In addition, the program now includes documentation and unit tests to improve program stability and maintainability going forward.
![documentation.png](/garden/documentation_1717384823218_0.png)
<div class="img-container"><img src="/garden/documentation_1717384823218_0.png" title="documentation.png"/></div>
![unittests.png](/garden/unittests_1717384825666_0.png)
<div class="img-container"><img src="/garden/unittests_1717384825666_0.png" title="unittests.png"/></div>

View file

@ -6,7 +6,14 @@ title: "Planar Pioneers"
prev: false
next: false
---
# Planar Pioneers
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Planar Pioneers</h1>
<p>25 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [My Projects](/garden/my-projects/index.md), [Profectus](/garden/profectus/index.md)

View file

@ -5,7 +5,14 @@ title: "Pre-Order Bonuses"
prev: false
next: false
---
# Pre-Order Bonuses
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Pre-Order Bonuses</h1>
<p>98 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Video Game Monetization](/garden/video-game-monetization/index.md)

View file

@ -5,7 +5,14 @@ title: "Premium Currency"
prev: false
next: false
---
# Premium Currency
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Premium Currency</h1>
<p>71 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Pre-Order Bonuses](/garden/pre-order-bonuses/index.md)

View file

@ -6,7 +6,14 @@ title: "Profectus"
prev: false
next: false
---
# Profectus
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Profectus</h1>
<p>73 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Advent Incremental](/garden/advent-incremental/index.md), [Planar Pioneers](/garden/planar-pioneers/index.md)

View file

@ -6,7 +6,14 @@ title: "Social Media"
prev: false
next: false
---
# Social Media
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Social Media</h1>
<p>98 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Commune](/garden/commune/index.md), [Fediverse](/garden/fediverse/index.md)

View file

@ -5,7 +5,14 @@ title: "Synapse"
prev: false
next: false
---
# Synapse
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Synapse</h1>
<p>2 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Incremental Social](/garden/incremental-social/index.md)

View file

@ -6,7 +6,14 @@ title: "The Beginner's Guide"
prev: false
next: false
---
# The Beginner's Guide
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">The Beginner's Guide</h1>
<p>70 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [Davey Wreden](/garden/davey-wreden/index.md)

View file

@ -5,7 +5,14 @@ title: "The Cozy Web"
prev: false
next: false
---
# The Cozy Web
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">The Cozy Web</h1>
<p>45 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Digital Gardens](/garden/digital-gardens/index.md), [The Small Web](/garden/the-small-web/index.md)

View file

@ -1,11 +1,18 @@
---
public: "true"
slug: "the-indieweb/amplification"
title: "The IndieWeb/Amplification"
slug: "the-indieweb___amplification"
title: "The IndieWeb___Amplification"
prev: false
next: false
---
# The IndieWeb/Amplification
<script setup>
import { data } from '../../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">The IndieWeb___Amplification</h1>
<p>57 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
Refers to reblogging (and re-hosting, sometimes) of someone else's content on your own site

View file

@ -1,10 +1,17 @@
---
public: "true"
slug: "the-indieweb/signature-blocks"
title: "The IndieWeb/Signature Blocks"
slug: "the-indieweb___signature-blocks"
title: "The IndieWeb___Signature Blocks"
prev: false
next: false
---
# The IndieWeb/Signature Blocks
<script setup>
import { data } from '../../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">The IndieWeb___Signature Blocks</h1>
<p>14 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
A proposal I want to write for posting signed content on your [IndieWeb](/garden/the-small-web/index.md) website

View file

@ -6,7 +6,14 @@ title: "The Small Web"
prev: false
next: false
---
# The Small Web
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">The Small Web</h1>
<p>437 words, ~2 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [/now](/now/index), [This Knowledge Hub](/garden/this-knowledge-hub/index.md)

View file

@ -5,7 +5,14 @@ title: "This Knowledge Hub"
prev: false
next: false
---
# This Knowledge Hub
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">This Knowledge Hub</h1>
<p>135 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Digital Gardens](/garden/digital-gardens/index.md)

View file

@ -6,22 +6,29 @@ title: "V-ecs"
prev: false
next: false
---
# V-ecs
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">V-ecs</h1>
<p>209 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [My Projects](/garden/my-projects/index.md)
![screenshot.png](/garden/screenshot_1717383987886_0.png)
<div class="img-container"><img src="/garden/screenshot_1717383987886_0.png" title="screenshot.png"/></div>
V-ecs (pronounced "Vex") is a Vulkan-based engine I made for making highly moddable games and tools in Lua centered around the ECS design pattern and a work-stealing job system.
The engine works with "worlds", which are collections of systems and renderers. The engine comes with several worlds using systems and renderers I made, including a voxel world, an incremental game, and some test scenes. All of these include systems to render the fps as well as show a debug console by typing the grave key (\`). The default world is a title screen that detects any worlds in the "worlds" folder and displays a button for each of them.
![debug.png](/garden/debug_1717384018620_0.png)
<div class="img-container"><img src="/garden/debug_1717384018620_0.png" title="debug.png"/></div>
The original plans were to eventually put it on the steam workshop so people could more easily share their creations amongst each other, but I never became happy enough with the performance of the engine - the parallelization of the lua code involved a lot of overhead that severely limited performance.
Instead, I made a couple of worlds by myself - an infinite procedurally generated voxel world, a simple incremental game, and a more complex incremental game I call "[Sands of Time](https://thepaperpilot.itch.io/sands-of-time)".
![sandsoftime.png](/garden/sandsoftime_1717383994964_0.png)
<div class="img-container"><img src="/garden/sandsoftime_1717383994964_0.png" title="sandsoftime.png"/></div>
The gameplay of Sands of Time was replicated in [Kronos](/garden/kronos/index.md) Chapter 2!

View file

@ -5,7 +5,14 @@ title: "Video Game Monetization"
prev: false
next: false
---
# Video Game Monetization
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Video Game Monetization</h1>
<p>123 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Life is Strange](/garden/life-is-strange/index.md)

View file

@ -5,7 +5,14 @@ title: "Vitepress"
prev: false
next: false
---
# Vitepress
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Vitepress</h1>
<p>4 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [This Knowledge Hub](/garden/this-knowledge-hub/index.md)

View file

@ -6,7 +6,14 @@ title: "Wanderstop"
prev: false
next: false
---
# Wanderstop
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Wanderstop</h1>
<p>8 words, ~0 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Tags: [Davey Wreden](/garden/davey-wreden/index.md)

View file

@ -5,7 +5,14 @@ title: "Webrings"
prev: false
next: false
---
# Webrings
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Webrings</h1>
<p>139 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [The Small Web](/garden/the-small-web/index.md)

View file

@ -5,7 +5,14 @@ title: "Weird"
prev: false
next: false
---
# Weird
<script setup>
import { data } from '../../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">Weird</h1>
<p>114 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
> Referenced by: [Commune](/garden/commune/index.md), [Fedi v2](/garden/fedi-v2/index.md), [The Small Web](/garden/the-small-web/index.md)

27
site/git.data.ts Normal file
View file

@ -0,0 +1,27 @@
const fs = require("fs");
const path = require("path");
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);
export default {
watch: ['site/garden/**/*'],
async load(files: string[]): Record<string, string> {
const ret: Record<string, string> = {};
await Promise.all(files.map(e => new Promise<void>(async (resolve) => {
const firstCommit = (await new Promise(async (resolve, reject) => {
exec(`git log -n 1 --diff-filter=A --format="<a href='https://code.incremental.social/thepaperpilot/pages/commit/%H' title='%ad'><time class='dt-published' datetime='%ad'>%as</time></a>" -- ${e}`)
.then(output => resolve(output.stdout))
.catch(err => console.warn(`Error calculating first commit for ${e}:\n${err}`) || reject());
})) ?? "";
const lastCommit = (await new Promise(async (resolve, reject) => {
exec(`git log -n 1 --diff-filter=M --format="<a href='https://code.incremental.social/thepaperpilot/pages/commit/%H' title='%ad'><time class='dt-updated' datetime='%ad'>%as</time></a>" -- ${e}`)
.then(output => resolve(output.stdout))
.catch(err => console.warn(`Error calculating first commit for ${e}:\n${err}`) || reject());
})) ?? "";
ret[e] = `Planted ${firstCommit}.${lastCommit ? ` Last tended to ${lastCommit}.` : ''}`;
resolve();
})));
return ret;
}
};

View file

@ -6,3 +6,5 @@ next: false
# Hello!
I'm Anthony, or The Paper Pilot, and I make fun games and tools!
<img class="hero" src="/paperpilot.png" />

View file

@ -5,7 +5,14 @@ title: "/now"
prev: false
next: false
---
# /now
<script setup>
import { data } from '../git.data.ts';
import { useData } from 'vitepress';
const pageData = useData();
</script>
<h1 class="p-name">/now</h1>
<p>212 words, ~1 minute read. <span v-html="data[`site/${pageData.page.value.relativePath}`]" /></p>
<hr/>
This "now page" offers a big picture glimpse into what Im focused on at this point in my life. [What is a now page](https://nownownow.com/about)?

BIN
site/public/paperpilot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB