Compare commits

..

11 Commits

66 changed files with 72 additions and 5433 deletions

View File

@@ -1,6 +1,6 @@
node_modules
.next
Dockerfile
.git
.gitea
*.md
.env*
.gitignore
*.mdx

View File

@@ -14,25 +14,10 @@ jobs:
- name: Checkout Code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build image
uses: docker/build-push-action@v5
with:
context: .
target: release
tags: local/gabriel-blog:latest
load: true
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=min
- name: Rotate cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
- name: Deploy and cleanup
- name: Rebuild and Deploy with Docker Compose
run: |
docker build --target release -t local/gabriel-blog:latest .
docker compose up -d
# Clean up any old, unused images to save disk space
docker image prune -f

3
.gitignore vendored
View File

@@ -39,6 +39,3 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
# brainstorm
.superpowers/

View File

@@ -5,7 +5,7 @@ import GoBackButton from "@/components/go-back-button";
export default function NotFound() {
return (
<div className="mx-auto max-w-md pt-16">
<Window title="Oopsie doopsie! You're lost!">
<Window title="Windows cannot find this page">
<div className="flex items-start gap-4 mb-6">
<div className="flex-shrink-0 flex h-10 w-10 items-center justify-center rounded-full bg-red-600 shadow-inner">
<svg

View File

@@ -1,20 +1,12 @@
import { getSortedPostsData, PostMeta } from "../lib/posts";
import Link from "next/link";
import Window from "../components/window";
import Badges from "../components/badges";
function isNew(dateStr: string): boolean {
const postDate = new Date(dateStr);
const now = new Date();
const diffDays = (now.getTime() - postDate.getTime()) / (1000 * 60 * 60 * 24);
return diffDays <= 30;
}
export default function Home() {
const allPostsData: PostMeta[] = getSortedPostsData();
return (
<div className="space-y-6">
<div className="space-y-12">
<header className="text-center">
<h1 className="text-5xl font-bold text-white [text-shadow:_2px_2px_4px_rgb(0_0_0_/_40%)]">
Gabriel's Kaszewski Blog
@@ -25,25 +17,16 @@ export default function Home() {
</header>
<section>
<Window title="Blog Posts" showRss>
{/* The list of posts is displayed inside our custom Window component */}
<Window title="Blog Posts">
{allPostsData.length > 0 ? (
<ul className="space-y-4">
{allPostsData.map(({ id, date, title, wip }) => (
{allPostsData.map(({ id, date, title }) => (
<li key={id}>
<Link
href={`/posts/${id}`}
className="relative block overflow-hidden rounded-md bg-white/50 p-4 transition-all duration-200 hover:bg-white/80 hover:shadow-md"
className="block rounded-md bg-white/50 p-4 transition-all duration-200 hover:bg-white/80 hover:shadow-md"
>
{isNew(date) && !wip && (
<div className="animate-blink absolute top-[10px] right-[-24px] w-[100px] rotate-[35deg] bg-[#e05010] py-0.5 text-center text-[9px] font-bold text-white shadow-sm">
NEW!
</div>
)}
{wip && (
<div className="absolute top-[10px] right-[-24px] w-[100px] rotate-[35deg] bg-amber-500 py-0.5 text-center text-[9px] font-bold text-white shadow-sm">
🚧 WIP
</div>
)}
<h3 className="font-bold text-lg text-blue-800">{title}</h3>
<small className="text-gray-600">
{new Date(date).toLocaleDateString("en-US", {

View File

@@ -1,16 +1,16 @@
import Link from "next/link";
import { getPostData, getAllPostIds, getAdjacentPosts } from "@/lib/posts";
import { getPostData, getAllPostIds } from "@/lib/posts";
import type { PostData } from "@/lib/posts";
import Window from "@/components/window";
import TableOfContents from "@/components/table-of-contents";
import { MDXRemote } from "next-mdx-remote/rsc";
import rehypePrettyCode from "rehype-pretty-code";
import rehypeSlug from "rehype-slug";
import remarkGfm from "remark-gfm";
import Video from "@/components/video";
interface PageProps {
params: Promise<{ slug: string }>;
params: {
slug: string;
};
}
export async function generateStaticParams() {
@@ -19,55 +19,50 @@ export async function generateStaticParams() {
}
export async function generateMetadata({ params }: PageProps) {
const { slug } = await params;
const postData = await getPostData(slug);
const postData = await getPostData(params.slug);
return {
title: `${postData.title} | Gabriel's Kaszewski Blog`,
};
}
export default async function Post({ params }: PageProps) {
const { slug } = await params;
const postData: PostData = await getPostData(slug);
const { prev, next } = getAdjacentPosts(slug);
const postData: PostData = await getPostData(params.slug);
return (
<div className="mx-auto max-w-6xl">
<div className="lg:flex lg:gap-4 lg:items-start">
<Window title={postData.title} showProgress className="lg:flex-1 min-w-0">
<article>
<div className="mb-4 text-gray-500 flex flex-col gap-1">
<span>
{new Date(postData.date).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})}
</span>
<span className="text-sm text-gray-400">{postData.readingTime}</span>
<div className="mx-auto max-w-5xl">
<Window title={postData.title} showProgress>
<article>
<div className="mb-4 text-gray-500 flex flex-col gap-1">
<span>
{new Date(postData.date).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})}
</span>
<span className="text-sm text-gray-400">{postData.readingTime}</span>
</div>
{postData.wip && (
<div className="mb-6 flex items-center gap-3 rounded-lg border border-amber-300 bg-amber-50/70 px-4 py-3 text-sm text-amber-800">
<span className="text-lg">🚧</span>
<span>This post is a work in progress content may change.</span>
</div>
)}
{postData.wip && (
<div className="mb-6 flex items-center gap-3 rounded-lg border border-amber-300 bg-amber-50/70 px-4 py-3 text-sm text-amber-800">
<span className="text-lg">🚧</span>
<span>This post is a work in progress content may change.</span>
</div>
)}
{/* Mobile TOC — shown above article, hidden on lg+ */}
{postData.headings.length > 0 && (
<div className="lg:hidden mb-6">
<TableOfContents headings={postData.headings} />
</div>
)}
{/* Mobile TOC — inline above article, hidden on lg+ */}
{postData.headings.length > 0 && (
<div className="lg:hidden mb-6 bg-white/20 backdrop-blur border border-white/30 rounded-lg p-4">
<TableOfContents headings={postData.headings} />
</div>
)}
<div className="prose lg:prose-lg max-w-none">
<div className="lg:flex lg:gap-8 lg:items-start">
<div className="prose lg:prose-lg max-w-none flex-1 min-w-0">
<MDXRemote
source={postData.content}
components={{ Video }}
options={{
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[
@@ -82,50 +77,24 @@ export default async function Post({ params }: PageProps) {
}}
/>
</div>
</article>
</Window>
{/* Desktop TOC — separate Aero Window, sticky on the right */}
{postData.headings.length > 0 && (
<div className="hidden lg:block w-56 flex-shrink-0 sticky top-8">
<Window title="Contents">
<TableOfContents headings={postData.headings} />
</Window>
{/* Desktop TOC sidebar — hidden on mobile */}
{postData.headings.length > 0 && (
<div className="hidden lg:block w-52 flex-shrink-0">
<TableOfContents headings={postData.headings} />
</div>
)}
</div>
)}
</div>
<div className="mt-8 flex items-center justify-between gap-4">
{prev ? (
<Link
href={`/posts/${prev.id}`}
className="inline-block max-w-[38%] truncate rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
title={prev.title}
>
{prev.title}
</Link>
) : (
<span />
)}
</article>
</Window>
<div className="mt-8 text-center">
<Link
href="/"
className="inline-block shrink-0 rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
className="inline-block rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
>
Home
Back to home
</Link>
{next ? (
<Link
href={`/posts/${next.id}`}
className="inline-block max-w-[38%] truncate rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
title={next.title}
>
{next.title}
</Link>
) : (
<span />
)}
</div>
</div>
);

View File

@@ -16,7 +16,6 @@
"rehype-pretty-code": "^0.14.3",
"rehype-slug": "^6.0.0",
"remark": "^15.0.1",
"remark-gfm": "^4.0.1",
"remark-html": "^16.0.1",
"rss": "^1.2.2",
"shiki": "^4.0.2",
@@ -256,8 +255,6 @@
"esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="],
"escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
"estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="],
@@ -366,24 +363,8 @@
"markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="],
"markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
"mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="],
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="],
"mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="],
"mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="],
"mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="],
"mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="],
"mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="],
"mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="],
"mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="],
"mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
@@ -404,20 +385,6 @@
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
"micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="],
"micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="],
"micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="],
"micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="],
"micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="],
"micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="],
"micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="],
"micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="],
"micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="],
@@ -536,8 +503,6 @@
"remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="],
"remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="],
"remark-html": ["remark-html@16.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "hast-util-sanitize": "^5.0.0", "hast-util-to-html": "^9.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0" } }, "sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ=="],
"remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="],
@@ -656,10 +621,6 @@
"hast-util-to-jsx-runtime/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"mdast-util-find-and-replace/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
"mdast-util-find-and-replace/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
"mdast-util-from-markdown/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"mdast-util-mdx-jsx/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
@@ -692,10 +653,6 @@
"vfile-message/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"mdast-util-find-and-replace/unist-util-is/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"mdast-util-find-and-replace/unist-util-visit-parents/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"mdast-util-phrasing/unist-util-is/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
}
}

View File

@@ -1,85 +0,0 @@
import Link from "next/link";
interface BadgeProps {
href?: string;
children: React.ReactNode;
style?: React.CSSProperties;
}
function Badge({ href, children, style }: BadgeProps) {
const base = (
<div
className="flex items-center justify-center border border-white/40 text-center font-mono leading-tight select-none"
style={{ width: 88, height: 31, fontSize: 9, ...style }}
>
{children}
</div>
);
if (href) {
if (href.startsWith("http")) {
return (
<a href={href} target="_blank" rel="noopener noreferrer" className="hover:opacity-80 transition-opacity">
{base}
</a>
);
}
return (
<Link href={href} className="hover:opacity-80 transition-opacity">
{base}
</Link>
);
}
return base;
}
export default function Badges() {
return (
<div className="flex flex-wrap gap-1.5">
<Badge
href="https://nextjs.org"
style={{ background: "linear-gradient(135deg, #0d0d0d, #1a1a2e)", color: "#7dd3fc", borderColor: "#334155" }}
>
<span> Next.js</span>
</Badge>
<Badge
href="https://bun.sh"
style={{ background: "linear-gradient(135deg, #1a0a00, #2d1500)", color: "#fb923c", borderColor: "#7c2d12" }}
>
🍞 Powered by Bun
</Badge>
<Badge
style={{ background: "linear-gradient(135deg, #0c1a3a, #1e3a6e)", color: "#93c5fd", borderColor: "#1e40af" }}
>
<div>
<div>Best viewed</div>
<div>1024×768</div>
</div>
</Badge>
<Badge
href="/feed.xml"
style={{ background: "linear-gradient(135deg, #431407, #7c2d12)", color: "#fde68a", borderColor: "#b45309" }}
>
📡 Valid RSS
</Badge>
<Badge
style={{ background: "linear-gradient(135deg, #0f172a, #1e1b4b)", color: "#c4b5fd", borderColor: "#4c1d95" }}
>
Made with
</Badge>
<Badge
style={{ background: "linear-gradient(135deg, #0369a1, #0ea5e9)", color: "white", borderColor: "#38bdf8" }}
>
<div>
<div style={{ fontSize: 8 }}> Frutiger</div>
<div style={{ fontSize: 8 }}>Aero </div>
</div>
</Badge>
</div>
);
}

View File

@@ -4,19 +4,9 @@ import { useRouter } from "next/navigation";
export default function GoBackButton() {
const router = useRouter();
const handleBack = () => {
if (window.history.length > 1) {
router.back();
} else {
router.push("/");
}
};
return (
<button
onClick={handleBack}
aria-label="Go back to previous page"
onClick={() => router.back()}
className="px-4 py-1.5 text-sm bg-gradient-to-b from-blue-100 to-blue-200 border border-blue-300 rounded hover:from-blue-200 hover:to-blue-300 transition-colors"
>
Go Back

View File

@@ -35,7 +35,7 @@ export default function TableOfContents({ headings }: TableOfContentsProps) {
if (headings.length === 0) return null;
return (
<nav>
<nav className="bg-white/20 backdrop-blur border border-white/30 rounded-lg p-4 lg:sticky lg:top-8">
<p className="text-xs font-bold uppercase tracking-widest text-blue-800 mb-3">
Contents
</p>
@@ -43,7 +43,7 @@ export default function TableOfContents({ headings }: TableOfContentsProps) {
{headings.map(({ slug, text, level }) => (
<li
key={slug}
className={level === 3 ? "pl-6" : level === 2 ? "pl-3" : ""}
className={level === 3 ? "pl-3" : ""}
>
<a
href={`#${slug}`}

View File

@@ -1,28 +0,0 @@
interface VideoProps {
src: string;
caption?: string;
}
export default function Video({ src, caption }: VideoProps) {
return (
<figure className="my-4">
<div className="rounded-lg border border-white/30 bg-white/10 backdrop-blur-sm overflow-hidden shadow-md">
<video
src={src}
className="w-full"
aria-label={caption ?? src}
preload="metadata"
controls
loop
muted
playsInline
/>
</div>
{caption && (
<figcaption className="mt-2 text-center text-sm text-gray-500 italic">
{caption}
</figcaption>
)}
</figure>
);
}

View File

@@ -47,7 +47,6 @@ interface WindowProps {
children: React.ReactNode;
className?: string;
showProgress?: boolean;
showRss?: boolean;
}
export default function Window({
@@ -55,21 +54,18 @@ export default function Window({
children,
className = "",
showProgress = false,
showRss = false,
}: WindowProps) {
return (
<div
className={`rounded-lg border border-white/30 bg-white/70 shadow-window backdrop-blur-xl ${className}`}
>
<div className="rounded-t-md overflow-hidden sticky top-0 z-10">
<div className="rounded-t-md overflow-hidden">
<div className="flex select-none items-center justify-between bg-gradient-to-b from-blue-500 to-window-title px-4 py-1.5 font-bold text-white text-sm">
<div className="flex items-center space-x-2">
<span>{title}</span>
{showRss && (
<Link href="/feed.xml" title="RSS Feed">
<RSSIcon className="h-4 w-4 opacity-80 hover:opacity-100" />
</Link>
)}
<Link href="/feed.xml" title="RSS Feed">
<RSSIcon className="h-4 w-4 opacity-80 hover:opacity-100" />
</Link>
</div>
<div className="flex items-center space-x-2">
<div className="flex h-4 w-4 items-center justify-center opacity-80">

View File

@@ -2,7 +2,6 @@ import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import readingTime from 'reading-time';
import { notFound } from 'next/navigation';
const postsDirectory = path.join(process.cwd(), 'posts');
@@ -33,7 +32,7 @@ export interface PostMeta {
}
function extractHeadings(content: string): Heading[] {
const regex = /^(#{1,3})\s+(.+)$/gm;
const regex = /^(#{2,3})\s+(.+)$/gm;
const headings: Heading[] = [];
let match;
while ((match = regex.exec(content)) !== null) {
@@ -89,19 +88,8 @@ export function getAllPostIds() {
}
}
export function getAdjacentPosts(slug: string): { prev: PostMeta | null; next: PostMeta | null } {
const posts = getSortedPostsData(); // newest → oldest
const index = posts.findIndex((p) => p.id === slug);
if (index === -1) return { prev: null, next: null };
return {
prev: posts[index + 1] ?? null, // older
next: posts[index - 1] ?? null, // newer
};
}
export async function getPostData(id: string): Promise<PostData> {
const fullPath = path.join(postsDirectory, `${id}.mdx`);
if (!fs.existsSync(fullPath)) notFound();
const fileContents = fs.readFileSync(fullPath, 'utf8');
const matterResult = matter(fileContents);
const stats = readingTime(matterResult.content);

4167
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,17 +20,16 @@
"rehype-pretty-code": "^0.14.3",
"rehype-slug": "^6.0.0",
"remark": "^15.0.1",
"remark-gfm": "^4.0.1",
"remark-html": "^16.0.1",
"rss": "^1.2.2",
"shiki": "^4.0.2"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"tailwindcss": "^4",
"typescript": "^5"
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4"
}
}

View File

@@ -1,27 +0,0 @@
---
title: "About Me"
description: "First post — introducing myself as an 17-year-old developer from Gdańsk with big dreams."
date: "2019-05-09"
---
First of all, I am aware that blogs are kind of a 20102012 thing. But since I am really bored and I've watched a lot of Victorious and iCarly recently, I thought that I'll also make my own blog, or at least try...
So, let's talk about me.
Hi, I'm an 17-year-old boy who lives in Gdańsk, Poland — well, for at least five days a week. I go to III High School and I'm in a bilingual class.
Like every other teenager, I have hobbies. My main hobby is **programming**. I've been coding since I was 11. I started with C++ but moved into C# very quickly. Currently, I make mobile apps, desktop applications, games, microservices, and many other interesting things. In the future, I want to work as a Software Developer in a big tech company like Google or Microsoft.
I also take photos. In my junior high, I had Photography classes and since then I've been interested in it. Although I don't plan anything with it in my future — it'll stay as a hobby, I guess.
Another hobby is very related to the last one: **filmmaking**. Since I was a little kid I wanted to make movies. When I was 11, I uploaded my first video on YouTube — not really a movie, but a Minecraft let's play I recorded with my friend. After that I started uploading other let's plays, tutorials, and vlogs. I've been to some summer camps where I learned how to make a movie, write a script, etc. I also was in a film group in my primary school and junior high. I've made 3 short movies but I want to make more.
This year I started going to the gym and... I loved it. I recommend everyone start going — it's fun and you can improve your health a lot.
Despite all those things, I'm trying to learn how to play the guitar and how to sing. The singing part is a spontaneous decision. I kinda like singing but I suck at it, so I want to learn how to do it properly. I'm pretty sure I'm gonna fail, but hey — it's worth trying, isn't it?
After high school, I want to study Computer Science and Data Engineering. Then I want to move to the United States, probably somewhere near Silicon Valley, and start my life there. I've wanted that since I was a little kid. My ultimate life goal is to have a good life, a lovely family, and a great job.
Okay, I think this is everything. I'm pretty sure no one will read this but I don't care — I just wanted to write some stuff and put it on the internet.
Have a nice day!

View File

@@ -1,17 +0,0 @@
---
title: "The Beginning of a Tough Week"
description: "3:30 AM coding sessions, a Physics homework nightmare, and a week packed with tests ahead."
date: "2019-05-13"
---
It's 3:30 AM on a Monday morning. Saturday's party was great — I danced a lot and, of course, ate a lot too.
Today I finally got my test project for work. I thought it was going to be much harder than it actually was. I've just finished working on those tasks. For almost 3 hours I was trying just to *run* the project. It took me that long because CMake couldn't find the libraries, so I downloaded Linux and did my work there.
Now I'm working on my Physics homework, which is not easy — mostly because I have no idea how to do it. My task is to draw a graph of a planet's journey around the sun and its apparent retrograde motion. The main problem is that I've got no idea where to get the data about Mars positions. I'll probably end up making them up.
This whole week isn't going to be easy either. On Tuesday I'm retaking two recent Math exams and I also have a Chemistry test. On Wednesday there's a Geography pop quiz from Europe's physical relief map. On Thursday I think I'm free, but I'll study before Friday's Math test.
As you can see, this week is really tough. But the bright side is that after this week, summer break will be a little closer.
Okay, I gotta get back to that Physics homework.

View File

@@ -1,17 +0,0 @@
---
title: "Boring civics class, blood drawn, and lime coke"
description: "First day back after teacher strikes, downloading my Google data, and anxiously waiting for a job test project."
date: "2019-05-09"
---
Welcome! Today it was my first day in school since last month. Teachers in my country went on strike, so we didn't have classes. But the strike is over — and so is my free time.
I had easy classes today: civics, English, two hours of Polish, and that's it. Civics was the worst. My teacher somehow changes the speed of the clock — I always feel like it's two hours instead of one. Today's topic actually wasn't that bad though; we were talking about the European Union and how it works, because last week was the 15th anniversary of Poland joining the EU. Tomorrow I have a day off because I'm going to the doctor.
After school I went home, watched a new episode of Riverdale on Netflix, and then downloaded my Google, Snapchat, and Facebook data. I found a few interesting things — for example, I didn't know that when Google tracks my location, it saves whether I was walking or driving. I also found some really embarrassing things from my past.
I've been checking my email for almost 8 days now. I'm waiting for a test project that will decide if I'm going to get a job as a C++ Software Engineer. I'm so pumped about this but also a little afraid. If I get this job, I'd have to keep up with school and work at the same time. I don't know how I'm going to do it, but I'll figure it out later. The job is 100% remote so that's at least good news. I've never worked before so all of this is new to me, and I'm thrilled.
I haven't had dinner yet and I'm literally starving — I had blood drawn this morning and couldn't have breakfast, so today I've eaten only two chocolate bars and drank lime coke so far.
I think that's it for now. Really, I gotta eat something.

View File

@@ -1,15 +0,0 @@
---
title: "Chill Saturday"
description: "Housework, singing practice, and exciting news about an early summer break."
date: "2019-05-18"
---
Hey! I've just pushed the last changes to my test project for work.
Today's weather was awesome. In the morning it was sunny, then it rained for a while, and now it's sunny and really warm. I was alone in the house so I did groceries, laundry, and washed dishes. After all that housework I had a little time for myself before I had to go back to work, so I practiced my singing. Actually, it wasn't that bad — I think I'm getting better at it. Maybe I'll do some covers soon, who knows.
A funny thing happened today: the Prime Minister of Poland said that summer break is going to be sooner than it was supposed to be. I'm going to have a summer vacation in literally a month. I'm so happy about this news. I just have to survive the next two weeks and I'll finally be free.
Well, not really free — if my evaluation tomorrow goes great, I'll have to work. But that's okay.
I tried to record something for my YouTube channel but didn't have any ideas. So I think that's it for today. See you soon.

View File

@@ -1,19 +0,0 @@
---
title: "Decisions"
description: "Weighing university options from Poland to Stanford, and discovering Gavin James and MAX."
date: "2020-03-11"
---
As you may already know, I'm a junior in high school, which means I'll have to choose a college soon. So today I took my time and checked universities in my country, in Europe, and I also looked at Stanford University. Having done that, I've come to some conclusions.
Firstly, I would love to study in the US, especially in California. But if I wanted to accomplish that, I'd have to start working on my GPA (which is not the best right now — 3.40) and prepare for the SAT. Secondly, I couldn't find any university in Europe (excluding the UK) that would suit me best, and I don't want to go study abroad just for the sake of it. If I went abroad, I'd want to study at a prestigious university that is respected globally.
Poland has some pretty good universities, but they rank very low in both world and European rankings. So I have to decide now, because there's a lot to do. If I choose Stanford, I'll have to ask teachers for recommendation letters, write a personal essay, and register for the SAT in Poland. Fortunately, Stanford doesn't require TOEFL.
The biggest problem is my GPA. I kind of messed up my grades during my freshman year and I can't change those anymore — they're pulling my GPA down. To hit a 4.0, I'd need to get top marks in Math, Physics, Spanish, and Polish. Maybe not all of it, but Math will definitely be the hardest. I'm not really worried about the SAT though — I did a mock one a few months ago and it went pretty well. The Math section was actually the easiest part.
I'll have to do more research on European universities. Maybe something will catch my eye.
On a completely different note: since last week I've been listening to Gavin James and MAX (also known as Max Schneider). I find Gavin's music very soothing, especially his album *Only Ticket Home*. I used to listen to MAX through Kurt Hugo Schneider's covers. Kurt also makes great music — if you haven't listened to him yet, go check him out. You might like it.
I think this is all for now. See ya sometime in the future!

View File

@@ -1,19 +0,0 @@
---
title: "The End of July"
description: "Lake house fishing, C++ and math homework, Minecraft, The Lion King, and Victoria Justice's new song."
date: "2019-08-01"
---
So July has come to an end. It's been a quite normal month — I haven't done anything particularly special.
I spent last week at the lake house with my family. I didn't bring a computer, so instead I took a book about C++ programming and my math notebook, calculator, and pencil case — because my math teacher sent me an email with 4 PDF files full of exercises about quadratic functions. I knew the day would come when my teacher would email me homework during vacation. And sadly it did. Actually, I was surprised that I still remembered how to solve those exercises and still had the equations down.
The lake house was near an actual lake, so I wanted to try fishing a little. I didn't have a fishing rod, so I made one myself. It was a really satisfying experience. I managed to catch 3 fish.
When I got back, I spent most of the week playing Minecraft and coding a game in C++. I'm really glad that Minecraft got popular again and that I actually have fun playing it. I feel like I'm 10 again.
Also, an amazing thing happened this week: Victoria Justice posted on Instagram that she's recording a brand new song! I'm so happy — I had literally just started listening to her songs and was thinking "I wonder when she'll make a new song," and then BANG, a new one is coming.
Oh, and I almost forgot — I went to see *The Lion King* twice! I was skeptical before seeing it, but after I watched it I changed my mind. I really liked the remake, although the original is still the best.
So that wraps up my recent activities. As you can see, nothing too crazy happened — maybe except for the Victoria thing.

View File

@@ -1,13 +0,0 @@
---
title: "1st of September"
description: "Summer's over, moving into a new apartment, and reflecting on a surprisingly productive vacation."
date: "2019-09-01"
---
So summertime has come and gone... and unfortunately, school starts tomorrow.
I've just moved into a new apartment with my best friend. Honestly, I'm a little worried about the upcoming school year — math is going to be much harder, and I'm living alone for the first time in my life.
To summarize my vacation: I did many interesting nerdy things. I built my own blog website (didn't deploy it though), wrote a video sharing website (same story), started writing a dating website (didn't finish), made a short movie (I have to publish it someday), got better at C++ programming, and finally became more productive — although I put off gym training and now I'll have to start again at some point.
Okay, I think this is all for now. See ya.

View File

@@ -1,167 +0,0 @@
---
title: "From simple afterthought to over-engineered software"
description: "How a Sunday night movie turned into a federated, hexagonal-architecture movie diary"
date: "2026-06-02"
---
## Genesis
One weekend, I was lying in bed with my home projector on, deciding to finally watch a movie I'd kept on the back burner for a month: _The Bourne Supremacy_. The movie was good, though I think I liked the first one better.
But as I watched, my twisted developer mind couldn't just appreciate young Matt Damon doing spy things. I started thinking about how awesome it would be to add a section to my personal website where people could see the movies I'd watched and read my opinions on them. You know, as one does.
Initially, it seemed straightforward. Just create a new `movie-corner` directory, add a `page.tsx`, dump a model and some data into a `lib.ts` file, and I'd be good to go.
But then I thought a bit more, and a new idea came to my head. Instead of a static, manual, hard-coded list of movies, wouldn't it be much better to have a widget? You know, like those old-school widgets that roamed the internet in the 00s. An `iframe` that would display my profile from a brand new, dedicated web service handling all this movie stuff.
Let's be honest: I am quite a lazy person. I knew that hard-coding movies, fetching posters, managing metadata myself, and making a git commit every single time I watched a film would quickly become cumbersome, and I'd just stop doing it. Not to mention, adding a new movie from my phone or any device that isn't my laptop would be a massive pain in the ass.
So, the idea for a dedicated web service was born. When the movie finished, I didn't even move from my bed. I just grabbed my laptop, opened it up, created a new directory, and at 10:00 PM on a Sunday, I began what I naively thought would be a simple two-hour adventure.
Now, you might be asking yourself (or rather, asking me) why reinvent the wheel? Services like _Filmweb_, _Letterboxd_, _IMDb_, and probably a dozen others already exist and do exactly what I wanted.
To be honest, if you have to ask that question, you don't know what we as programmers, engineers, and developers actually do. We love to solve already-solved problems from scratch. We are the exact people who look at 14 competing standards, complain that there are too many standards, and proceed to create a 15th one ;)
But jokes aside, I did have a genuine motivation beyond just an itch to write code. I used Filmweb extensively from 2015 to 2020, and eventually, I realized a fatal flaw in these platforms: you don't own your data. Filmweb owns it. Letterboxd owns it. [citation needed, i am not actually sure about letterboxd, so don't sue me.]
Since around 2021, I've become a massive fan of the Fediverse. I absolutely love the concept of the decentralized web. So I thought, hey, this little pet project of mine actually has a highly sensible reason to be decentralized and federated. Instead of trapping my reviews in another walled garden, I could own my database and broadcast my activity to the wider network.
But, wait a second. Fediverse, federation... so many words, so many concepts. What the hell do those even mean? It would be very impolite of me not to explain myself and leave you, dear reader, with this unpinned grenade (is this even an idiom in English??).
So let's take a quick tangent into my obsession with the decentralized internet, shall we?
---
## What the hell is the Fediverse?
If you aren't deep into decentralized tech circles, the Fediverse (Federated Universe) might sound like something out of Star Trek. But you actually already use a federated system every single day: **Email**.
Think about it. If you have a _Gmail_ account, you can send a message to your boss who uses _Outlook_, or to your weird uncle who still uses _wp_ or _o2_ or other old ad-ridden mail provider. You don't all need to be on the same platform to talk to each other, because all of those servers speak the same underlying language (SMTP).
Now, imagine if social media worked like that. Imagine (_John Lennon starts playing in the background_) if you could use a Twitter account to follow your friend's Instagram page, like a YouTube video, and comment on a Reddit thread, all without ever leaving Twitter.
That is Fediverse. It is a network of thousands of independent social media servers that can all talk to each other.
The magic glue that makes this possible is a web standard called **ActivityPub**. It's essentially the HTTP of social networking. It is a language, a protocol that social media platforms use to speak to each other. If your server speaks **ActivityPub**, it can communicate with anyone else on the network, the most famous example being Mastodon. And spoiler alert: Movies Diary entries _do_ show up on Mastodon feeds!
Or so that is the theory.
---
## Personal career growth limbo
Okay, so I hope that clears up what the Fediverse is and how federation works. I promise I will come back to the ActivityPub stuff later.
But building a federated node wasn't actually my first, or even second, motivation. You see, I have been programming since I was 11. Now I am at the ripe age of 24, and I love programming as much as I did as a kid. Maybe even more so, now that I'd consider myself a fairly decent software engineer.
But I would love to become a software architect one day. Right now, I'm in this kind of professional limbo where I am utterly obsessed with architecture, system design, and all of that high-level jazz. Low-level details just aren't as important to me anymore.
So, before I even wrote a single line of code, I decided on the core principles of this project. The idea itself was simple (it was essentially just a CRUD app) but that doesn't mean you have to do it the half-assed way.
Recently (well, five months ago), I bought a few books about, surprise surprise, software architecture and Domain-Driven Design (DDD). Naturally, I haven't read them yet. But I _did_ read a few articles! I am in no way knowledgeable enough to give lectures on DDD, but I decided this project would strictly follow my favorite pattern: **Hexagonal Architecture**, splitting the core business logic cleanly into Domain and Application layers.
Why go through all this trouble? It was supposed to just be a widget, right?
Well, yes. But we need a way to store data, which means we have to bring in some persistence. That naturally means bringing in a database engine. And that makes me think: _hmmm, what if I want to swap out the database engine later?_ It's nice to abstract it from the start so it won't be a pain in the ass to change down the road.
Then there's the metadata. We need a way to fetch movie details from free APIs. That's another thing we should abstract. There are at least two providers I know of (TMDb and OMDb), and our core domain shouldn't care which one we actually use.
And then we have the movie posters. We need to store image files. We could have multiple storage backends. I run a MinIO instance on my home server, but someone else might prefer to use their local file system, or maybe even dump blobs into a PostgreSQL table.
As you can see, this simple little pet project surprisingly has a ton of dependencies and underlying complexity. And that's not even mentioning the fact that we definitely need a background worker, which brings in a whole new set of ports and adapters to implement.
So, that explains the Hexagonal Architecture. But I had a few other guiding principles.
First, I absolutely didn't want to use React, or any JavaScript, for that matter. In the spirit of the old-school retro widget, I figured classic server-rendered HTML templates with just a pinch of CSS would do just fine. At the same time, I didn't want to lock users into just my web client. I wanted to expose a clean REST API so anyone could build their own custom clients if they felt like it.
And the final principle: I love open-source, and I am a huge advocate for self-hosting. I want my projects to be incredibly easy to spin up on a home server, and just as easy to maintain and extend.
This is the ultimate justification for using Hexagonal Architecture on a "pet project." If the codebase ever grows, or if I want to swap out pieces in the future, working with it won't feel like untangling a bowl of spaghetti.
---
## Sunday, 10 PM. Let's go.
Alright, enough philosophy. Let me tell you what actually happened.
The language was never a question. I write everything in Rust. Personal projects, work stuff, throwaway scripts that any sane person would write in Python. Rust. It's just how my brain works at this point. I could go on another tangent why I despise Python and other languages, but I will have some mercy for you, dear reader, and not bore you with that.
So I opened my laptop, created a new directory, and did what I always do first: I wrote the domain layer. Not a web server. Not a database schema. Not even a "hello world" endpoint. The _domain_. `Movie`. `Review`. `Rating`. Trait definitions for `MovieRepository`, `MetadataProvider`, `PosterStorage`. Pure types, zero dependencies, zero I/O.
Then the application layer. The use cases. `LogReview`. `GetDiary`. `FetchMovieMetadata`. Just orchestration through the ports. At this point, the project had no idea what a database was. It didn't know HTTP existed. It was pure business logic floating in the void, and it compiled, and it was correct.
I always start here because the domain and application layers are the _soul_ of your software. They're the most stable part. They only change when business rules change, which, for a movie diary, is basically never. Everything else (database, web framework, storage) is just details. Adapters. If you get one wrong, you just unplug it and write another. You don't have to be nearly as careful with them.
Now, most languages let you enforce these boundaries: separate projects, separate assemblies, whatever your ecosystem calls them. The tools are there. But not everyone uses them. It's very tempting to just throw everything into one project and say "eh, I'll keep the layers separate by convention." And you will, for about two weeks, until it's 3 AM and you just need to quickly access the database from the domain layer, just this once, just a small thing, let me just add it here and be done.
I know myself. I know my lazy human brain would absolutely do that.
So I used the strongest guard I had: separate crates. Each layer, each adapter, its own crate. The domain crate _cannot_ import the SQLite crate. The compiler literally won't let it. Every port is a trait. Every adapter is a crate that implements that trait. No willpower required.
And it's not just about me. Maybe I'd stay disciplined. But if someone else ever contributes to this project, they don't have to know the rules. The compiler already knows them. Of course, in the end the ball is always in the programmer's hand. You can always work around anything if you really want to. But at least you have to _try_ to break it, instead of breaking it by accident.
Once I was happy with the soul of the app, I started plugging things in. SQLite for persistence. OMDb for movie metadata. Askama for HTML templates. Axum for routing. Each one its own crate, implementing the traits from the domain. By somewhere around midnight, maybe 1 AM (time gets fuzzy), I had a working movie diary. Register, log in, search for a movie, write a review, see your diary. Posters and everything.
A sane person would have stopped there. That was the widget. That was the whole original idea. Ship it, embed it, done.
But then I thought: _okay, but what about federation?_
---
## Down the ActivityPub rabbit hole
Remember the whole Fediverse tangent from earlier? Yeah, that came back to haunt me about four hours into the project.
I had a working CRUD app. Everything worked locally. And in that post-midnight, slightly delirious state of flow, my brain decided this was the perfect time to federate the thing.
I'm not insane enough to implement ActivityPub from scratch, though. There's a great Rust crate called `activitypub_federation` that handles the hard stuff: HTTP signatures, JSON-LD, inbox/outbox routing, WebFinger, all of that. My job was to wrap it and wire it into my project.
I ended up creating two crates, and this split wasn't random. Movies Diary wasn't the only project I had in mind. I was already planning other apps that would need federation, and I knew that if I mashed the protocol glue directly into this project, I'd be copy-pasting hundreds of lines next time around. So I split it: a generic `activitypub_base` crate that wrapped `activitypub_federation` with all the Axum boilerplate, and a Movies Diary-specific `activitypub` adapter that knew about my domain.
That bet paid off fast. `activitypub_base` later became its own standalone library, `k-ap`, and I reused it in _Thoughts_, my social platform project that I've been building on and off since 2024 (if you've read my [previous posts](/posts/my-2024-and-2025-roadmap), you know the one). ActivityPub integration was always on the roadmap for Thoughts, and thanks to k-ap, it was basically plug-and-play. HTTP signatures, actor resolution, inbox routing, all already done. I just wrote the adapter for Thoughts' domain types and federation worked out of the box.
Now, adding federation wasn't _free_. I did have to go back into the domain and application layers. New ports for tracking remote actors and followers, new events like `ReviewPublished` and `FollowReceived`, new use cases for incoming federation activities. The domain grew. But it grew cleanly. The existing code didn't break, nothing got tangled. The movie logging flow didn't suddenly need to know about ActivityPub. New federation ports just sat alongside the existing ones, and the adapters plugged in the same way as everything else.
By Monday morning, it worked. I could follow a Movies Diary user from Mastodon. Reviews showed up in my feed with proper hashtags. Other Movies Diary instances could federate with each other. Or, well, it worked well enough. The next two weeks were spent on, let's say, "spec compliance refinements." ActivityPub is a _fun_ specification to work with.
One thing worth mentioning though. Movies Diary is not a typical Fediverse citizen. Most federated apps are general-purpose. Mastodon handles any kind of post, Lemmy handles any kind of discussion. Movies Diary is opinionated. It _broadcasts_ to everyone: follow a Movies Diary user from Mastodon and you'll see their reviews in your feed, no problem. But incoming? If you try to send a random Mastodon post to a Movies Diary instance, it'll just quietly ignore it. It only accepts activities that are compatible with its domain: reviews, watchlist entries, stuff that actually makes sense for a movie diary.
That's deliberate. Movies Diary doesn't pretend to be a social network. It's a specialized node that speaks the common language just enough to participate, but stays true to what it is.
---
## So, what does it actually look like?
Enough talking. Let me just show you the thing.
![profile page](/posts/movies-diary/profile.webp)_User profile with diary entries, stats, and reviews_
![global feed](/posts/movies-diary/feed.webp)_The global feed showing reviews from all users_
![movie detail page](/posts/movies-diary/movie-page.webp)_Movie detail page with cast, crew, ratings, and reviews_
![watchlist](/posts/movies-diary/watchlist.webp)_The watchlist — add movies you want to watch later_
![review on Mastodon](/posts/movies-diary/mastodon.webp)_A review showing up in a Mastodon feed via ActivityPub_
![review in Thoughts](/posts/movies-diary/thoughts.webp)_The same review appearing in Thoughts, my other federated app_
![widget on personal site](/posts/movies-diary/widget.webp)_The widget embedded on my personal site's Movie Corner page_
---
## Was it worth it?
Since I started this project, I've watched three movies and logged every one through Movies Diary. Added three films to the watchlist. Reviews federate to Mastodon, posters get fetched automatically. I don't have to open my laptop, make a git commit, or touch a JSON file. Phone, few sentences, submit. Done. I love it.
Hexagonal architecture and DDD on a "pet project"? I stand by it. It's just the best way to write software. It makes sense from day one, it scales without pain, and it keeps things maintainable even when you keep bolting on features at 2 AM. I will keep building software this way for the foreseeable future.
And yes, I looked at Letterboxd, Filmweb, IMDb, complained about the state of things, and went ahead and built yet another one. I am part of the problem. But this one is _mine_. My data, my server, my rules. It federates, it's open-source, and it started with Matt Damon running from the CIA on a Sunday night.
I wouldn't have it any other way.
---
## Check it out
If you want to see the thing in action: [movies.gabrielkaszewski.dev](https://movies.gabrielkaszewski.dev/)

View File

@@ -1,21 +0,0 @@
---
title: "Hey Ho... I Am Alive"
description: "Adjusting to living alone, surviving a brutal school schedule, and squeezing in some coding between naps."
date: "2019-10-11"
---
Yeah, I know — I wasn't posting anything for a while. Honestly, I didn't expect such a big change in my life.
First of all, living alone (without your parents) is quite challenging. There are a lot of house chores I didn't notice before. The fridge becomes empty *very* quickly so I have to do groceries every two days. You're running short on flatware every time you want to prepare something to eat. It's not as great as you'd think.
School doesn't give me any slack either. I have a lot of math and physics. My daily routine looks something like this: wake up, grab something to eat (usually cornflakes), go to school, stop at the store on the way to buy lunch, sit through 78 hours of school, go back to the apartment, take a nap (sometimes 3 hours), prepare dinner, do homework and prepare for the next day's classes, take a shower, and finally go to sleep.
I don't have much time to code anything or practice singing or playing an instrument. This week I brought my harmonica and wanted to practice, but — no time.
Even though there are a lot of classes, my grades are not that bad so far. Tomorrow I have a very important math test and a Polish test. I honestly hate Polish as a school subject. It is so pointless and irritating. Nevertheless, I somehow managed to work a little on my video sharing website, and I'm quite proud of the result. It still looks ugly but I don't care about the frontend right now — the backend works perfectly.
HackHeroes started this week. It's an IT contest where contestants have to come up with an app that helps solve one of the global problems. I still have no idea what I want to build, but I'll figure it out.
Unfortunately, I stopped going to the gym. The reason is simple: no time, and no gym near me anymore. I was thinking about doing some in-house training but I haven't prepared a plan yet.
Anyway, it's already 2 AM and I still have a lot of studying to do. See you sometime in the future.

View File

@@ -1,15 +0,0 @@
---
title: "Hope"
description: "Math resit passed, test postponed, surviving on sleep deprivation with summer break just 26 days away."
date: "2019-05-15"
---
It's Wednesday afternoon — finally, half of the week is behind me. My Math resit went great and I got a better grade. Friday's test was postponed to next week, so I don't have any tests or pop quizzes until the end of this week.
But I'm really sleep-deprived. I don't sleep because I've got homework, the Erasmus project, and my job. On the other hand, I only have 26 more days to get through like this, and then I'll have a summer break. I can definitely do it.
Yesterday I watched *No Kiss List* and *The Outcast*. The Outcast was quite boring but No Kiss List turned out to be fine. My whole body is sore today because I went to the gym yesterday — my first training after almost a two-week break.
From now on, no more breaks. Summer is closer every day, and I gotta work on my body.
Okay, I think that's it for now.

View File

@@ -1,15 +0,0 @@
---
title: "I Got a Job!"
description: "Landing my first commercial programming job in the game dev industry — despite never wanting to work in game dev."
date: "2019-10-23"
---
So I finally got my first job. I'm obviously very happy, but the whole thing is a little ironic. I've always said I don't want to work in the game dev industry — and yet my first job is in the game dev industry.
I got hired as a programmer (obviously). Unfortunately I can't write much about it because I signed an NDA. But I can tell you that the job is great and it's good money. Of course, I'm happy for more reasons than just the pay — I'll finally have some commercial experience on my resume, which should make getting new jobs easier. Or at least that's what I hope.
My school life is also great right now. I passed all the exams and my grades are solid. Although I do miss hanging out with friends and summer parties — I don't have much time for those anymore.
So yeah, that was a quick life update. Have a nice day!
*(I really have to improve the formatting of these posts. Maybe I'll do it this weekend.)*

View File

@@ -1,15 +0,0 @@
---
title: "Interesting Friday"
description: "Doctor's visit, a new suit, pizza, and finally watching Avengers: Endgame."
date: "2019-05-11"
---
What a day. I slept only an hour today and didn't go to school because I had an appointment with the doctor. I waited for an hour because my mom got stuck in traffic. The doctor said everything is okay with me, so I'm happy. After the short visit we drove back to my city.
Tomorrow I'm going to my cousin's 18th birthday party and I didn't have a suit, so we went to the city center and bought me a new one. Then my sister and I went to some restaurant to get pizza. Weirdly I couldn't finish mine, which was strange because I was starving. Then I went home and as soon as I got there, I fell asleep. When I woke up it was 10 PM, so I finally watched Avengers: Endgame.
**Spoiler warning!**
I'm sad that the directors killed Tony Stark and not Captain America.
Okay, it's 3 AM now and I'll try to go back to sleep.

View File

@@ -1,17 +0,0 @@
---
title: "Interesting Weekend"
description: "Discovering Ron Pope, party games, watching a Bill Gates documentary, and ordering books."
date: "2019-10-27"
---
It's Sunday, 10 PM, and I sat down to write this post. This weekend passed so quickly. I don't remember anything from Friday to be honest — nothing really happened. Saturday was quite interesting: I was working, dealing with documents, and also did some house chores like vacuuming, cleaning dishes, and taking out the trash.
I started listening to Ron Pope, especially *Bitterness or Sympathy* and *One Grain of the Sand*. When I was in 4th grade I heard *A Drop in the Ocean* and really liked it, and this week while I was studying with Spotify in the background, those songs came on. I'm glad that happened. Thanks to Spotify's auto-play, I also discovered the AJR band a few years ago — and by the way, they dropped a new single this week: *Dear Winter 2.0*.
In the evening I had a party at my friend's house. We chatted, played some party games like spin the bottle and never have I ever. We also managed to dance what we call in Poland "Belgian dance." It was quite challenging because we did it in a very small room, but it was fun.
Today I was also working, and had a small chat with my coworker about deadlines. I watched one part of a documentary about Bill Gates and it motivated me to start reading books again. So I ordered *A Brief History of Time* by Stephen Hawking and *The Subtle Art of Not Giving a F\*ck*. I also watched *17 Again* — loved it. I love stupid comedies. So I watched another one: *American Pie 2*. Also great. Fun fact: I've never actually watched the original *American Pie*, so I'll have to fix that soon.
The upcoming week is going to be a piece of work. I have a few exams and I have to retake a Physics test and a recent Spanish pop quiz — both of which I failed. But I'll worry about that later.
To summarize: I'm happy and a little tired. That's it for now.

View File

@@ -1,17 +0,0 @@
---
title: "What Has Been Going On With My Life and Other Things..."
description: "Playing the DOS Dune game, Minecraft, web development, and rewriting a microservice."
date: "2019-07-22"
---
So July is coming to an end — well, not really, but half of it is already gone. For all that time I've been doing literally nothing. Hence the no new posts.
Today I discovered the old DOS game *Dune*, which is an adaptation of Frank Herbert's novel. I read that book back in April and it was amazing. Currently I'm on the third part of the series. Anyway, the game turned out to be really addictive. I spent 5 hours playing it today instead of Minecraft — which, by the way, I started playing again (thanks PewDiePie). Sadly, Dune keeps crashing at one specific mission and I can't progress anymore.
I did a little web development during the first week of July. I wrote my own blog platform. But I'm too lazy to finish configuring it for deployment, so I'm still using Blogger for these posts. Yesterday I rewrote a microservice for my music streaming platform.
Unfortunately I stopped going to the gym. I guess vacation time made me really lazy.
Last week I finished watching Stranger Things season 3. I was surprised because this season was actually good — I didn't like the previous one.
So I have no idea what else to write, so I guess bye until the next post!

View File

@@ -1,25 +0,0 @@
---
title: "Learning Spanish"
description: "Planning a Flutter app to gamify Spanish vocabulary learning because passive sitting in class just wasn't cutting it."
date: "2019-05-09"
---
Hello, it's me again. This is my 3rd post today. Anyway — this year I started learning Spanish, or I should say I signed up for Spanish classes at school, because I don't really *learn* there.
What I mean is that I attend the classes but I mostly just sit passively and listen to whatever the teacher says. So I decided to change my attitude. I was thinking for a while about how I can learn vocabulary and grammar in the fastest and most efficient way, and I came up with a solution.
Since I'm lazy and a programmer, I thought about making a simple app. A few months back I was making a game — an FPS shooter where, to destroy an enemy, you have to type the Spanish equivalent of an English word shown on the screen. I didn't finish that project, but I did make a tool that takes a CSV file with data and converts it into a JSON file. That way I can easily add words to a dictionary and parse it through the application.
The app itself will show me a new word (one in English, one in Spanish). But since I'm lazy and I really doubt I'll open the app every day, I'd have the option to add a widget to my home screen and have the app send me a daily notification. Might sound complicated, but it's not. All I need is a cup of tea and the Flutter docs.
I really need to start actually learning Spanish because:
1. I'd love to know this language.
2. It would boost my self-esteem.
3. I could brag that I know Spanish. 😂
So far I only know how to greet and introduce myself, read and speak, count, and describe my appearance or someone else's.
*Mi español es pobre.*
*Nos vemos más tarde, amigos!*

View File

@@ -25,8 +25,6 @@ But that wasn't all I did in the first month of 2024. I had this crazy idea to c
Next, I wrote a **Minesweeper** game in C++ using Raylib. That was pretty fun! The code, however, isn't really good—it's not idiomatic C++, more like C with classes—but the point of the project was just to have fun. Thats why Im not going to link the repo. However, if someone is interested, they can easily find it on my GitHub.
![minesweeper](/posts/minesweeper.webp)
## February - Small but Fun Projects
February, the shortest month of the year! I hopped from project to project, but some were actually finished and published.
@@ -39,28 +37,18 @@ You might ask, _Why use Rust for that instead of JavaScript?_ Great question! Th
Next, I started working on a **Missile Commander clone**—a recreation of the old Atari game **Missile Command**. I actually managed to replicate the core gameplay, but since Im terrible at designing games and coming up with new mechanics, levels, and features, I abandoned it pretty quickly. I even wrote a **level editor** for it! The game and editor were both written in Rust using **macroquad**, as I wanted to export it to the web. Unfortunately, I ran into some errors when trying to export and gave up.
![missile_commander](/posts/missile_commander.webp)
<Video src="/posts/missile_commander.mp4" />
## March - A Sokoban Game in Java
In March, I only worked on one toy project—a **Sokoban game in Java** using Raylib. Why Java? No idea. I guess I just wanted to refresh my skills in the language.
![Sokoban](/posts/sokoban.webp)
## April - The RTS Struggle
In April, I really wanted to create an **RTS game**. Unfortunately, I didnt succeed. Nevertheless, I made an attempt at creating an **RTS engine in Rust** using the _comfy_ crate. Later, I tried moving to Bevy, but pathfinding defeated me. I haven't given up on the idea completely, though—I may go back to it in the future, because I love RTS and strategy games so much.
<Video src="/posts/rts.mp4" caption="My failed RTS engine attempt" />
While researching RTS mechanics, I wrote my own **quadtree** in Rust and visualized it using Raylib. That was pretty fun and easy.
I also got into **ray tracing** and, thanks to _Ray Tracing in One Weekend_, I wrote my own **software ray tracer** in Rust.
![raytracer](/posts/raytracer.webp)
Another Rust project from April was an **Otodom scraper** with a frontend in React. Otodom is a website listing real estate for sale or rent, and since I was house-hunting, I needed a better way to filter available listings. So I wrote a simple service using _Axum_ that scrapes the data every ten minutes, allowing me to easily filter through listings.
Last but not least, I created **better_notepad**, a Notepad-like app because I was annoyed that the default Windows Notepad didnt close tabs when the app was closed. I wrote mine in C++ with wxWidgets. Later, I learned that you can actually turn that behavior off in the Notepad settings... oops.
@@ -69,16 +57,10 @@ Last but not least, I created **better_notepad**, a Notepad-like app because I w
In May, I started a **2D platformer in Unity**, inspired by **Brave Dwarves 2** (a childhood favorite). I focused on **composition over inheritance**, and I loved that approach—so much that I still use it in all future projects. Unfortunately, I abandoned the game.
<Video src="/posts/dwarves.mp4" />
I also built a **tiny social network** inspired by the late 2000s and early 2010s, when social media was more about you and your friends rather than memes, ads, and algorithm-driven feeds. My idea was simple: users could publish short thoughts (up to 128 characters), follow friends, and see only their friends' posts in the feed. I used Django, but I plan to rewrite it in Rust for lower memory usage. I might even make it **decentralized using ActivityPub**, because I recently fell in love with that concept.
<Video src="/posts/thoughts-2024.mp4" />
I also built my own **r/place clone** in Rust, using WebSockets via _socket.io_ and plain JavaScript for the client. It worked pretty well! However, I ran into an issue where I was sending data inefficiently, which caused massive memory usage—something like **~100MB per user connection**. I dont remember if I ever fixed it, but debugging network-related stuff is still a bit of a mystery to me.
<Video src="/posts/rplace.mp4" />
## June - A Grand Strategy Game Attempt
In June, I made another attempt at an **RTS/Strategy game**, this time a **turn-based grand strategy game** similar to _Civilization_. I used **Bevy** and the **hexx crate**, but as you can imagine, I didnt get very far—I got stuck on the turn system :p
@@ -91,22 +73,16 @@ In **August**, I experimented with **Godot** and started developing a **boomer s
This was yet another project I left unfinished. While I enjoy working with **Godot**, I found its 3D tools a bit too clunky for my workflow.
<Video src="/posts/boomer_shooter_attempt.mp4" />
## September - My Own Podcast Platform
In September, I built my own **podcast platform**! I wrote the backend in **Loco.rs** and the frontend in **Svelte**. I was really happy with how it turned out, but after recording just **one episode**, I lost interest. Shame.
<Video src="/posts/podcast.mp4" />
In the meantime, I created a **mod for VTOL VR**, which currently has **623 subscribers**! One day, I would love to create my own **VR game**, but for now, I have **zero ideas** for what it could be :&lt;
## December - Back to Game Development
In December, I tried **Advent of Code**, but I gave up after **three days** :p. Instead, I started working again on my **2D platformer game, Mr. Brick Adventures**. This time, I _vow_ to finish it and release it on **Steam**! Im using **Godot** again, and I have to admit—its quite nice for 2D development. I wanted to use Rust, but it was a bit too tedious, so I stuck with GDScript.
<Video src="/posts/mr_brick_2024.mp4" />
---
# 2025 Roadmap

View File

@@ -1,15 +0,0 @@
---
title: "My Life"
description: "Feeling sick before important exams and a party, reviving Twitter, and hoping to survive the night."
date: "2019-05-21"
---
Tuesday, 10 PM — I finally came back to being alive. I slept for 4 hours right after I came back from school.
Lately I've been having this weird cough but it didn't hurt or anything so I simply ignored it. But today after the second period I was shaking a little bit and didn't feel well. I still don't feel right — I have a headache and I'm pretty sure I have a fever. But I have to keep studying and pretend like I'm not sick for two reasons.
First, I have really important exams this weekend so I can't miss them. Second, my friend is throwing a party this Saturday and I really want to go — so I have to feel better by Friday.
Recently I also revived my Twitter account, so I'm quite active on social media these days.
That's it for today. To the next time... I hope I'm not going to die in my sleep tonight.

View File

@@ -1,338 +0,0 @@
---
title: "Qui Sumus"
date: "2026-07-20"
description: "Existence, immortality, and the irrelevance of both."
---
> *So God created mankind in his own image.*
>
> -- Genesis 1:27
# Preface
This is not a philosophy paper. I don't even know what this is. A very sophisticated, very pretentious form of shitpost, one could argue. Or me trying to look smarter than I actually am. But I wanted to write down some thoughts I have on the simplest concept in the universe, which is existence.
I have never read Plato. The closest thing to philosophy I've read is either *Animal Farm* or the Bible (not in full though). I've read *Harry Potter* fifty times in two languages. I'm a software engineer from Bytow. I think in systems. These thoughts have been forming in my head since I was about fourteen, alone, at night, staring at the ceiling. Nobody taught me this. Nobody assigned it. I just kept thinking and the thoughts kept connecting to each other until they became whatever this is.
# I. Pattern
I think identity, the thing that makes you *you*, is information. Not your body. Not your specific atoms. Not some mystical soul hovering above the machinery. It's the **pattern**. The specific arrangement and state of everything happening inside you: the neural connections, the chemical balances, the electrical signals, the memories encoded in protein structures. All of it, together, running. That's you.
Your body replaces most of its atoms every seven to ten years. The Gabriel writing this shares almost no physical matter with the fourteen-year-old who started thinking about this stuff. But I persisted. Because the pattern persisted. The hardware swapped out underneath me and I never noticed.
If that's true (and I suspect it is) then the body is a substrate. A medium. Like a hard drive. You don't care about the hard drive. You care about the data on it. The information.
---
If you snapshot the complete pattern, every connection, every state, every signal, and write it to a new substrate, and the original is gone, the copy *is* you. Not a clone. Not a replica. You. Because there is nothing else that *you* consists of beyond that pattern. There is no ghost left behind that the copy is missing.
If the original survives, then you have two entities. For one instant they are identical. Then they start having separate experiences and they diverge. Think of it like a git branch. Same commit history, different futures. Both are legitimate. Neither is more "real." They just forked.
Or if you prefer biology over software: homologous genes. A single ancestral gene duplicates, that's a paralog. Same origin, same sequence at the moment of duplication. But from that point on, each copy accumulates its own mutations, adapts to its own pressures, evolves its own function. Given enough time, the two copies become so different you'd never guess they started as the same thing. But they did. They share a root. They diverged.
Identity (or what I like to call the pattern) works the same way. Two copies of a person are paralogs. Same origin, independent evolution from the moment of the fork.
This doesn't make you less unique. Each fork is unique in its own right. They share a root, but they are independent from the moment they diverge.
---
There's an uncomfortable idea here: what if there's a gap, a moment where the pattern exists in neither the old substrate nor the new one? Maybe the snapshot sits on a shelf for ten years before a new body is ready.
I don't care about the gap. Here's why: from the perspective of the pattern, the gap didn't happen. You closed your eyes and opened them. Ten years passed for the world, zero seconds passed for you. It's the same as dreamless sleep. It's the same as anesthesia. It's the same as being shipwrecked for a decade and coming home. Disorienting, painful, but nobody questions whether you're still you.
The mechanism of the gap is irrelevant. Unconscious on an island, stored as data on a server. Same result. The subjective thread picks up where it left off.
This raises a question: what is your age, then? If you're stored inert for twenty years, did you age twenty years? I don't think so. No processing happened. No memories formed. No experience accumulated. The pattern was paused, not living.
Age, in this framework, is accumulated conscious experience, not elapsed calendar time. It's a runtime counter, not a wall clock. If a six-year-old's pattern is stored for twenty years and then restored into a thirty-year-old body, that person is six. They experienced six years of life. The calendar says twenty-six, the body says thirty, but the person inside is six. I'm not proposing a technical solution for how to track this on paper. I'm just saying that the honest answer to "how old are you" should be based on how long you've actually been conscious, not how long the universe has been turning since you were born.
---
If identity is the pattern and the body is just the substrate carrying it, then what we currently call death is not really the end of a person. It's data loss. The substrate failed and nobody had a backup. The person didn't "end" in some metaphysical sense, their storage medium broke. If you had a backup, they wouldn't have died at all. Death, in this framework, stops meaning "the end of a person" and starts meaning "the end of a substrate." The person persists as long as the pattern persists somewhere, in any medium. What we currently call death is just the worst-case scenario: total, unrecoverable data loss.
My dad died when I was ten. He was my best friend. That day sucked. Not having a father sucked. But he showed me in ten years what it means to be decent, to be loving, to be a friend to your kid. I would take that kind of dad for ten years over a bad dad for sixty. If I could have him back, I would. But it is what it is.
What stays with me isn't the grief. It's the *stupidity* of it. His pattern, everything he was, everything he knew, the way he laughed, the way he made me feel safe, all of that was lost because a bunch of cells in his body misbehaved. That's the reason my dad is gone. Not fate. Not God's plan. Unrecoverable data loss in biological hardware.
# II. Consciousness
Everything you experience, every memory, every emotion, every dream, every flash of recognition when you hear a song from ten years ago, is a physical event. Chemical reactions. Electrical impulses. Proteins folding. Neurotransmitters crossing synaptic gaps. There is no non-physical component. No soul, no spirit, no sacred spark that exists outside the chemistry.
As far as I understand, this isn't a particularly wild claim. But I don't think it's commonly followed to its logical conclusion. And the gut feeling that there *must* be something more? That's also chemistry. Consciousness being biased about itself.
---
Think of a cake. If you have the exact same ingredients, the exact same measurements, the exact same oven temperature and timing, you get the same cake. Not a similar cake. The same cake. (well, functionally the same cake, of course it won't be the same to the atom.) Because the cake doesn't come from some mysterious cake-essence floating in the kitchen. It comes from the ingredients and the process. Nothing else.
Consciousness is the same. The ingredients are the state: the neural architecture, the synaptic weights, the chemical concentrations, the accumulated memories, every physical detail of the brain at a given moment. The process is biology doing what biology does. The result is *you*. Your thoughts, your feelings, your next decision, your experience of being alive right now.
In software terms, this is what's called a pure function. Same input, always same output, no hidden variables. But you don't need to know programming to understand it. You just need to accept that consciousness doesn't pull from some secret external source. It derives entirely from what's already physically there. Reconstruct the ingredients, run the recipe, and the same person emerges. Because there is nowhere else for them to come from.
---
A common objection: is a reconstructed mind really "them"? But we already accept massive data loss as a normal part of being alive, and nobody panics about it.
You don't remember most of your life. Entire years are gone. You might watch a home video of yourself at seven and have zero recollection of that day. The memories that defined you at fifteen have faded or warped beyond recognition by the time you're thirty. Your personality shifts. Your values evolve. Your tastes, your fears, your sense of humor, all of it changes continuously, uncontrollably, without your permission.
And yet nobody says "the real you died somewhere around 2019 because you can't remember a Tuesday in March." We accept continuity of identity despite constant, uncontrolled degradation of the underlying data.
Here's the thing: right now, today, your brain is a lossy backup of who you were yesterday. And you're fine with that. You don't panic every morning because you've forgotten 99% of what happened last month. You still call yourself you.
So if a deliberate snapshot preserves *more* of you than your own brain does naturally, why would that version be less you? If anything, it's more faithful to the original than what biology is doing to you right now. Your brain is already a worse copy of who you were. You just don't notice because it happens slowly.
---
Does the reconstruction need to be absolutely, perfectly identical down to the last atom? No. Because even your own brain isn't identical to itself from one millisecond to the next. There's noise in the system at every level: thermal fluctuations, random neurotransmitter release, quantum jitter. Perfect fidelity is impossible even in the original.
This only works because the original won't be around. A copy continues you after you're gone. If both exist at the same time, they immediately become two different people, different environment, different inputs, different outputs. The copy doesn't replace you while you're still here. It picks up where you left off.
What matters is **functional equivalence**. If I feel like me from the inside, and the people who know me experience me as the same person, then I am the same person. If nobody can tell the difference, not me, not my friends, not anyone, then there is no difference.
# III. Death
We treat death like it's a law of nature. Like gravity. Like thermodynamics. Something fundamental and unchangeable that we simply have to accept.
It's not. Death is hardware failure. Your heart wears out. Your cells stop dividing correctly. Your telomeres shorten. Your organs accumulate damage faster than your body can repair it. These are mechanical problems. Specific, identifiable, physical processes that go wrong in specific, identifiable, physical ways.
We already fix some of them. A pacemaker is fine. A kidney transplant is fine. Replacing a valve in your heart is fine. But somewhere between "replace a lung" and "replace the whole body," there seems to be a line where it stops being medicine and starts being something else.
I think that line is cultural, not logical. We've been dying for three hundred thousand years and we built everything (religion, philosophy, inheritance law, retirement funds, the entire concept of legacy) around the assumption that everyone does. Remove death and all of those frameworks collapse. I suspect the resistance isn't about extending life being wrong, it's about it being destabilizing.
---
I don't want to make people immortal. That's not even possible. The universe is thermodynamically finite. Energy is limited. Stars die. Entropy wins eventually. You cannot truly solve death. On a long enough timeline, everything stops.
What I want is to move death from the category of *things that happen to you* to the category of *things you decide*. Right now, death is a natural disaster. It arrives uninvited. A car accident, a cancer diagnosis, a heart that stops at sixty-three, a blood clot at forty. You don't get a vote. You don't get a say.
I want people to get a say.
One person might choose to live for a hundred and twenty years and decide that's enough. Another might want a thousand. Another might want a hundred thousand. The point isn't the number. The point is that *it's their number*. They chose it. Death becomes a door you walk through when you're ready, not a wall you crash into without warning.
That's not immortality. That's **sovereignty** over your own existence.
---
A human body isn't built to last a hundred thousand years. The brain evolved for seventy, maybe eighty years of experience. Run it longer than that and it starts to fail. Memory degrades, cognition slows, the architecture wasn't designed for that kind of load.
The solution is cycling.
Think of it like a snake shedding its skin, except the snake is shedding its entire body. You live in biological hardware until it starts to fail, or until you simply want a change. Then you reprint a fresh body, transfer the pattern, and keep going. The mind accumulates centuries or millennia of experience, but the hardware never ages past its prime.
And the medium doesn't have to be biological at all. The body is just an interface. It's one way to run the pattern, but it's not the only way. You could run on a bio-chip, on silicon, on some networked device, serialized into a digital format, or something we haven't invented yet. The pattern is information, and information doesn't care what carries it. If it can be read, it can be stored. If it can be stored, it can be transferred. If it can be transferred, it can run on something else.
The technical challenge is enormous. But from a theoretical standpoint, there's no reason it shouldn't work. Information is information. The substrate is just the container.
You're like water. Same substance, different states. Ice, liquid, steam. Still water. Still you.
---
I want to be clear about what this doesn't solve. Extending life, even radically, even to thousands or hundreds of thousands of years, does not defeat entropy. The universe is cooling. Stars are burning out. Energy is finite and cannot be created.
This buys time. More Tuesdays. More breakfasts with the people you love. More years to build, to learn, to experience, to be present. And by my own framework (the one where the cosmic timescale is meaningless and the human timescale is everything) more time on the human scale is the only thing that actually matters.
You cannot live forever. But you can live long enough that death becomes something you chose rather than something that chose you. And that difference, between dying because your body failed and dying because you decided you were ready, is the difference between tragedy and dignity.
# IV. Two clocks
I operate on two timescales at the same time. One where nothing matters, and one where everything does.
---
Modern humans have existed for about three hundred thousand years. For two hundred and ninety-five thousand of those years, we didn't even write things down. In the last five thousand we made leaps that would be incomprehensible to our ancestors. Dinosaurs roamed the earth for over a hundred and sixty million years and never built a single thing. In about a billion years, the sun will expand and the earth will be gone.
On this clock, nothing matters. My life, your life, the greatest achievements of our species, they're rounding errors. The universe doesn't care. It doesn't care the way a rock doesn't care. Not with indifference, because indifference implies the capacity to care and the choice not to. The universe simply has no mechanism for caring. It's not hostile. It's not cold. It's just running. We happen to be inside it while it does.
I don't find this depressing. I don't find it scary. I find it obvious. It's like being told water is wet. Yes. And?
---
On the other clock, the one that runs for seventy, eighty, maybe a hundred years, everything matters. Every moment has weight. A Tuesday in September where nothing happens and you just sit on a patio with someone you love, that matters. A phone call with your mom where she complains about something trivial, that matters. A child laughing so hard no sound comes out, that matters more than anything that has ever happened in the history of the universe.
Not because the universe assigns it meaning. The universe doesn't assign anything. It matters because I experience it. Because I'm a thinking animal who can hold both clocks in my head and *choose* to care about the small one. A dog lives entirely on the human clock. A rock exists entirely on the cosmic one. I'm the thing in between that sees both and decides, consciously, deliberately, that the breakfast I make tomorrow morning is more important than the heat death of the universe.
That decision, caring *despite* knowing it doesn't matter cosmically, is not irrational. It's the most rational thing a conscious being can do. Because the cosmic clock is not actionable. I can't do anything about entropy. I can't stop the sun from expanding. I can't add meaning to the void. But I *can* make breakfast. I *can* show up. I *can* be present for the people I love for the limited time we overlap on this rock.
Choosing to act on the timescale where action is possible is not delusion. It's pragmatism.
---
Apparently, discovering that the universe is meaningless is supposed to be a crisis. Philosophers have written entire books about whether you should kill yourself over it. I've heard it's a big deal.
I never had that moment. Not because I'm tough or special. I just never had the expectation that the universe owed me meaning in the first place. I didn't start from "life must have purpose" and then discover it didn't. I started from "I'm here, I didn't ask to be, let's see what happens." The absence of cosmic meaning was never a loss because I never assumed it was there.
If there is any biological "purpose," it's reproduction. Pass your genes on, and you've done what evolution designed you to do. Everything after that is a bonus. It's your choice. You decide what matters, what to pursue, what to care about. The universe doesn't hand you a mission. You write your own or you don't. Either way is fine.
It is what it is.
---
Given the choice between existing and never having existed at all, I would choose never having existed. Not because my life is bad, it's actually quite good. But existence is a package deal I didn't negotiate. Nobody asked me. I was just here. And no matter how good life gets, suffering is inevitable. It's built into the system. So from a purely pragmatic standpoint: why sign up for guaranteed suffering when non-existence costs nothing? There's nobody in non-existence to miss the good parts.
This isn't depression. It's arithmetic. The absence of pleasure is not a tragedy when there's no one to be deprived of it. The presence of suffering is always a cost, no matter how small.
Though, if pattern persistence were real, if people I love didn't have to disappear because their hardware failed, if I could have more time with them instead of losing them to biology's schedule, my answer might be different. The calculus changes when existence stops being a trap with guaranteed loss. A world where you don't have to bury your dad at ten because nobody bothered to back him up, that's a world where existence might actually be worth choosing.
But I *am* here, in this world, the one without backups. The choice was made without my consent, and I can't undo it. So I play the hand I was dealt, and I play it well. I love people. I build things. I eat good food and argue about stupid things with my friends and stay up too late and feel the sun on my face. Because once you're in the game, refusing to play doesn't undo the fact that you're playing. It just means you're playing badly.
---
Every thought in this document traces back to one thing: **agency**.
No human being chooses to be born. No human being chooses when they die. Our identities are trapped in hardware we didn't design that degrades without our permission. We are assigned consciousness without a manual or a warranty.
These aren't personal complaints. As far as I can tell, this is just the deal: existence imposed without consent, death imposed without consent, and a body that fails on its own schedule regardless of what you want.
Everything I've described in these pages (identity as transferable pattern, consciousness as preservable data, death as an engineering problem, existence on two clocks) isn't about what *I* want for myself. It's about what I think every conscious being deserves: the ability to choose.
Every person should get to decide. About their body. About their mind. About how long they stay. About when they leave.
Not the universe deciding for them. Not biology. Not God. Not the government. Not culture. Not tradition. *Them*. Each individual, for themselves.
Agency isn't a privilege for the smart or the rich or the lucky. It's a right that belongs to every person who can understand the question "do you want to continue?"
And here's the paradox I can't resolve: nobody asks to be born. They can't. It's impossible. You cannot consent to your own creation because you don't exist yet to give consent. That's not a flaw in the system, it's the system. The one act that determines everything about a person's existence is the one act they have zero say in.
And I would do it anyway. If I were in love, truly in love, and that love was strong enough that we felt this need to create a life, to make a person we would adore and guide and let explore the world, I would do it. Knowing everything I've written in this document. Knowing that by creating a life out of our own selfish need to love someone new, we condemn them to suffering. Because suffering is built into existence, and we'd be signing them up without asking.
That's the contradiction I live with. I believe agency is the most fundamental right a conscious being has. And I would violate it at the most fundamental level, at the very beginning, because I wanted to be a father. I don't have a justification for that. I just have the honesty to say it.
# V. Directed evolution
This is the section where I contradict myself. I'm doing it openly because honesty about the contradiction is more useful than pretending it doesn't exist.
I'm not a geneticist. I don't run a lab. I don't have the resources or the authority to do any of what follows. This is a thought experiment, a thing I think about late at night when my brain won't shut off. But thought experiments are how I process the world, and this one has been sitting in my head since I was about sixteen, so I'm writing it down.
---
We already direct evolution. We've done it for thousands of years. We bred wolves into dogs. We turned wild grasses into wheat that feeds billions. We engineered crops to resist disease, survive drought, and grow in soil that would have killed their ancestors. We modify bacteria to produce insulin for diabetics, to synthesize proteins, to manufacture things our bodies need but can't make on their own. We call it agriculture, GMO, biotechnology. We celebrate it because it works and it saves lives.
The same principle applied to humans is called eugenics, and it carries a hundred years of horror behind the word. Forced sterilizations. Death camps. Entire populations designated as inferior and eliminated. The history is real and it's monstrous and it should never be minimized.
But the principle underneath, that you can improve biological outcomes through deliberate selection, didn't become wrong because terrible people used it terribly. Fire isn't evil because someone committed arson. The question isn't whether directed evolution works. It's whether it can be done without the cruelty.
---
Imagine a technology that allows genetic editing of embryos. A couple is expecting a child. Someone sits them down and offers: we can remove the gene that causes Down syndrome. We can reduce the predisposition to autoimmune disease. We can nudge the baseline for empathy slightly higher. For critical thinking. For compassion.
Most parents would say yes.
That's the design. Every individual choice is voluntary, informed, and reasonable. No one is forced. No one is sterilized. No one is told their genes are inferior. Every parent is simply asked: do you want the best possible starting conditions for your child? And they say yes, because of course they say yes.
Do this for twenty generations. Sixty generations. The gene pool shifts. The species baseline moves. Slowly, imperceptibly, one voluntary decision at a time, humanity becomes different. More empathetic. More thoughtful. More capable of the kind of thinking that prevents atrocities rather than enabling them.
Every individual chose freely. And the cumulative result was designed from the start.
---
I know what this is. It's an illusion of choice. Each decision is real. The overall direction is engineered. Individual agency is preserved at the micro level and subverted at the macro level. Nobody voted on "should we redesign the species." They just each said yes to their own kid, one at a time, until the species was different.
If I were in a position to do this, it would make me a hypocrite. My entire framework is built on agency, every person's right to choose for themselves. And this system technically preserves choice while ensuring the outcome was never in question.
I'm aware of the structural parallel. Every person in history who tried to steer human evolution believed they were doing good. Every one of them was certain their values were the right values. The conviction of righteousness is not evidence of righteousness. I know this. The position I'm describing is structurally the same one they held. The difference is method: voluntary, non-violent, individually consensual. The difference is values: empathy, compassion, critical thinking rather than racial purity.
But so did they. They all trusted their values too.
---
The clean answer, the one that resolves the contradiction, is simple: don't do it. Nobody has the right to decide what humanity becomes. Stay in your lane. Let evolution take its random walk. Accept that suffering and stupidity and cruelty are the price of freedom.
I think about that answer often. And still there's a thought, a tiny but not suppressible voice in my head that nudges me, that convinces me that I might be right, that it's not as bad as it sounds.
First: because standing by while preventable suffering continues, because someone was too principled to act, feels worse than the hypocrisy. I would rather be a hypocrite who reduced suffering than a consistent philosopher who watched it happen and said "well, it's not my place."
Second: because the technology will exist eventually. We already modify bacteria in labs to produce what we need, I've seen it done in college. The jump from editing microorganisms to editing human embryos is a matter of complexity, not principle. Sooner or later, someone will have the capability. And if someone with good values doesn't shape how it's used, someone with worse values will. Someone who might use the same tools, the same rhetoric, the same voluntary-at-the-individual-level framework, and steer humanity toward obedience instead of critical thinking. Toward tribalism instead of empathy. Toward control instead of freedom.
Inaction is not neutral. It is ceding the field to whoever comes next. And if I had to choose, I would rather a vision built on empathy and compassion shape the species than wait and hope for the best.
The traits I keep coming back to (empathy, critical thinking, compassion) are not arbitrary preferences. They are, as far as I can tell, objectively net positive (yes, I hear the oxymoron). A more empathetic, more thoughtful humanity doesn't lose the mess of being human. People with more empathy can still be selfish. People with better critical thinking can still believe stupid things. The freedom to fail, to struggle, to be imperfect, all of that stays. The floor just rises.
And I believe, knowing it would make me a hypocrite, knowing the structural parallel to history's worst actors, knowing it violates my own framework, that a higher floor is worth it.
This is a tension I choose to sit with rather than resolve. Because resolving it means either abandoning the principle of agency or abandoning the idea. And when I'm honest with myself, late at night, staring at the ceiling, I'm not willing to do either.
# VI. The boundary
Everything in this document (identity, consciousness, death, agency, evolution) is theory. Ideas I turn over in my head at night. Thought experiments I run when the ceiling gets boring. Most of it may never matter beyond these pages.
But this section isn't theoretical. This is the one non-negotiable rule I hold. The floor beneath every other position. The thing I will not bend on regardless of context, regardless of who's involved, regardless of what they've done.
---
You can think whatever you want about another person. You can think they're stupid. You can think their beliefs are absurd. You can think you're smarter, more capable, more correct. I certainly do, about a lot of people. I'm a classist. I think less of people who don't think critically. I look down on certain worldviews. That's my bias and I own it.
But thought is not action. The moment it crosses from what you think to what you do, the moment you deny someone's right to exist, the moment you treat them as subhuman, the moment you decide your superiority gives you permission to harm them, you've crossed the only boundary that actually matters.
**No exceptions.**
Not for criminals. Not for dictators. Not for people who themselves violate this principle. Nobody forfeits their right to exist. You can punish. You can imprison. You can ostracize. You can sanction. You can remove someone from society to protect others. But you don't kill them. Because the moment you claim that authority over someone else's existence, you've put yourself above them. And then you're not better than them. You're the same thing.
---
The line works both ways.
You can't kill someone, that revokes their existence without their consent. But you also can't force someone to live, that revokes their agency over their own exit. Forcing someone to stay alive against their will is the same category of violation as forcing someone to die. Both are impositions on someone else's sovereignty over their own existence.
You don't get to decide for another person whether they exist. In either direction. That decision is theirs. Only theirs. Always.
---
This is where my framework produces its most uncomfortable output, and I want to be honest about it rather than hide it.[^1]
[^1]: To be clear: I am not advocating for suicide. I am not giving anyone permission. If you are struggling, please talk to someone. What follows is a philosophical position about the principle of sovereignty, not advice.
If sovereignty over one's own existence is absolute, then that includes the right to end it. Logically, consistently, unavoidably. Otherwise sovereignty is conditional, and conditional sovereignty isn't sovereignty at all. It's permission granted by someone else who can revoke it whenever they decide you're not thinking clearly enough to exercise it.
I have never personally experienced the desire to end my own life. I cannot imagine it. I don't understand it from the inside, and I won't pretend to. So my position here comes from the framework, not from empathy, and I acknowledge that limit.
The standard response, we stop someone because they're in crisis, because it's a permanent solution to a temporary problem, because it gets better, is built on an assumption. Probably a correct assumption in most cases. But an assumption nonetheless. We override someone's stated decision about their own existence based on our belief that we know better than they do about their own life.
I don't have a clean answer here. I don't think one exists.
What I keep coming back to is something like this: if you love someone, truly, as a free and sovereign person, then part of that love is accepting that they can leave. That their existence is not your property. That the grief you would feel is not evidence that they were wrong, it's evidence that the connection was real. The price of loving a free person is that they might use their freedom in a way that destroys you.
That's a deeply uncomfortable thing to write down. It sounds like indifference. It isn't. It's the opposite, a form of respect so total that it extends even to the decision you most desperately want them not to make.
But I also know that no matter how carefully I phrase this, in a world where people are actively suffering, where families are actively grieving, it will sound wrong. Because the socially required response is "please stay," and anything else, no matter how philosophically consistent, will land as cruelty.
This is the one place in the framework where I hold the position and simultaneously understand why people hear it and call me a monster. I don't have a resolution. I just have the honesty to say: this is where my logic leads, and I'm not comfortable enough with it to pretend I am, but I'm not willing to abandon the principle to make it easier to say out loud.
---
I will tolerate anyone's existence unconditionally. I will not tolerate their ideas unconditionally.
Fascism, nazism, nationalism, any ideology rooted in the reduction of someone's liberty is **despicable** to me. There is **no nuance** here. No good faith argument. No "well actually." Slavery was not good because it gave people housing. Hitler was not good because he built roads.
---
And right now, in Poland, in 2026, people are assaulting Ukrainians on the street because they heard them speak Ukrainian, or because the Ukrainian government did something unpopular, as if the actions of a government justify punching a person at a bus stop. A nation of forty million people and some "patriots" decide the whole country is guilty because of what a few individuals did. And yes, I know about Wolyn. I know about the crimes committed against Poles by Ukrainians. I don't minimize it. I don't condone it. Crimes against humanity are crimes against humanity regardless of who commits them. But the person walking down the street in Gdansk speaking Ukrainian in 2026 is not the person who did that in 1943. They weren't there. They didn't do it. Punishing someone for what someone else did eighty years ago because they share a nationality is not justice. It's collective punishment, and collective punishment is the tool of every regime I just listed above. That's not patriotism. That's the same pattern it's always been, just wearing a different flag. There is no "X was actually fine because Y" when X involves treating human beings as less than human. **No. Just no.**
If someone holds these views, if they advocate for the subjugation, dehumanization, or elimination of other people, I have zero obligation to give them a platform, to engage with their arguments, or to remain silent while they spread harm. Tolerance of existence is non-negotiable. Tolerance of bullshit is not.
You get to be here. You get to breathe and eat and live and die on your own terms. You don't get agreement. You don't get a megaphone. You don't get my silence.
---
In a framework where the universe is meaningless, where identity is transferable, where death is an engineering problem, where I've admitted I would hypothetically steer human evolution and acknowledged the hypocrisy, this is the anchor.
Because without it, everything else becomes dangerous. Intelligence without this boundary is manipulation. Power without this boundary is tyranny. Directed evolution without this boundary is the Third Reich. Every tool I've described in this document, every idea about consciousness and agency and genetic optimization, is only safe if this floor exists underneath it.
You don't get to decide who deserves to exist. You don't get to decide who has to stay. The only person whose existence you have authority over is your own.
# Closing
But what do I know.
I barely consider myself an adult. I still watch cartoons and I like sci-fi. I eat frozen pizza for dinner more often than I'd like to admit.
I'm not a philosopher. I'm not a visionary. I'm not someone you should do a deep analysis of or write a thesis about. I'm a twenty-four-year-old software engineer from Bytow who makes a living writing code and spends too much time staring at ceilings.
This document is just a more or less coherent stream of thoughts that have been forming in my head since I was about fourteen. They started as fragments, a question about what happens when you die, a frustration with the answers people gave, a suspicion that nobody actually knows anything and most of them aren't honest about it. Over the years the fragments connected, one idea pulling the next one out, until they became whatever this is.
Some of it might be wrong. A lot of it is probably incomplete. I've apparently been independently reinventing philosophers I've never heard of, which either means the ideas are obvious or I need to read more books that don't have wizards in them.
The only thing I'll defend without qualification is the boundary, the part about not claiming authority over someone else's existence. Everything else I hold loosely. I could be convinced otherwise. I'm not attached to being right. I'm attached to being honest about what I actually think, even when it's ugly, even when it makes people uncomfortable, even when the normal thing to do would be to nod and say something safe.
*Qui sumus*, who are we? I don't know. I don't think anyone does. But I'd rather sit with the question honestly than grab the nearest comfortable answer just to make the silence stop.
*Gabriel Kaszewski*
*Gdansk, July 2026*

View File

@@ -1,17 +0,0 @@
---
title: "Quite Active Friday"
description: "Skipped the date but had a great gym session, swam at the lake alone, and caught a breathtaking sunset."
date: "2019-06-15"
---
So I didn't ask my crush out. Apparently she came to Gdańsk with her friends when I was on the train back home, so we couldn't really meet.
Instead of going on a date, I went to the gym and had an amazing training session. I did my usual full body workout and some abs exercises, but today was different — after my routine I did cardio and some boxing. I have to say, I loved punching the punching bag. I'm considering training boxing for real. It could be useful, and it's a great exercise for improving physical condition. Also, when you're punching a bag, you can completely blow off steam you've gathered over a whole week. That's amazing.
After the gym, I finally got my bike from the basement and rode to the lake. Unfortunately I was alone there because some of my friends were with my crush in Gdańsk and others weren't available. So I swam for a while and rode back home.
On my way back I saw such an amazing sunset. It was the most breathtaking view I've seen this year. I was really upset that I didn't have my DSLR camera with me. Well, I didn't lose much — every summer I have this view, so I'll take a picture of it someday and post it here.
When I got back I made myself a second dinner: scrambled eggs with beef steaks and a strawberry milkshake my mom made before. After that I worked a little on my game, and now I'm writing this post while waiting for Flutter to finish updating so I can implement new features to my app. After that I want to start coding a brand new app — more info on that later.
So to sum up: no date today, but I did awesome things anyway. I see this as an absolute win.

View File

@@ -20,14 +20,14 @@ Nevertheless, Rust got me interested and I feel like writing some simple 2D game
The second technology is **Machine Learning**. Machine learning has become more and more popular lately; the famous [Chat GPT](https://chat.openai.com/), or [stable-diffusion](https://stablediffusionweb.com/), [MidJourney](https://www.midjourney.com/) and many other machine learning projects. Machine learning has interested me a lot since middle school, but somehow I can't grasp it. I understand the theory and how neural networks work, but I can't create a model that recognizes how many fingers we show, for example. I'd like to grasp this eventually and create one project I've been considering for about a year. It's a project that involves automatic audio de-noising, I know [OBS](https://obsproject.com/) has such filters, although I'd like to make my own software for this, yes for educational purposes. My next project is to automatically create .srt files based on song lyrics and audio. In January I created a [mod](https://github.com/GKaszewski/BeatLyrics) for [BeatSaber](https://beatsaber.com/) that adds song lyrics, unfortunately, the mod requires an srt file with the given time and lyrics. I would like to automate the process of creating these files, just using artificial intelligence to do it.
![ai-generated-image](/posts/K00zak_pixar-style_puppy_chasing_its_tail_with_transparent_back_9e3efbe7-0427-42db-b71a-902ddf60f40c.png)_A dog generated by MidJourney AI_
![ai-generated-image](https://gabrielkaszewski.dev/media/K00zak_pixar-style_puppy_chasing_its_tail_with_transparent_back_9e3efbe7-0427-42db-b71a-902ddf60f40c.png)_A dog generated by MidJourney AI_
The last thing is **game dev** in a broad sense. Creating games in **_Typescript_**, making some games in VR in [Unity](https://unity.com/), finishing a clone of **_Sammy Suricate_**, and super if I could make some simple strategy game. I love RTS games.
![sammy-clone](/posts/screenshot-2022-12-28T19-05-22-0041341Z.png)_My Sammy Suricate clone. Made in Unity_
![sammy-clone](https://gabrielkaszewski.dev/media/screenshot-2022-12-28T19-05-22-0041341Z.png)_My Sammy Suricate clone. Made in Unity_
### Conclusion (none)
That's pretty much it at the moment, it's pretty late and I think I'll keep updating this post as something else pops into this crazy head of mine. For now, this is my farewell to you and I wish you a good day.
![cat](/posts/cat.jpg)_Aaaaaand this is my cat. Piernik ✨_
![cat](https://gabrielkaszewski.dev/media/cat.jpg)_Aaaaaand this is my cat. Piernik ✨_

View File

@@ -11,7 +11,7 @@ In the previous post I have written that I would have wanted to get into Rust. I
Okay, so the first 'project' that I did in Rust was a simple program that creates Mandelbrot's set image. The code for that was provided by the book _Programming Rust: Fast, Safe Systems Development 2nd Edition_
I did it because it seemed cool and in High School I made similar program but in Java.
This one was more interesting because it used multithreading.
![mandelbrot](/posts/output.png)
![mandelbrot](https://gabrielkaszewski.dev/media/output.png)
But that was just a **hello world** program, I did not write my 'own' code.
**Repo:** [mandelbrot](https://github.com/GKaszewski/mandelbrot)
@@ -38,8 +38,6 @@ Repo: [screensaver](https://github.com/GKaszewski/screensaver)
The last project that I have been working on is asteroids game. It is actually just a remake of my C project (I used SDL2 for that one). In this one I am using **Bevy engine** and I have to admit it is pretty handy and straight-forward to use. I love the data driven design. I have yet still to add HUD, power-ups, boss fight and second-player feature to the game and then I will publish it on my website. In the future I am planning to make my first **commercial game** with Bevy. But we will see.
![asteroids](/posts/asteroids2.webp)
### Conclusion
Rust is fun, I had no idea that I would find myself in that language but I am pleasantly surprised. Same thing was with Python 😜. I really love the eco-system of Rust. Cargo is just the best. I hated in C and C++ the linking and compiling of external libraries and setting up the toolchain, in Rust all of those problems just fade away. The match feature is also cool.

View File

@@ -1,15 +0,0 @@
---
title: "School Trip"
description: "Writing from a hotel in Poznań, exhausted from sightseeing, and planning to finally ask my crush out."
date: "2019-06-11"
---
So I haven't been posting anything new for a while. Honestly, I don't have much time lately — every weekend I go out with my friends or go to parties. My social life is quite decent now and I'm really glad about that.
Right now I'm lying on the bed in my hotel room. I'm in Poznań on my school trip. The trip is actually pretty good. I'm exhausted from walking and visiting a lot of buildings, but the vibe is good and the weather is great. Today it was 93°F — that's insane. Tomorrow is going to be at least 96°F. I think I'm gonna melt.
But honestly I can't wait to get back to Gdańsk. I'm going to ask my crush out, so I'm excited and terrified at the same time. I'd be so happy if she said yes. I hope I find the courage to actually do it on Friday.
The thing I'm most worried about is that our relationship will get worse if she says no. But whoever doesn't take action doesn't really know what life is about — or something like that.
Wish me luck, and hopefully I'll write about my amazing date on Friday night.

View File

@@ -1,23 +0,0 @@
---
title: "Solved Problem"
description: "A breakthrough in socializing, realizing conversations work differently than I thought, and reflecting on work habits."
date: "2019-11-07"
---
Today a magical thing happened. I accidentally solved my problem with having conversations with people.
I've always had trouble starting a conversation with anyone. I thought that asking questions like "how are you?" or "how was your day?" was stupid because they didn't give me any valuable information. So by thinking that way, I struggled with socializing.
But today I came to the realization that this is completely normal — asking casual questions. And this is brilliant. If I know how to start a conversation, I can talk with people more often, and I'll be less awkward around them. What's more, I boosted my self-esteem and started caring less about what people think about me. Previously I didn't really care either, but I wasn't very confident or sure about my actions.
I also realized that girls are actual human beings. I know that sounds weird, so let me explain. When I was talking with a girl, I had some filter on — I was choosing my words very carefully for no real reason. But recently I stopped doing that, and the results are awesome. You can actually just have a normal conversation.
I watched *The Society* and it gave me a lot to think about. I really didn't expect to come away with thoughts from a teen drama TV show. I kept thinking: how would I and my friends deal with a similar situation?
I've slowly started to regret some of my life decisions. I have a job and that's great, but I am so not qualified for it. I know how to code and I think I'm a decent coder, but the job turned out not to be about coding that much. There are so many things I wasn't prepared for.
Also, school gave me bad habits around deadlines — I'm used to doing all my homework or school projects just one day before the deadline. And that is **so wrong** in the real world. I need to start sticking to my schedule.
So I have a few things to work on. One: I have to really get to work. Two: I have to prepare my TED Talk for the Erasmus thing. Three: I have to finally ask my crush out. Hopefully I'll do all of it by the end of November.
See ya!

View File

@@ -1,19 +0,0 @@
---
title: "Summer Time"
description: "Missing friends during summer break, working on games, a birthday party, and discovering Jon Bellion and classical music."
date: "2019-06-30"
---
The second week of my vacation has just started, and I have to admit — even though I have summer break — I don't feel as happy as I thought I would. I guess the problem is the absence of my friends. Some went to various summer camps, others are working, so we can't hang out together.
Nevertheless, I managed to finish my Spanish learning game last week. Now I'm working on a Pepsiman remake with a friend. I'm also still working on my other projects like my game engine and some other things.
Yesterday I was at my cousin's 18th birthday party and it was a really great one. This time I wasn't the photographer — my ex-classmate from junior high took that job. I talked with her about some stuff and danced with her and obviously other people too. I don't really like dancing because I just don't know how to dance. But if it's a party, you've got to have fun, so dancing is what you do.
Sadly I haven't been to the gym since June 15th. This makes me sad. I can't motivate myself to go. Even though I really want to, it's 90°F so I spend most of my time at the lake, and when I come back I'm too tired to go. Maybe it'll change this week.
Recently I started listening to Jon Bellion and — wait for it — classical music. It's really weird. I've never liked classical music, but a few days ago when I was sunbathing on the patio I thought: let's try some classical music. And since that moment I listen to it. It turned out it's not as bad as I always thought.
And Jon Bellion's music makes me really happy. My favorites are Stupid Deep (acoustic version), 80s Films, and Human (acoustic version).
So that's it for now. How is your summer break?

View File

@@ -1,21 +0,0 @@
---
title: "Task Failed Successfully"
description: "Getting rejected but feeling accomplished anyway, and figuring out that having money is surprisingly hard to manage."
date: "2019-11-21"
---
I was meaning to write this post last week but I got caught up in homework and work, so I'm writing it now.
Last week was wonderful. I finally got enough courage and asked out my crush. You're probably curious about her response — well, she said no. She said she didn't want to date anyone at that moment, so I got rejected. But I was quite happy with the result. I mean, I finally asked somebody out. The feeling of overcoming your fear is awesome. By doing it I boosted my confidence so much.
My cousin's daughter had her 1-year birthday party on Saturday, so naturally we went. I actually enjoyed my time there — I talked to my uncle about my job and economics.
This week, on the other hand, was strange. I was feeling weird. Last week I had been feeling somewhat accomplished and full of joy. But this week was completely different — I didn't have any goal to accomplish, which could explain the weird feelings. I got some not-so-great grades and had two difficult tests.
But I also got paid yesterday, and oh man... that feeling when you get your payment is so joyous I honestly can't describe it. You have to experience it yourself.
And with it, I found a new problem to solve. I started spending money like water. The problem is that I have a fairly nice bank balance at the moment, and when I spend 100 or 50 PLN, I don't see that much change in my account. So my brain thinks I'm not spending much and proceeds to spend even more. And **this is bad**.
I guess I have to get used to having a little more money than I've ever had before.
So the last two weeks flew right in front of my eyes. Thanksgiving is next week but my family doesn't celebrate it, so I'm just waiting for Black Friday — maybe I'll buy something cool this year.

View File

@@ -1,15 +0,0 @@
---
title: "The Final Week!"
description: "Erasmus visitors, a massive house party, and just two tests left before summer freedom."
date: "2019-06-02"
---
Hello everybody! I haven't posted anything new for a while — it was caused mostly by my social life and school. I'm so glad that I started going out with my friends again on weekends. I really missed it.
Last week I had the Erasmus thing going on at school. I have to admit, my English wasn't that bad compared to the Italian and Portuguese guys. Also last week I was at an amazing party at my friend's house. It was supposed to be a small gathering but it turned into a really big one — instead of 30 people, almost 40 came. And it wouldn't have been that bad if they hadn't brought gallons of alcohol. I actually didn't drink much through the whole party. Right at the beginning I drank the beer I had bought before, and later I didn't drink anything. So I was sober through the entire event. I helped my best friend keep the house safe, talked with my friends, and helped one of them down the stairs. To summarize: the party was great.
The week after the party wasn't the best, but I made it through. That Erasmus thing was really interesting and I'm definitely going to take part in such an event next year. It's a lot of fun and you get to meet people from different cultures across Europe. I really liked the Dutch students — their English was decent and they were friendly. They tried to teach me some Dutch but failed. It's impossible for me to pronounce those sentences.
This week is my **final week** with tests. I only have two more and then I'm completely free. After Wednesday I can chill by the seashore. Can't wait to come back home. I'm going with some friends to a lake to play volleyball and swim, and later we'll probably set a campfire. Also during this week I'm probably going to work a little on my game.
I hope tomorrow's Physics test will be easy. That's it for tonight.

View File

@@ -1,37 +0,0 @@
---
title: "What Have I Been Up to Lately?"
description: "Four months of life updates: losing and gaining a job, turning 18, writing audio software, and a birthday party."
date: "2020-02-24"
---
My last post was a very long time ago — four months to be exact. During that period I lost my job but got another one, became an adult, got addicted to Minecraft again, lost interest in ukulele (which I'd picked up during Christmas), wrote audio recording software, and became more attractive and handsome. I'd had no idea that was even possible. I was already perfect. (/s)
But let's start from the beginning.
## December
The first half of December was pretty terrible. There were a lot of tests and I had a lot of stuff from work on my plate. We were running 2 weeks behind schedule and there were a lot of unresolved tickets. I couldn't keep up with Math, Physics, and work at the same time. I knew I had to drop either my education or work. That problem ended up solving itself at the beginning of January — more on that later.
The second half of December was much more pleasant. First: Christmas break — no school. Second: I love Christmas season because my entire family gathers at my grandparents' house and there's this friendly, loving vibe everywhere. The smells are great. It's just magical. Third: I was playing Minecraft constantly and enjoying it like I did when I was a little kid back in 20112013.
The last night of that decade I spent at my friend's house at a New Year's party. There were a lot of people — my friends and their friends. The party was great.
## January
Which brings us to January 1st... oh boy, it was a very busy night. I came back home around 11 AM, sat down at my desk, and played Minecraft. Around 5 PM I packed my stuff and went back to my friend's house because we were heading back to our apartment in Gdańsk for school. I was pretty hungry — I hadn't eaten anything all day. When we got to the apartment I made myself french fries and grabbed a diet coke from the fridge. Then I went to sleep.
A week and a half after the Christmas break we had another one: Winter Break, which lasted two weeks as usual. During that break I hung out with friends and slept through most of it. Oh, and I got another job — this time making a website for the dental clinic where my mom works. After the break there were those exams again. Obviously I passed all of them. I did have to retake one Math test about polynomial equations and inequalities, but I got a 4 from the retake, which was nice.
My music taste also expanded: Jon Bellion and his *The Human Condition* album, and Michael Jackson. I actually didn't know that "I Want You Back" was originally performed by The Jacksons — I thought it was created for the show *Victorious*. Every day you learn something new.
## February
I have a warm feeling about this month — my birthday is on the 27th, and I have nice memories tied to this time of year.
During the first week, I wrote audio recording software and started working on another piece of software: a screen recorder. I haven't completed it yet, but I'm very close. I also think I finally figured out OpenGL, which is a huge milestone.
I had my 18th birthday party on the 15th. It was quite decent. Last week I took a mock bilingual English "matura" exam (something like the SATs in the US), and the last task is always to write an opinion essay. Well, I hadn't written any essays in a while, and this one I wrote so badly I can't even describe it. There was no structure. Arguments were weak. It seemed like I had no idea what I wanted to say — which honestly wasn't that far from the truth.
Today I helped my friend shoot a short ad for his class. We had a lot of fun even though it was freezing cold and raining outside. But we managed to shoot it, and the results are astonishing.
Well, that's it for today. Have a nice day and stay safe!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.