Compare commits

...

119 Commits

Author SHA1 Message Date
d9045f23c2 added blog post about changing domains 2026-03-26 20:51:13 +01:00
816f9cefec replaced links to this website with natconf.dev 2026-03-26 20:21:39 +01:00
94416f5779 edited about page 2026-03-26 11:11:55 +01:00
7ab4a9a173 edited the button corner on the main page 2026-03-25 22:33:04 +01:00
2d052acf91 added warning banner to outdated postgresql blog post 2026-03-25 22:29:26 +01:00
5dee4fccc1 added new blog post 2026-03-25 22:18:57 +01:00
d0d74becc5 added subtitle to main page 2026-03-25 21:44:49 +01:00
0911a8892f added update about blog post 2026-03-17 17:10:56 +01:00
c95fd2a101 edited styling of code blocks to improve legibility 2026-03-17 17:06:59 +01:00
e118a71f76 added blog post 0317 2026-03-17 17:03:47 +01:00
3c47cbe581 added 88x31 buttons to main page 2026-03-14 22:22:39 +01:00
8c00b77d4e slight text edits to blog post 2026-03-14 17:54:25 +01:00
070e50e718 updated page title on Homesick page where it previously announced the page as Project N5 2026-03-14 10:45:47 +01:00
757510744f updated links to copyparty public share 2026-03-14 09:32:36 +01:00
c63aeabb6c added that homesick was previously called project n5 to the project page. should have done this before 2026-03-11 19:48:06 +01:00
4ff75057da renamed project n5 to homesick on main page 2026-03-11 19:33:44 +01:00
5558e3cf3b added update to link to drawing page 2026-03-11 19:22:34 +01:00
a186a0e4bc changed Project N5 references in some places to Homesick 2026-03-11 18:57:19 +01:00
e094d68dfa removed project n5 link from header; added homesick and drawing page links to footer 2026-03-11 18:54:33 +01:00
72b9d15381 adjusted gallery to scale down on mobile devices 2026-03-11 18:38:32 +01:00
013c6e38c7 added drawing to drawing gallery; added alt texts to all drawings 2026-03-10 23:17:24 +01:00
4683233272 removed redundant png screenshot from devlog files 2026-03-09 22:07:13 +01:00
b88908d7bf added devlog 2026/0309 2026-03-09 22:06:49 +01:00
a9756725da added link to art page to main page; added appropriate banner to art page; changed banner of project n5 page on main page to match the actual page banner 2026-03-09 17:40:30 +01:00
71010be02c added art page link to header and footer; removed unrelevant banner from art page 2026-03-09 17:21:54 +01:00
1f67da8996 added art page that links to its subpages 2026-03-09 17:17:07 +01:00
e1d8b1b5a4 made drawing gallery mobile-friendlier 2026-03-09 16:47:06 +01:00
7ecc34b762 finished adding content to drawing gallery for now 2026-03-09 16:43:26 +01:00
f2511470c5 moved discography page to art folder and added blurb to drawing gallery page 2026-03-09 16:13:08 +01:00
72a7515120 added drawing gallery page, not linked anywhere yet 2026-03-09 16:06:56 +01:00
6b42760737 removed redundant reverseTextOrder property from gallery 2026-03-07 20:37:37 +01:00
103b153dc0 show overflow on gallery entries to prevent text cutoff on hover 2026-03-07 15:01:57 +01:00
7263d5c136 removed uses, test pages 2026-03-07 14:18:53 +01:00
01f3f52958 removed portsmouth postmortem blog stub 2026-03-07 14:15:54 +01:00
bc9af8225a added website update 2026-03-07 14:14:01 +01:00
59ecefbe1a removed redundant no ai webring images; using local webring image instead of remote 2026-03-07 14:08:43 +01:00
656b51c58c widened banners on projects page 2026-03-07 14:05:39 +01:00
4aa078a9a2 changed width scaling of table of contents to better adapt to screen width 2026-03-07 13:47:28 +01:00
b8eaa69cc0 changed transition timing for all animations to use exponential function 2026-03-07 13:43:38 +01:00
41ef47d53d gallery component now fancier 2026-03-07 13:40:28 +01:00
b36da8b0f7 changed layout of main page 2026-03-07 12:30:32 +01:00
550ba35078 adjusted max page width 2026-03-06 15:11:06 +01:00
945cbbf995 added update about drawing challenge 2026-03-06 00:02:02 +01:00
1b5d692e14 added final entry to drawing challenge 2026-03-05 23:59:29 +01:00
5e8d605052 added entry to drawing challenge 2026-03-04 21:39:53 +01:00
2259b982b2 added work-in-progress photo to today's drawing challenge entry 2026-03-03 22:01:37 +01:00
1822fe48bd added entry to drawing challenge 2026-03-03 21:51:26 +01:00
223219756e added entry to drawing challenge 2026-03-02 22:38:19 +01:00
7271ac446a added entry to drawing challenge 2026-03-01 22:33:23 +01:00
373cc0c6d4 added entry to drawing challenge 2026-02-28 22:15:55 +01:00
6e0da40cc4 fixed link in latest drawing challenge entry 2026-02-27 23:53:55 +01:00
2a965e42a8 added scroll to top button to all pages 2026-02-27 23:49:25 +01:00
76296359ae added entry to drawing challenge 2026-02-27 23:04:25 +01:00
c7789100ad updated alt text on image 2026-02-25 to reflect wrong date written 2026-02-26 22:27:41 +01:00
a49315a19c added entry to drawing challenge 2026-02-26 22:22:01 +01:00
3290065228 added update about small projects page 2026-02-26 20:21:58 +01:00
c559cb7930 added more prominent links to subpages to projects page; added banner for small projects page 2026-02-26 20:14:26 +01:00
9a51c314b0 added 3DS USB-C mod to small projects page 2026-02-26 20:00:52 +01:00
ec9b4cdb1a added deej0461 to small projects page 2026-02-25 23:23:06 +01:00
2370792073 added entry to drawing challenge 2026-02-25 21:57:39 +01:00
90071ee33d added Small Projects page; added update about status markers on Projects page 2026-02-25 19:34:32 +01:00
5a0a8b25c4 added My Tracks page 2026-02-25 19:23:59 +01:00
005684ad8c added status to projects 2026-02-25 19:16:21 +01:00
0f7e2df3a9 disabled table of contents mouse hover animation for snappier feel 2026-02-25 18:08:24 +01:00
5c1f07bbda added section about webring element to about page 2026-02-25 18:05:42 +01:00
76bfd344e4 moved outline/border styles to property 2026-02-25 17:52:13 +01:00
debf014615 added entry to drawing challenge 2026-02-24 21:43:31 +01:00
4b2fc7910d fixed title in latest drawing challenge entry 2026-02-23 22:26:06 +01:00
c8844fc4dc added entry to drawing challenge 2026-02-23 22:22:21 +01:00
a20cd63ef2 added entry to drawing challenge 2026-02-22 20:26:13 +01:00
a20a7454db added unique arrows for no ai webring prev/next links 2026-02-21 20:15:15 +01:00
a56cac6dcc edited alt and subtitle text for drawing challenge entry image (i forgor) 2026-02-21 20:13:21 +01:00
e29199b6a2 added entry to drawing challenge 2026-02-21 20:09:25 +01:00
2efdc57ec6 added update about no AI webring addition 2026-02-21 16:26:18 +01:00
c7d6fa014d changed link styling 2026-02-21 14:52:56 +01:00
11449319a6 added robots.txt and ai.txt 2026-02-21 14:47:28 +01:00
08a3bb1860 added no ai webring links to main page 2026-02-21 14:29:48 +01:00
e192e56326 minor about page updates 2026-02-21 14:05:42 +01:00
e31ff3c7ba added entry to drawing challenge 2026-02-20 20:50:47 +01:00
f8dc06542c added entry for drawing challenge 2026-02-19 22:07:18 +01:00
d13b1f13ad added entry to drawing challenge 2026-02-18 23:08:29 +01:00
19b9d85342 edited some FAQ info on about page 2026-02-17 22:48:13 +01:00
2fb6e02456 added entry to drawing challenge 2026-02-17 22:33:12 +01:00
6b7599c412 added OpenMoji font and licence text to about page 2026-02-17 15:36:00 +01:00
bb86437eda added entry to drawing challenge 2026-02-16 21:46:20 +01:00
8ab87a2f97 added update about bucket webring 2026-02-16 18:45:20 +01:00
9b84c6050e removed drawing-gallery page 2026-02-16 18:43:56 +01:00
669a5f95d0 renamed changelog to updates and moved link 2026-02-16 18:19:46 +01:00
f5c8aba740 reduced number of changelog entries displayed on main page from 4 to 3 2026-02-16 14:35:10 +01:00
12671306b7 added bucket webring links 2026-02-16 14:34:30 +01:00
649124a8f1 added entry to drawing challenge 2026-02-15 22:02:02 +01:00
6042157caf moved and rewrote table-of-contents.svelte to use stateful design 2026-02-15 13:36:29 +01:00
151e1206ab edited link styling in header and footer 2026-02-15 13:07:13 +01:00
14664054bd configured smartypants options for mdsvex 2026-02-14 21:40:49 +01:00
31232f10ea added entry to drawing challenge 2026-02-14 21:37:45 +01:00
5ddaa29853 added blog post 2026/0214 2026-02-14 19:52:00 +01:00
8b82f5fb4f added entry to drawing challenge 2026-02-13 21:28:52 +01:00
cd44e5e2de added new entry to drawing challenge 2026-02-12 21:56:23 +01:00
4e82d67799 moved toc padding parameters to variables 2026-02-12 19:48:16 +01:00
4497b78f38 edited about page faq 2026-02-12 17:48:18 +01:00
80b1a2f592 added wavy effects to links as well as headers; added blurs to code blocks and more elements with background; changed table of contents style 2026-02-12 16:39:28 +01:00
b0b89569d9 fixed name of CSS --border-dash-size property 2026-02-12 16:22:18 +01:00
632eef453b moved some CSS properties to variables 2026-02-12 16:21:20 +01:00
6119ee8eda added blur to gallery entries when highlighted 2026-02-12 15:47:47 +01:00
96ee17e8c5 added some faq questions to about page 2026-02-12 15:44:41 +01:00
c321a7de7a added padding to blog and devlog post indices 2026-02-12 11:56:13 +01:00
4a984d4daf added entry to drawing challenge 2026-02-11 20:58:07 +01:00
c484f556a6 added background to gallery items when highlighted 2026-02-11 11:59:54 +01:00
72a0c37011 changed italic album titles to bold 2026-02-10 21:39:18 +01:00
8eb200d006 tried something, didn't work, here we are 2026-02-10 21:11:33 +01:00
e177bdcecd added alt text for drawing challenge day 5 image 2026-02-10 19:10:45 +01:00
7e3b695b54 added new entry to drawing challenge 2026-02-10 19:01:00 +01:00
fd40399d8d added blog post 2026/0208 2026-02-08 17:45:30 +01:00
d9145cbed9 added entry to drawing challenge 2026-02-08 11:50:35 +01:00
238b9479ad added entry to drawing challenge 2026-02-07 20:53:28 +01:00
cfe4008989 updated project n5 banner on projects page 2026-02-07 18:55:54 +01:00
79cce84495 split up project groups into individual arrays and removed 'type' property 2026-02-07 18:53:53 +01:00
acb7892122 now using the 3DS banner image on the projects page 2026-02-07 18:51:14 +01:00
39533cb410 updated links to subdomains to use https 2026-02-07 13:59:19 +01:00
141 changed files with 2926 additions and 954 deletions

View File

@@ -1,5 +1,5 @@
# pages-svelte # pages-svelte
SvelteKit repository for my website hosted at [https://denizk0461.dev/](https://denizk0461.dev/) SvelteKit repository for my website hosted at [https://natconf.dev/](https://natconf.dev/)
![Screenshot of the website's main page](website-screenshot.webp) ![Screenshot of the website's main page](website-screenshot.webp)

47
package-lock.json generated
View File

@@ -16,6 +16,7 @@
"@sveltejs/adapter-static": "^3.0.8", "@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.16.0", "@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0", "@sveltejs/vite-plugin-svelte": "^5.0.0",
"@types/node": "^25.2.3",
"mdsvex": "^0.12.6", "mdsvex": "^0.12.6",
"svelte": "^5.0.0", "svelte": "^5.0.0",
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",
@@ -921,9 +922,9 @@
} }
}, },
"node_modules/@sveltejs/kit": { "node_modules/@sveltejs/kit": {
"version": "2.49.1", "version": "2.50.2",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.49.1.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.50.2.tgz",
"integrity": "sha512-vByReCTTdlNM80vva8alAQC80HcOiHLkd8XAxIiKghKSHcqeNfyhp3VsYAV8VSiPKu4Jc8wWCfsZNAIvd1uCqA==", "integrity": "sha512-875hTUkEbz+MyJIxWbQjfMaekqdmEKUUfR7JyKcpfMRZqcGyrO9Gd+iS1D/Dx8LpE5FEtutWGOtlAh4ReSAiOA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -932,13 +933,13 @@
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
"acorn": "^8.14.1", "acorn": "^8.14.1",
"cookie": "^0.6.0", "cookie": "^0.6.0",
"devalue": "^5.3.2", "devalue": "^5.6.2",
"esm-env": "^1.2.2", "esm-env": "^1.2.2",
"kleur": "^4.1.5", "kleur": "^4.1.5",
"magic-string": "^0.30.5", "magic-string": "^0.30.5",
"mrmime": "^2.0.0", "mrmime": "^2.0.0",
"sade": "^1.8.1", "sade": "^1.8.1",
"set-cookie-parser": "^2.6.0", "set-cookie-parser": "^3.0.0",
"sirv": "^3.0.0" "sirv": "^3.0.0"
}, },
"bin": { "bin": {
@@ -951,11 +952,15 @@
"@opentelemetry/api": "^1.0.0", "@opentelemetry/api": "^1.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0",
"svelte": "^4.0.0 || ^5.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0",
"typescript": "^5.3.3",
"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@opentelemetry/api": { "@opentelemetry/api": {
"optional": true "optional": true
},
"typescript": {
"optional": true
} }
} }
}, },
@@ -1019,6 +1024,16 @@
"@types/unist": "*" "@types/unist": "*"
} }
}, },
"node_modules/@types/node": {
"version": "25.2.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/@types/resolve": { "node_modules/@types/resolve": {
"version": "1.20.2", "version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
@@ -1128,9 +1143,9 @@
} }
}, },
"node_modules/devalue": { "node_modules/devalue": {
"version": "5.5.0", "version": "5.6.2",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.5.0.tgz", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz",
"integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==", "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -1521,10 +1536,11 @@
} }
}, },
"node_modules/set-cookie-parser": { "node_modules/set-cookie-parser": {
"version": "2.7.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz",
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", "integrity": "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/sirv": { "node_modules/sirv": {
"version": "3.0.1", "version": "3.0.1",
@@ -1656,6 +1672,13 @@
"node": ">=14.17" "node": ">=14.17"
} }
}, },
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"node_modules/unist-util-is": { "node_modules/unist-util-is": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz",

View File

@@ -17,6 +17,7 @@
"@sveltejs/adapter-static": "^3.0.8", "@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.16.0", "@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0", "@sveltejs/vite-plugin-svelte": "^5.0.0",
"@types/node": "^25.2.3",
"mdsvex": "^0.12.6", "mdsvex": "^0.12.6",
"svelte": "^5.0.0", "svelte": "^5.0.0",
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",

View File

@@ -0,0 +1,32 @@
<script lang="ts">
import { type IndieButton } from "./indie-button";
let {
button
}: {
button: IndieButton;
} = $props();
</script>
<a class="button" href="{button.link}">
<img src="/common/buttons/{button.img}" alt="{button.alt}">
</a>
<style>
.button {
width: 88px;
height: 31px;
transition: scale var(--duration-animation) var(--anim-curve);
margin: 0;
}
.button:hover {
scale: 1.2;
z-index: 10;
}
.button img {
height: 100%;
width: 100%;
}
</style>

View File

@@ -0,0 +1,26 @@
export interface IndieButton {
img: string;
alt: string;
link?: string;
}
export let buttons: IndieButton[] = [
{
img: "iso8601.png",
alt: "A button with the text 'ISO 8601 YYYY-MM-DD'.",
link: "https://www.iso8601.com/",
},
{
img: "queercoded.png",
alt: "A button with the text \"you're telling me a queer coded this\" on a rainbow background.",
},
{
img: "madewithsveltekit.gif",
alt: "A red button with the text 'MADE WITH SVELTEKIT'.",
link: "https://svelte.dev",
},
{
img: "trans-rights-now.png",
alt: "A button with the text 'TRANS RIGHTS NOW!' next to a trans flag.",
},
];

View File

@@ -21,11 +21,11 @@
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: var(--font-size-mono); font-size: var(--font-size-mono);
padding: 8px; padding: 8px;
border: dashed 2px var(--color-highlight); border: var(--border-style) var(--border-dash-size) var(--color-highlight);
color: var(--color-highlight); color: var(--color-highlight);
font-weight: 700; font-weight: 700;
cursor: pointer; cursor: pointer;
transition: background-color 0.05s ease-out; transition: background-color var(--duration-animation) var(--anim-curve);
} }
.outlined-button:hover { .outlined-button:hover {

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
let { let {
ringName,
ringLink, ringLink,
prevLink, prevLink,
nextLink, nextLink,
@@ -7,8 +8,10 @@
listLink, listLink,
prevSymbol, prevSymbol,
nextSymbol, nextSymbol,
highlightEmoji, highlightEmojiLeft,
highlightEmojiRight,
}: { }: {
ringName: string;
ringLink: string; ringLink: string;
prevLink: string; prevLink: string;
nextLink: string; nextLink: string;
@@ -16,26 +19,34 @@
listLink?: string; listLink?: string;
prevSymbol: string; prevSymbol: string;
nextSymbol: string; nextSymbol: string;
highlightEmoji: string;
// Emoji to be used as highlight next to the title
highlightEmojiLeft: string;
/**
* Emoji to be used as highlight to the right of the title. If
* not set, will default to highlightEmojiLeft.
*/
highlightEmojiRight?: string;
} = $props(); } = $props();
</script> </script>
<div class="webring-container"> <div class="webring-container">
<div class="webring-row"> <div class="webring-row">
<span></span> <span></span>
<a href="{ringLink}">{highlightEmoji} GAMEDEV WEBRING {highlightEmoji}</a> <a href="{ringLink}">{highlightEmojiLeft} {ringName} {highlightEmojiRight ?? highlightEmojiLeft}</a>
<span></span> <span></span>
</div> </div>
<div class="webring-row"> <div class="webring-row">
<span></span> <span></span>
<a href="{prevLink}">{prevSymbol} PREV</a> <a href="{prevLink}">{prevSymbol} prev</a>
{#if randLink} {#if randLink}
<a href="{randLink}">RAND</a> <a href="{randLink}">rand</a>
{/if} {/if}
{#if listLink} {#if listLink}
<a href="{listLink}">LIST</a> <a href="{listLink}">list</a>
{/if} {/if}
<a href="{nextLink}">NEXT {nextSymbol}</a> <a href="{nextLink}">next {nextSymbol}</a>
<span></span> <span></span>
</div> </div>
</div> </div>
@@ -46,21 +57,25 @@
width: fit-content; width: fit-content;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
margin: 16px auto; margin: 0 4px;
} }
a { a {
margin: 0 4px; margin: 0 4px;
text-decoration: none; text-decoration: none;
font-size: 1.0rem; font-size: 1.0rem;
line-height: 1.4rem; line-height: 1.4rem;
transition: color 0.1s ease-out, font-weight 0.1s ease-out; font-weight: 500;
/* border: var(--border-width); */
transition: color var(--duration-animation) var(--anim-curve),
font-weight var(--duration-animation) var(--anim-curve);
/* border-color var(--duration-animation) var(--anim-curve); */
} }
a:link, a:visited, span { a:link, a:visited, span {
color: var(--color-highlight); color: var(--color-highlight);
} }
a:hover { a:hover {
font-weight: 600;
color: var(--color-highlight-alt); color: var(--color-highlight-alt);
text-decoration: inherit;
} }
.webring-row { .webring-row {
font-family: var(--font-mono); font-family: var(--font-mono);

View File

@@ -0,0 +1,34 @@
<script lang="ts">
let y: number;
function scrollToTop() {
document.documentElement.scrollTop = 0;
}
</script>
<svelte:window bind:scrollY={y} />
{#if y > 2400}
<button class="scroll-top-button" onclick={scrollToTop}>↑</button>
{/if}
<style>
.scroll-top-button {
position: fixed;
bottom: 24px;
right: 48px;
font-size: 1.4rem;
cursor: pointer;
border: var(--border-style) var(--border-dash-size) var(--color-highlight);
color: var(--color-highlight);
background-color: var(--color-background-highlight);
backdrop-filter: blur(var(--blur-radius-background));
padding: 12px;
transition: background-color var(--duration-animation) var(--anim-curve);
z-index: 10;
}
.scroll-top-button:hover {
background-color: var(--color-background-highlight-hover);
}
</style>

View File

@@ -0,0 +1,27 @@
<script lang="ts">
import ScrollTopButton from "$lib/components/scroll-top-button.svelte";
let { children } = $props();
</script>
<div class="split-container">
{@render children()}
</div>
<style>
.split-container {
width: 100%;
display: flex;
flex-direction: row;
}
.split-container * {
flex-basis: 1;
}
@media screen and (max-width: 800px) {
.split-container {
flex-direction: column;
}
}
</style>

View File

@@ -1,20 +1,36 @@
<script lang="ts"> <script lang="ts">
import Video from '$lib/video.svelte';
let { let {
image, image,
altText, altText,
subtitle, subtitle,
// options: left, right. leaving empty means centred // options: left, right. leaving empty means centred
alignment, alignment,
video,
pixelated,
smaller,
}: { }: {
image: string; image: string;
altText: string; altText?: string;
subtitle?: string; subtitle?: string;
alignment?: string; alignment?: string;
video?: boolean;
pixelated?: boolean;
smaller?: boolean;
} = $props(); } = $props();
</script> </script>
{#snippet subtitledImageContent()} {#snippet subtitledImageContent()}
<img class="subtitled-img" src="{image}" alt="{altText}"> {#if video}
<Video src={image} />
{:else}
{#if pixelated}
<img class="subtitled-img pixelated-img" src="{image}" alt="{altText}">
{:else}
<img class="subtitled-img" src="{image}" alt="{altText}">
{/if}
{/if}
{#if subtitle} {#if subtitle}
<hr> <hr>
@@ -25,32 +41,53 @@
{/if} {/if}
{/snippet} {/snippet}
<!-- this structure is ugly as fuck. there must be a better way of doing this -->
{#if alignment && alignment == "left"} {#if alignment && alignment == "left"}
<a class="subtitled-img-container subtitled-img-container-left" href="{image}"> {#if smaller}
{@render subtitledImageContent()} <a class="subtitled-img-container subtitled-img-container-left subtitled-img-reduced-size" href="{image}">
</a> {@render subtitledImageContent()}
</a>
{:else}
<a class="subtitled-img-container subtitled-img-container-left" href="{image}">
{@render subtitledImageContent()}
</a>
{/if}
{:else if alignment && alignment == "right"} {:else if alignment && alignment == "right"}
<a class="subtitled-img-container subtitled-img-container-right" href="{image}"> {#if smaller}
{@render subtitledImageContent()} <a class="subtitled-img-container subtitled-img-container-right subtitled-img-reduced-size" href="{image}">
</a> {@render subtitledImageContent()}
</a>
{:else}
<a class="subtitled-img-container subtitled-img-container-right" href="{image}">
{@render subtitledImageContent()}
</a>
{/if}
{:else} {:else}
<a class="subtitled-img-container subtitled-img-container-centred" href="{image}"> {#if smaller}
{@render subtitledImageContent()} <a class="subtitled-img-container subtitled-img-container-centred subtitled-img-reduced-size" href="{image}">
</a> {@render subtitledImageContent()}
</a>
{:else}
<a class="subtitled-img-container subtitled-img-container-centred" href="{image}">
{@render subtitledImageContent()}
</a>
{/if}
{/if} {/if}
<style> <style>
.subtitled-img-container { .subtitled-img-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border: 2px var(--color-highlight) dashed; border: var(--border-dash-size) var(--color-highlight) var(--border-style);
text-decoration: none; text-decoration: none;
box-sizing: border-box; box-sizing: border-box;
transition: background-color 0.1s ease-out; backdrop-filter: blur(var(--blur-radius-background));
transition: background-color var(--duration-animation) var(--anim-curve);
} }
.subtitled-img-container-centred { .subtitled-img-container-centred {
width: var(--media-width); width: var(--media-width);
/* width: fit-content; */
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
@@ -97,6 +134,10 @@
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
.subtitled-img-reduced-size {
max-width: initial;
}
} }
@media screen and (min-width: 600px) { @media screen and (min-width: 600px) {
@@ -104,6 +145,10 @@
width: 34%; width: 34%;
} }
.subtitled-img-reduced-size {
max-width: 20%;
}
/* Don't limit height of images set to the side because text flows around them */ /* Don't limit height of images set to the side because text flows around them */
.subtitled-img-container-left img, .subtitled-img-container-right img { .subtitled-img-container-left img, .subtitled-img-container-right img {
max-height: initial; max-height: initial;

View File

@@ -1,32 +1,27 @@
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte'; import {onMount} from 'svelte';
let { interface TocEntry {
stickyScrolling, text: string;
}: { link: string;
stickyScrolling?: boolean;
} = $props();
let idCounter: number = 0; /**
* possible values: 0, 1, 2, 3
*/
indentLevel: number;
}
let root: HTMLElement; let tocEntries: TocEntry[] = $state([]);
let container: HTMLElement;
onMount(() => { onMount(() => {
let headers = getHeaders(); let headers = getHeaders();
headers.forEach(header => { headers.forEach(header => {
let headerId = getHeaderId(header); tocEntries.push({
var element = document.createElement("a"); text: `${(header as HTMLElement).innerHTML}`,
element.classList += "toc-level-" + getHeaderLevel(header); link: `#${getHeaderId(header)}`,
element.href = `#${headerId}`; indentLevel: getHeaderLevel(header),
element.innerHTML = `${(header as HTMLElement).innerHTML}`; });
container.appendChild(element);
}); });
// Hide table of contents if no valid entries have been found
if (headers.length == 0) {
root.style.display = "none";
}
}); });
let getHeaders = function(): NodeList { let getHeaders = function(): NodeList {
@@ -43,59 +38,63 @@
text = text.replaceAll(/[^a-zA-Z0-9]/gi, "-"); text = text.replaceAll(/[^a-zA-Z0-9]/gi, "-");
id = text; id = text;
(header as HTMLElement).id = id; (header as HTMLElement).id = id;
idCounter += 1;
} }
return id; return id;
} }
let getHeaderLevel = function(header: Node): string { function getHeaderLevel(header: Node): number {
switch ((header as HTMLElement).tagName) { switch ((header as HTMLElement).tagName) {
case "H2": case "H2":
return "0"; return 0;
case "H3": case "H3":
return "1"; return 1;
case "H4": case "H4":
return "2"; return 2;
case "H5": case "H5":
return "3"; return 3;
default: default:
return "0"; return 0;
} }
} }
</script> </script>
{#if stickyScrolling} {#snippet tocEntryLine({ entry }: { entry: TocEntry })}
<div class="toc-container notched sticky-toc" bind:this={root}> <a class="toc-level-{entry.indentLevel}" href="{entry.link}">{@html entry.text}</a>
{@render tocList()} {/snippet}
</div>
{:else} {#if tocEntries.length > 0}
<div class="toc-container notched" bind:this={root}> <div class="toc-container">
{@render tocList()} <ul class="toc-list">
{#each tocEntries as entry}
{@render tocEntryLine({ entry })}
{/each}
</ul>
</div> </div>
{/if} {/if}
{#snippet tocList()}
<ul class="toc-list" bind:this={container}></ul>
{/snippet}
<style> <style>
:global { :global {
.toc-container { body {
width: 70%; --padding-indent-base: 44px;
margin-left: auto; --padding-level-indent: 24px;
margin-right: auto;
background-color: var(--color-background-highlight);
padding: 16px 0;
} }
.sticky-toc { .toc-container {
position: sticky; max-width: var(--width-toc);
top: 20px; margin-left: auto;
margin-right: auto;
margin-top: 12px;
box-sizing: border-box;
background-color: var(--color-background-highlight);
padding: 16px 0;
border: var(--border-style) var(--border-dash-size) var(--color-highlight);
backdrop-filter: blur(var(--blur-radius-background));
} }
.toc-list { .toc-list {
padding: 0; padding: 0;
margin: 0; margin: 0;
width: 100%;
} }
.toc-list a { .toc-list a {
@@ -104,11 +103,13 @@
line-height: 1.4rem; line-height: 1.4rem;
padding-top: 2px; padding-top: 2px;
padding-bottom: 2px; padding-bottom: 2px;
padding-right: 24px; padding-right: var(--padding-indent-base);
margin: 0; margin: 0;
display: inline-block; display: inline-block;
text-decoration: none; text-decoration: none;
box-sizing: border-box; box-sizing: border-box;
/* transition: color var(--duration-animation) var(--anim-curve),
background-color var(--duration-animation) var(--anim-curve); */
} }
.toc-list a, .toc-list a:link, .toc-list a:visited { .toc-list a, .toc-list a:link, .toc-list a:visited {
color: var(--color-text); color: var(--color-text);
@@ -120,25 +121,19 @@
.toc-level-0 { .toc-level-0 {
font-weight: 800; font-weight: 800;
padding-left: 44px; padding-left: var(--padding-indent-base);
} }
.toc-level-1 { .toc-level-1 {
padding-left: 68px; padding-left: calc(var(--padding-indent-base) + var(--padding-level-indent));
} }
.toc-level-2 { .toc-level-2 {
padding-left: 92px; padding-left: calc(var(--padding-indent-base) + calc(var(--padding-level-indent) * 2));
} }
.toc-level-3 { .toc-level-3 {
padding-left: 116px; padding-left: calc(var(--padding-indent-base) + calc(var(--padding-level-indent) * 3));
} }
.toc-level-1::before, .toc-level-2::before, .toc-level-3::before { .toc-level-1::before, .toc-level-2::before, .toc-level-3::before {
content: "└ "; content: "└ ";
} }
@media screen and (max-width: 550px) {
.toc-container {
width: 95%;
}
}
} }
</style> </style>

View File

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
export interface ChangelogEntry { export interface UpdateEntry {
date: string; date: string;
time: string; time: string;
@@ -10,48 +10,48 @@
let { let {
entry, entry,
}: { }: {
entry: ChangelogEntry; entry: UpdateEntry;
} = $props(); } = $props();
</script> </script>
<div class="changelog-entry"> <div class="update-entry">
<div class="changelog-entry-timestamp-container"> <div class="update-entry-timestamp-container">
<span>{entry.date}</span> <span>{entry.date}</span>
<span class="changelog-entry-timestamp-comma">,&nbsp;</span> <span class="update-entry-timestamp-comma">,&nbsp;</span>
<span>{entry.time}</span> <span>{entry.time}</span>
</div> </div>
<span class="changelog-entry-timestamp-divider">::</span> <span class="update-entry-timestamp-divider">::</span>
<p> <p>
{entry.content} {@html entry.content}
{#if entry.link} {#if entry.link}
<a class="changelog-entry-link" href="{entry.link}">»</a> <a class="update-entry-link" href="{entry.link}">»</a>
{/if} {/if}
</p> </p>
</div> </div>
<style> <style>
.changelog-entry * { .update-entry * {
margin: 0; margin: 0;
} }
.changelog-entry { .update-entry {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 8px; gap: 8px;
margin: 4px 0; margin: 4px 0;
} }
.changelog-entry p { .update-entry p {
font-size: 1.0rem; font-size: 1.0rem;
line-height: 1.3rem; line-height: 1.3rem;
} }
.changelog-entry-timestamp-container { .update-entry-timestamp-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.changelog-entry-timestamp-container *, .changelog-entry-timestamp-divider { .update-entry-timestamp-container *, .update-entry-timestamp-divider {
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: 0.8rem; font-size: 0.8rem;
line-height: 1.3rem; line-height: 1.3rem;
@@ -60,7 +60,7 @@
min-width: fit-content; min-width: fit-content;
} }
.changelog-entry-link { .update-entry-link {
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: 1.2rem; font-size: 1.2rem;
color: var(--color-highlight); color: var(--color-highlight);
@@ -68,19 +68,19 @@
line-height: 1.3rem; line-height: 1.3rem;
} }
.changelog-entry-link:hover { .update-entry-link:hover {
font-weight: 700; font-weight: 700;
} }
@media screen and (max-width: 550px) { @media screen and (max-width: 550px) {
/* Align timestamp texts vertically */ /* Align timestamp texts vertically */
.changelog-entry-timestamp-container { .update-entry-timestamp-container {
flex-direction: column; flex-direction: column;
align-items: end; align-items: end;
} }
/* Hide separating comma */ /* Hide separating comma */
.changelog-entry-timestamp-comma { .update-entry-timestamp-comma {
display: none; display: none;
} }
} }

View File

@@ -32,8 +32,6 @@
.row-container { .row-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
/* margin-bottom: 8px;
gap: 8px; */
} }
.row-entry { .row-entry {
@@ -42,17 +40,20 @@
margin: 0; margin: 0;
padding: 8px; padding: 8px;
text-decoration: none; text-decoration: none;
transition: background-color 0.1s ease-out, border-color 0.1s ease-out; transition: background-color var(--duration-animation) var(--anim-curve),
border: 2px dashed transparent; border-color var(--duration-animation) var(--anim-curve),
backdrop-filter var(--duration-blur) var(--anim-curve);
border: var(--border-dash-size) var(--border-style) transparent;
} }
.row-entry:hover { .row-entry:hover {
background-color: var(--color-background-highlight); background-color: var(--color-background-highlight);
border-color: var(--color-highlight); border-color: var(--color-highlight);
backdrop-filter: blur(var(--blur-radius-background));
} }
.row-entry:hover .row-img { .row-entry:hover .row-img {
scale: 1.06; scale: 1.2;
} }
.row-img-container { .row-img-container {
@@ -66,7 +67,7 @@
.row-img { .row-img {
width: 100%; width: 100%;
object-fit: cover; object-fit: cover;
transition: scale 0.1s ease-out; transition: scale var(--duration-animation) var(--anim-curve);
} }
.row-text-container { .row-text-container {

View File

@@ -5,25 +5,23 @@
img: string; img: string;
imgAlt: string; imgAlt: string;
link: string; link: string;
description: string;
} }
let { let {
entries, entries,
reverseTextOrder,
}: { }: {
entries: GalleryEntry[]; entries: GalleryEntry[];
reverseTextOrder?: boolean;
} = $props(); } = $props();
</script> </script>
<div class="post-list"> <div class="post-list">
{#each entries as entry} {#each entries as entry}
{@render galleryEntry({entry, reverseTextOrder})} {@render galleryEntry({entry})}
{/each} {/each}
</div> </div>
{#snippet galleryEntry({entry, reverseTextOrder}: {entry: GalleryEntry, reverseTextOrder?: boolean})} {#snippet galleryEntry({entry}: {entry: GalleryEntry})}
<!-- {#snippet galleryEntry({key, post, index}: {key: string, post: DevlogPost, index: number})} -->
<a class="gallery-container" href="{entry.link}"> <a class="gallery-container" href="{entry.link}">
{#if entry.img && entry.img !== ""} {#if entry.img && entry.img !== ""}
<img class="gallery-img" src="{entry.img}" alt="{entry.imgAlt}"> <img class="gallery-img" src="{entry.img}" alt="{entry.imgAlt}">
@@ -31,13 +29,9 @@
<div class="gallery-img-placeholder"></div> <div class="gallery-img-placeholder"></div>
{/if} {/if}
<div class="gallery-text-container"> <div class="gallery-text-container">
{#if reverseTextOrder} <p class="gallery-subtitle">{@html entry.subtitle}</p>
<p class="gallery-subtitle">{@html entry.subtitle}</p> <p class="gallery-title">{entry.title}</p>
<p class="gallery-title">{entry.title}</p> <p class="gallery-description">{entry.description}</p>
{:else}
<p class="gallery-title">{entry.title}</p>
<p class="gallery-subtitle">{@html entry.subtitle}</p>
{/if}
</div> </div>
</a> </a>
{/snippet} {/snippet}
@@ -56,22 +50,24 @@
.gallery-container { .gallery-container {
box-sizing: content-box; box-sizing: content-box;
height: 80px; height: 120px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
text-decoration: none; text-decoration: none;
align-items: center; align-items: center;
margin: 6px 0; margin: 0;
justify-content: center;
border: var(--border-style) transparent var(--border-dash-size);
transition: border-color var(--duration-animation) var(--anim-curve);
} }
.gallery-img, .gallery-img-placeholder { .gallery-img, .gallery-img-placeholder {
width: 145px; width: 180px;
min-width: 145px; min-width: 180px;
height: 100%; height: 100%;
margin: 0; margin: 0;
object-fit: cover; object-fit: cover;
/* filter: grayscale(60%); */ transition: width var(--duration-animation) var(--anim-curve);
transition: margin 0.1s ease-out;
} }
.gallery-img-placeholder { .gallery-img-placeholder {
@@ -79,23 +75,21 @@
} }
.gallery-text-container { .gallery-text-container {
display: flex; display: grid;
flex-direction: column; grid-auto-columns: 1fr;
grid-template-rows: 1fr 1fr 0fr;
align-items: center;
flex-grow: 1; flex-grow: 1;
height: 100%; padding: 0 16px;
padding-left: 16px; transition: background-color var(--duration-animation) var(--anim-curve),
padding-right: 16px; backdrop-filter var(--duration-blur) var(--anim-curve),
border-style: dashed; grid-template-rows var(--duration-blur) var(--anim-curve);
justify-content: center;
border-color: transparent;
border-width: 2px;
border-left: none;
transition: border-color 0.1s ease-out, padding-right 0.1s ease-out;
} }
.gallery-title, .gallery-subtitle { .gallery-title, .gallery-subtitle, .gallery-description {
margin: 0; margin: 0;
transition: color 0.1s ease-out; transition: color var(--duration-animation) var(--anim-curve),
opacity var(--duration-animation) var(--anim-curve);
} }
.gallery-title { .gallery-title {
@@ -103,42 +97,59 @@
font-weight: 700; font-weight: 700;
} }
.gallery-subtitle { .gallery-subtitle, .gallery-description {
font-size: 1.0rem; font-size: 1.0rem;
line-height: 1.2rem; line-height: 1.2rem;
overflow: hidden;
} }
.gallery-container:hover .gallery-text-container { .gallery-description {
font-weight: 500;
opacity: 0;
}
.gallery-container:hover {
border-color: var(--color-highlight); border-color: var(--color-highlight);
} background-color: var(--color-background-highlight);
.gallery-container:hover .gallery-img, .gallery-container:hover .gallery-img-placeholder { backdrop-filter: blur(var(--blur-radius-background));
/* filter: grayscale(0%); */
margin-left: 8px;
}
.gallery-container:hover .gallery-text-container {
padding-right: 8px;
} }
.gallery-container:hover p { .gallery-container:hover p {
color: var(--color-highlight); color: var(--color-highlight);
} }
@media screen and (max-width: 700px) { @media screen and (min-width: 800px) {
/* .gallery-title { .gallery-title {
font-size: 1.0rem; font-size: 1.4rem;
line-height: 1.1rem; line-height: 2.0rem;
} }
.gallery-subtitle {
font-size: 0.9rem;
line-height: 1.1rem;
} */
}
@media screen and (max-width: 500px) { .gallery-container:hover .gallery-img, .gallery-container:hover .gallery-img-placeholder {
width: 260px;
}
.gallery-container:hover .gallery-text-container {
grid-template-rows: 0fr 1fr 1fr;
}
.gallery-container:hover .gallery-subtitle {
opacity: 0;
}
.gallery-container:hover .gallery-description {
opacity: 1;
}
}
@media screen and (max-width: 800px) {
.gallery-title { .gallery-title {
font-size: 1.0rem; font-size: 1.0rem;
line-height: 1.1rem; line-height: 1.1rem;
} }
.gallery-description {
display: none;
}
.gallery-subtitle { .gallery-subtitle {
font-size: 0.8rem; font-size: 0.8rem;
line-height: 1rem; line-height: 1rem;
@@ -146,7 +157,7 @@
} }
.gallery-container { .gallery-container {
height: 64px; height: 72px;
} }
.gallery-text-container { .gallery-text-container {
@@ -154,8 +165,8 @@
} }
.gallery-img, .gallery-img-placeholder { .gallery-img, .gallery-img-placeholder {
width: 100px; width: 110px;
min-width: 100px; min-width: 110px;
} }
} }
</style> </style>

View File

@@ -1,8 +1,11 @@
<script lang="ts"> <script lang="ts">
import ScrollTopButton from "$lib/components/scroll-top-button.svelte";
let { children } = $props(); let { children } = $props();
</script> </script>
<div class="main-content"> <div class="main-content">
<ScrollTopButton />
{@render children()} {@render children()}
</div> </div>

View File

@@ -20,18 +20,22 @@
<div class="content-container"> <div class="content-container">
<div class="content-box center-box"> <div class="content-box center-box">
<p> 20232026 denizk0461</p> <p> 20232026 denizk0461</p>
<p>Built from commit <a class="commit" href="https://code.denizk0461.dev/denizk0461/pages/src/commit/{version}">{version.substring(0, 6)}</a></p> <p>Built from commit <a class="commit" href="https://code.natconf.dev/denizk0461/pages/src/commit/{version}">{version.substring(0, 6)}</a></p>
</div> </div>
<div class="content-box"> <div class="content-box">
<h6>Content</h6> <h6>Content</h6>
<a href="/projects">Projects</a> <a href="/projects">Projects</a>
<a class="link-level-2" href="/projects/projectn5">Homesick</a>
<a href="/blog">Blog</a> <a href="/blog">Blog</a>
<a href="/art">Art</a>
<a class="link-level-2" href="/art/drawings">Drawings</a>
</div> </div>
<div class="content-box"> <div class="content-box">
<h6>Meta</h6> <h6>Meta</h6>
<a href="/meta/about">About</a> <a href="/meta/about">About</a>
<a href="/meta/feeds">Feeds</a> <a href="/meta/feeds">Feeds</a>
<a href="https://code.denizk0461.dev/denizk0461/pages">Page Source</a> <a href="/meta/updates">Updates</a>
<a href="https://code.natconf.dev/denizk0461/pages">Page Source</a>
<a href="/meta/privacy">Privacy & Cookies</a> <a href="/meta/privacy">Privacy & Cookies</a>
</div> </div>
</div> </div>
@@ -65,8 +69,17 @@
margin: 0; margin: 0;
} }
.link-level-2 {
padding-left: 16px;
}
.link-level-2::before {
content: '└ ';
}
footer a:hover { footer a:hover {
font-weight: 700; font-weight: 700;
text-decoration: var(--border-style) var(--underline-dash-size) var(--color-highlight) underline;
} }
.bottom-rat { .bottom-rat {
@@ -79,7 +92,7 @@
.background { .background {
background-color: var(--color-background-highlight); background-color: var(--color-background-highlight);
backdrop-filter: blur(6px); backdrop-filter: blur(var(--blur-radius-background));
margin-top: 32px; margin-top: 32px;
} }

View File

@@ -1,9 +1,8 @@
{#snippet headerLinks()} {#snippet headerLinks()}
<a href="/">Home</a> <a href="/">Home</a>
<a href="/projects">Projects</a> <a href="/projects">Projects</a>
<a href="/projects/projectn5">Project N5</a>
<a href="/blog">Blog</a> <a href="/blog">Blog</a>
<!-- <a href="/garden">Garden</a> --> <a href="/art">Art</a>
<a href="/meta/about">About</a> <a href="/meta/about">About</a>
{/snippet} {/snippet}
@@ -29,10 +28,10 @@
} }
a { a {
font-family: var(--font-);
font-size: 1rem; font-size: 1rem;
font-weight: bold;
text-decoration: none; text-decoration: none;
font-family: var(--font-mono);
font-weight: 500;
} }
a:link { a:link {
@@ -44,8 +43,9 @@
} }
/* mouse over link */ /* mouse over link */
a:hover { a:hover {
color: var(--color-highlight); font-weight: 700;
/* text-decoration: underline dashed 2px var(--color-highlight); */ /* color: var(--color-highlight); */
text-decoration: var(--border-style) var(--underline-dash-size) var(--color-highlight) underline;
} }
@media screen and (max-width: 500px) { @media screen and (max-width: 500px) {

View File

@@ -5,6 +5,10 @@
let { children } = $props(); let { children } = $props();
</script> </script>
<svelte:head>
<meta name="robots" content="noai, noimageai">
</svelte:head>
<div class="waters"></div> <div class="waters"></div>
<div class="all-content-container"> <div class="all-content-container">
<Header /> <Header />
@@ -92,10 +96,26 @@
font-weight: 400 700; font-weight: 400 700;
font-style: normal; font-style: normal;
} }
@font-face {
font-family: "LIGHTYEARS";
src: url("/fonts/lightyears.woff2");
font-weight: 400;
font-style: normal;
}
/* OpenMoji */
@font-face {
font-family: "OpenMoji";
src: url("/fonts/openmoji/openmoji.woff2") format("woff2");
unicode-range: U+23,U+2A,U+2D,U+30-39,U+A9,U+AE,U+200D,U+203C,U+2049,U+20E3,U+2117,U+2120,U+2122,U+2139,U+2194-2199,U+21A9,U+21AA,U+229C,U+231A,U+231B,U+2328,U+23CF,U+23E9-23F3,U+23F8-23FE,U+24C2,U+25A1,U+25AA-25AE,U+25B6,U+25C0,U+25C9,U+25D0,U+25D1,U+25E7-25EA,U+25ED,U+25EE,U+25FB-25FE,U+2600-2605,U+260E,U+2611,U+2614,U+2615,U+2618,U+261D,U+2620,U+2622,U+2623,U+2626,U+262A,U+262E,U+262F,U+2638-263A,U+2640,U+2642,U+2648-2653,U+265F,U+2660,U+2663,U+2665,U+2666,U+2668,U+267B,U+267E,U+267F,U+2691-2697,U+2699,U+269B,U+269C,U+26A0,U+26A1,U+26A7,U+26AA,U+26AB,U+26B0,U+26B1,U+26BD,U+26BE,U+26C4,U+26C5,U+26C8,U+26CE,U+26CF,U+26D1,U+26D3,U+26D4,U+26E9,U+26EA,U+26F0-26F5,U+26F7-26FA,U+26FD,U+2702,U+2705,U+2708-270D,U+270F,U+2712,U+2714,U+2716,U+271D,U+2721,U+2728,U+2733,U+2734,U+2744,U+2747,U+274C,U+274E,U+2753-2755,U+2757,U+2763,U+2764,U+2795-2797,U+27A1,U+27B0,U+27BF,U+2934,U+2935,U+2B05-2B07,U+2B0C,U+2B0D,U+2B1B,U+2B1C,U+2B1F-2B24,U+2B2E,U+2B2F,U+2B50,U+2B55,U+2B58,U+2B8F,U+2BBA-2BBC,U+2BC3,U+2BC4,U+2BEA,U+2BEB,U+3030,U+303D,U+3297,U+3299,U+E000-E009,U+E010,U+E011,U+E040-E06D,U+E080-E0B4,U+E0C0-E0CC,U+E0FF-E10D,U+E140-E14A,U+E150-E157,U+E181-E189,U+E1C0-E1C4,U+E1C6-E1D9,U+E200-E216,U+E240-E269,U+E280-E283,U+E2C0-E2C4,U+E2C6-E2DA,U+E300-E303,U+E305-E30F,U+E312-E316,U+E318-E322,U+E324-E329,U+E32B,U+E340-E348,U+E380,U+E381,U+F000,U+F77A,U+F8FF,U+FE0F,U+1F004,U+1F0CF,U+1F10D-1F10F,U+1F12F,U+1F16D-1F171,U+1F17E,U+1F17F,U+1F18E,U+1F191-1F19A,U+1F1E6-1F1FF,U+1F201,U+1F202,U+1F21A,U+1F22F,U+1F232-1F23A,U+1F250,U+1F251,U+1F260-1F265,U+1F300-1F321,U+1F324-1F393,U+1F396,U+1F397,U+1F399-1F39B,U+1F39E-1F3F0,U+1F3F3-1F3F5,U+1F3F7-1F4FD,U+1F4FF-1F53D,U+1F549-1F54E,U+1F550-1F567,U+1F56F,U+1F570,U+1F573-1F57A,U+1F587,U+1F58A-1F58D,U+1F590,U+1F595,U+1F596,U+1F5A4,U+1F5A5,U+1F5A8,U+1F5B1,U+1F5B2,U+1F5BC,U+1F5C2-1F5C4,U+1F5D1-1F5D3,U+1F5DC-1F5DE,U+1F5E1,U+1F5E3,U+1F5E8,U+1F5EF,U+1F5F3,U+1F5FA-1F64F,U+1F680-1F6C5,U+1F6CB-1F6D2,U+1F6D5-1F6D7,U+1F6DC-1F6E5,U+1F6E9,U+1F6EB,U+1F6EC,U+1F6F0,U+1F6F3-1F6FC,U+1F7E0-1F7EB,U+1F7F0,U+1F90C-1F93A,U+1F93C-1F945,U+1F947-1F9FF,U+1FA70-1FA7C,U+1FA80-1FA89,U+1FA8F-1FAC6,U+1FACE-1FADC,U+1FADF-1FAE9,U+1FAF0-1FAF8,U+1FBC5-1FBC9,U+E0061-E0067,U+E0069,U+E006C-E0079,U+E007F;
}
/* #endregion */ /* #endregion */
:global { :global {
:root { :root {
/* colours */
--color-text: #d0d0d0; --color-text: #d0d0d0;
--color-text-secondary: #b0b0b0; --color-text-secondary: #b0b0b0;
--color-text-img: invert(98%) sepia(1%) saturate(4643%) hue-rotate(297deg) brightness(115%) contrast(76%); --color-text-img: invert(98%) sepia(1%) saturate(4643%) hue-rotate(297deg) brightness(115%) contrast(76%);
@@ -107,28 +127,43 @@
--color-header-highlight: color-mix(in srgb, #6d1e26 80%, transparent); --color-header-highlight: color-mix(in srgb, #6d1e26 80%, transparent);
--color-background: #111111; --color-background: #111111;
--color-background-highlight: color-mix(in srgb, var(--color-highlight) 10%, transparent); --color-background-highlight: color-mix(in srgb, var(--color-highlight) 20%, transparent);
--color-background-highlight-alt: color-mix(in srgb, var(--color-highlight-alt) 20%, transparent);
--color-background-highlight-hover: color-mix(in srgb, var(--color-highlight) 60%, transparent); --color-background-highlight-hover: color-mix(in srgb, var(--color-highlight) 60%, transparent);
--color-background-highlight-hover-dark: color-mix(in srgb, var(--color-highlight-dark) 60%, transparent); --color-background-highlight-hover-dark: color-mix(in srgb, var(--color-highlight-dark) 60%, transparent);
--color-waters: #242424; --color-waters: #242424;
--notch-size: 32px;
--notch-size-small: 16px;
--color-link-unvisited: #c2e8ff; --color-link-unvisited: #c2e8ff;
--color-link-visited: #ffd7f0; --color-link-visited: #ffd7f0;
--color-link-hovered: #ffdad5; --color-link-hovered: #ffdad5;
/* blurs */
--blur-radius-background: 6px;
/* borders */
--border-style: dashed;
--border-dash-size: 2px;
--underline-dash-size: 1px;
/* durations */
--duration-blur: 0.2s;
/* animation */
--duration-animation: 0.3s;
--anim-curve: cubic-bezier(0.22, 1, 0.36, 1);
/* fonts */ /* fonts */
--font-line-height: 1.6rem; --font-line-height: 1.6rem;
--font-sans-serif: 'Bai Jamjuree', sans-serif; --font-sans-serif: 'Bai Jamjuree', 'OpenMoji', sans-serif;
--font-size-sans-serif: 1.1rem; --font-size-sans-serif: 1.1rem;
--font-mono: 'Kode Mono', monospace; --font-mono: 'Kode Mono', 'OpenMoji', monospace;
--font-size-mono: 0.9em; --font-size-mono: 0.9em;
--font-lightyears: 'LIGHTYEARS', sans-serif;
--font-size-h1: 2.0rem; --font-size-h1: 2.0rem;
--font-size-h2: 1.5rem; --font-size-h2: 1.5rem;
--font-size-h3: 1.3rem; --font-size-h3: 1.3rem;
@@ -139,12 +174,17 @@
/* sizing */ /* sizing */
--media-width: 80%; --media-width: 80%;
--width-toc: 650px;
/* page sizing */ /* page sizing */
--page-width: 900px; --page-width: 1200px;
--screen-width-mobile: 800px; --screen-width-mobile: 800px;
--margin-content-side: 24px; --margin-content-side: 24px;
/* misc */
--notch-size: 32px;
--notch-size-small: 16px;
} }
html { html {
@@ -205,9 +245,16 @@
color: var(--color-highlight); color: var(--color-highlight);
margin-top: var(--margin-header-top); margin-top: var(--margin-header-top);
margin-bottom: var(--margin-header-bottom); margin-bottom: var(--margin-header-bottom);
}
h1 {
width: fit-content; width: fit-content;
} }
h2, h3, h4, h5, h6 {
width: 100%;
}
h2 + h3, h3 + h4, h4 + h5, h5 + h6 { h2 + h3, h3 + h4, h4 + h5, h5 + h6 {
/* Remove top margin when a header immediately preceds another header */ /* Remove top margin when a header immediately preceds another header */
margin-top: 0; margin-top: 0;
@@ -252,7 +299,7 @@
width: 100%; width: 100%;
height: 1px; height: 1px;
border: none; border: none;
border-top: 2px dashed var(--color-highlight); border-top: var(--border-dash-size) var(--border-style) var(--color-highlight);
margin: 8px 0; margin: 8px 0;
} }
@@ -262,14 +309,19 @@
line-height: var(--font-line-height); line-height: var(--font-line-height);
font-weight: 500; font-weight: 500;
background-color: var(--color-background-highlight); background-color: var(--color-background-highlight);
backdrop-filter: blur(var(--blur-radius-background));
/* color: var(--color-background); */ /* color: var(--color-background); */
border-radius: 8px; border-radius: 8px;
padding-left: 6px; padding-left: 6px;
padding-right: 6px; padding-right: 6px;
} }
.code-block {
width: fit-content;
padding: 16px;
}
img, video { img, video {
width: var(--media-width);
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
display: flex; display: flex;
@@ -277,6 +329,23 @@
object-fit: contain; object-fit: contain;
} }
img {
width: var(--media-width);
}
video {
max-width: var(--media-width);
margin-top: 12px;
margin-bottom: 12px;
/* padding: 8px;
backdrop-filter: blur(var(--blur-radius-background));
border: var(--border-dash-size) var(--border-style) var(--color-highlight); */
}
.lightyears-text {
font-family: var(--font-lightyears);
}
.horizontally-centre-aligned { .horizontally-centre-aligned {
width: var(--media-width); width: var(--media-width);
display: flex; display: flex;
@@ -300,7 +369,10 @@
a:link { a:link {
color: var(--color-link-unvisited); color: var(--color-link-unvisited);
text-decoration-style: dashed; text-decoration-thickness: var(--underline-dash-size);
text-decoration-color: transparent;
text-decoration-style: var(--border-style);
font-weight: 500;
} }
/* visited link */ /* visited link */
a:visited { a:visited {
@@ -309,7 +381,7 @@
/* mouse over link */ /* mouse over link */
a:hover { a:hover {
color: var(--color-link-hovered); color: var(--color-link-hovered);
text-decoration-thickness: 1px; text-decoration-color: var(--color-link-hovered);
} }
.notched { .notched {
@@ -350,26 +422,22 @@
/* #region Lists (ul and LinkList) */ /* #region Lists (ul and LinkList) */
.list, ul { .list, ul {
display: flex;
flex-direction: column;
padding: 0; padding: 0;
display: table;
} }
.list a, li { .list a, li {
width: 100%; width: 100%;
/* transition: color 0.1s ease-in-out; */
margin: 0;
padding: 0px 0;
list-style-type: none; list-style-type: none;
display: table-row;
} }
.list a::before, li::before { .list a::before, li::before {
content: ""; content: "";
font-family: var(--font-mono); font-family: var(--font-mono);
font-weight: bold; font-weight: bold;
color: var(--color-highlight); color: var(--color-highlight);
margin: 0 4px 0 12px; display: table-cell;
} padding-left: 12px;
li::before {
padding-right: 8px; padding-right: 8px;
} }
.list a:hover::before { .list a:hover::before {
@@ -408,29 +476,14 @@
padding: 4px; padding: 4px;
} }
@media screen and (max-width: 800px) { .callout-warning {
/* h1 { margin: 12px auto;
font-size: 2.3rem; max-width: var(--width-toc);
line-height: 2.4rem; padding: 12px 20px;
} box-sizing: border-box;
backdrop-filter: blur(var(--blur-radius-background));
h2 { background-color: var(--color-background-highlight-alt);
font-size: 1.8rem; border: var(--border-dash-size) var(--border-style) var(--color-highlight-alt);
line-height: 1.8rem;
}
h3 {
font-size: 1.6rem;
line-height: 1.6rem;
}
h4, h5, h6 {
font-size: 1.4rem;
line-height: 1.4rem;
} */
/* p, span, li, pre, a {
} */
} }
} }
</style> </style>

View File

@@ -1,25 +1,25 @@
<script lang="ts"> <script lang="ts">
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import Webring from "$lib/webrings/ring.svelte";
import Gallery, { type GalleryEntry } from "$lib/lists/gallery.svelte";
import GalleryRow, { type GalleryRowEntry } from "$lib/lists/gallery-row.svelte"; import GalleryRow, { type GalleryRowEntry } from "$lib/lists/gallery-row.svelte";
import { posts as devlogPosts } from "./projects/projectn5/devlog/posts"; import { posts as devlogPosts } from "./projects/projectn5/devlog/posts";
import { posts as blogPosts } from "./blog/posts"; import { posts as blogPosts } from "./blog/posts";
import { entries as changelogEntries } from "./changelog/changelog"; import { entries as updateEntries } from "./meta/updates/updates";
import ChangelogEntry from "$lib/components/changelog-entry.svelte"; import UpdateEntry from "$lib/components/update-entry.svelte";
import IndieButton from "$lib/components/indie-button.svelte";
import { buttons } from "$lib/components/indie-button";
let latestDevlogDate = devlogPosts[0].post.date; let latestDevlogDate = devlogPosts[0].post.date;
let latestBlogDate = blogPosts[0].post.date; let latestBlogDate = blogPosts[0].post.date;
let changelogEntriesTrimmed = changelogEntries.slice(0, 4); let updateEntriesTrimmed = updateEntries.slice(0, 4);
const galleryTopRow: GalleryRowEntry[] = [ const galleryTopRow: GalleryRowEntry[] = [
{ {
title: "Project N5 devlog", title: "Homesick devlog",
description: `My active Godot game project about finding yourself in an unfamiliar future. <i>latest update: ${latestDevlogDate}</i>`, description: `My active Godot game project about finding yourself in an unfamiliar future. <i>latest update: ${latestDevlogDate}</i>`,
img: "projects/projectn5/devlog/2025/0523/birds_eye.webp", img: "projects/projectn5/banner2.webp",
altText: "Project N5 screenshot of Laura looking down at two cuboids.", altText: "The protagonist Laura standing on a floating platform in the purple test level. Ziplines are all around her and the text 'When this text is spinning, the game is not paused' is frozen in the sky.",
link: "projects/projectn5", link: "projects/projectn5",
}, },
{ {
@@ -34,24 +34,31 @@
const galleryBottomRow: GalleryRowEntry[] = [ const galleryBottomRow: GalleryRowEntry[] = [
{ {
title: "Projects", title: "Projects",
description: "An overview of what I do and have done", description: "An overview of my more technical projects",
img: "main/3ds.webp", img: "projects/banner.webp",
altText: "An upside-down New 3DS XL lying open on a desk. A small USB-C breakout board is attached to the 3DS, and a USB-C cable is plugged in. The 3DS is glowing to indicate that it is charging.", altText: "An upside-down New 3DS XL lying open on a desk with a small USB-C breakout board attached to it, and a USB-C cable plugged in. The 3DS is glowing to indicate that it is charging.",
link: "projects", link: "projects",
}, },
{
title: "Art",
description: "My creative side lives here",
img: "art/banner.webp",
altText: "A rainbow-like holographic effect produced by bending a reflective sheet of cardboard.",
link: "art",
},
{ {
title: "Files", title: "Files",
description: "Find things I've put for download on my Copyparty instance", description: "Find things I've put for download on my Copyparty instance",
img: "main/hypertext.webp", img: "main/hypertext.webp",
altText: "Screenshot of Hypertext Unity level. Crates are strewn across the floor, Waluigi is flying in front of the camera, and text such as 'COME AND TRY OUR ALL-NEW BLENDER' and 'omg! it's the brandenburg er tor!' is displayed.", altText: "Screenshot of Hypertext Unity level. Crates are strewn across the floor, Waluigi is flying in front of the camera, and text such as 'COME AND TRY OUR ALL-NEW BLENDER' and 'omg! it's the brandenburg er tor!' is displayed.",
link: "//files.denizk0461.dev/", link: "https://files.natconf.dev/public/",
}, },
{ {
title: "Gitea", title: "Gitea",
description: "I now also self-host a Gitea instance where I am likely migrating all my projects to", description: "I now also self-host a Gitea instance where I am likely migrating all my projects to",
img: "main/magic.webp", img: "main/magic.webp",
altText: "A 'magic' command written in Java. The command shuts down the computer when ran.", altText: "A 'magic' command written in Java. The command shuts down the computer when ran.",
link: "//code.denizk0461.dev/", link: "https://code.natconf.dev/",
}, },
]; ];
</script> </script>
@@ -63,67 +70,170 @@
<Content> <Content>
<h1 class="gradient-title"><i>Moin!</i> ~ welcome to my website :)</h1> <h1 class="gradient-title"><i>Moin!</i> ~ welcome to my website :)</h1>
<a href="/blog/2026/0325" class="page-subtitle gradient-title lightyears-text">you can change the world from your bedroom!</a>
<hr> <hr>
<div> <div>
<img class="me-img pixelated-img" src="me.webp" alt="Pixelated mirror selfie of the website creator wearing a green shirt, fitting the website theme. The face is obscured." title="hi.">
<p>Hi! I'm Deniz (he/him/they). I'm a hobbyist programmer based in 🇩🇪 Northern Germany who does coding, 3D modelling, and sometimes music too. I am also studying to become a secondary school teacher. Welcome to my webpage!</p> <img class="me-img pixelated-img" src="me.webp" alt="Pixelated mirror selfie of the website creator wearing a green shirt, fitting the website theme. The face is obscured." title="hi!">
<p>Here I publish my projects in programming, electronics (Arduino, Raspberry Pi etc.), and gamedev specifically, but I also set up a blog to talk about random things on my mind. Feel free to explore.</p>
<p>This place is a constant work-in-progress while I try to keep URLs intact, a lot of stuff is being modified and moved around! I'm also adding new things and seeing which things I enjoy maintaining. If anything's outright <a href="/blog/2026/0131">broken</a>, please do let me know.</p> <p>Hi! I'm Deniz. Welcome to my website! I keep rewriting this introduction but I'm REALLY bad at this type of stuff.</p>
<p>I made this website because I really don't like modern social media and I wanted a more creative way of expressing myself without giving in to the attention economy or submitting all my data including my soul to some megacorp. That's why you'll find a bunch of stuff here that interests me: programming, gamedev, 3D modelling, electronic music, drawing, electronics and microcontroller programming, Linux and self-hosting, and probably some other stuff too. I am currently developing at least one game and I am also posting random things on my blog, both of which you can find linked above and below.</p>
<p>I listen to A LOT of music (fav artists: <a href="https://acloudyskye.bandcamp.com/">acloudyskye</a>, <a href="https://jaronsteele.bandcamp.com/">Jaron</a>, <a href="https://janeremover.bandcamp.com/">Jane Remover</a>) and I enjoy dabbling around in <a href="https://godotengine.org/">Godot</a> and <a href="https://blender.org/">Blender</a>. I also use <a href="https://fedoraproject.org/">Fedora KDE</a>... btw. Want to know more about me and this website? Firstly, <i>why?</i> But also, <a href="/meta/about">here</a>!</p>
<p>irl I am from 🇩🇪 Northern Germany and studying to become a secondary school teacher.</p>
</div> </div>
<div class="changelog-container"> <div class="split-container">
<a class="changelog-header-link" href="/changelog"><h6 class="changelog-header">website changelog <span class="small-supertext">(new!)</span></h6></a> <div class="info-container">
{#each changelogEntriesTrimmed as entry} <h4 class="update-header">heads-up</h4>
<ChangelogEntry {entry} /> <p>This website works best on Firefox and other Gecko-based browsers! All pages <i>should</i> be responsive and work on mobile.</p>
{/each} <p>Also, this place is a constant work-in-progress and things may move around. If anything's outright <a href="/blog/2026/0131">broken</a> though, please do let me know.</p>
</div> </div>
<div class="update-container">
<div class="webring-container"> <a class="update-header-link" href="/meta/updates"><h4 class="update-header">website updates <span class="small-supertext">(new!)</span></h4></a>
<Webring {#each updateEntriesTrimmed as entry}
ringLink="https://www.rainbowcemetery.com/devring" <UpdateEntry {entry} />
prevLink="https://www.rainbowcemetery.com/devring/prev.php?id=18" {/each}
nextLink="https://www.rainbowcemetery.com/devring/next.php?id=18" </div>
randLink="https://www.rainbowcemetery.com/devring/rand.php?id=18"
listLink="https://www.rainbowcemetery.com/devring/list.php?id=18"
prevSymbol="&lt;&lt;"
nextSymbol="&gt;&gt;"
highlightEmoji="👾" />
</div> </div>
<GalleryRow entries={galleryTopRow} /> <GalleryRow entries={galleryTopRow} />
<GalleryRow entries={galleryBottomRow} /> <GalleryRow entries={galleryBottomRow} />
<div class="split-container">
<div class="webring-container">
<h4 class="update-header">webrings</h4>
<div class="webring">
<iframe title="bucket webring" id="bucket-webring" style="width: 100%; height: 3rem; border: none;" src="https://webring.bucketfish.me/embed.html?name=denizk0461"></iframe>
</div>
<div class="webring">
<a href="https://www.rainbowcemetery.com/devring/prev.php?id=18">
<img src="/webrings/gamedev/ringprev.png" alt="previous">
</a>
<a href="https://www.rainbowcemetery.com/devring/list.php?id=18">
<img src="/webrings/gamedev/88x31.png" alt="list">
</a>
<a href="https://www.rainbowcemetery.com/devring/next.php?id=18">
<img src="/webrings/gamedev/ringnext.png" alt="next">
</a>
</div>
<map name="w95widget">
<area href="https://baccyflap.com/noai" target="_blank" shape="rect" coords="0,0,308,22" alt="no ai webring" title="no ai webring">
<area href="https://baccyflap.com/noai/?prv&s=dzk" target="_top" shape="rect" coords="56,36,130,58" alt="previous" title="previous">
<area href="https://baccyflap.com/noai/?rnd" target="_top" shape="rect" coords="137,36,211,58" alt="random" title="random">
<area href="https://baccyflap.com/noai/?nxt&s=dzk" target="_top" shape="rect" coords="218,36,292,58" alt="next" title="next">
</map>
<img class="webring-img" usemap="#w95widget" src="/webrings/noai/w95widget.webp" alt="a gray Windows 95 style dialog box titled 'The No AI Webring' with a little icon showing a computer chip in a rubbish bin. beside it are three clickable buttons, labeled Previous, Random... and Next">
</div>
<div class="button-container">
<h4 class="update-header">button corner</h4>
<div class="button-subcontainer">
{#each buttons as button}
<IndieButton button={button} />
{/each}
</div>
<p>to be expanded!</p>
<p class="small-supertext">my own 88x31 button is in the making. ETA: ???</p>
</div>
</div>
</Content> </Content>
<style> <style>
.split-container {
width: 100%;
display: flex;
flex-direction: row;
gap: 16px;
margin: 16px 0;
}
@media screen and (max-width: 900px) {
.split-container {
flex-direction: column;
gap: 8px;
}
}
.button-container {
flex: 2;
}
.button-subcontainer {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
align-content: center;
}
.webring {
display: flex;
flex-direction: row;
margin-left: auto;
margin-right: auto;
}
.webring-img {
width: initial;
}
.me-img { .me-img {
width: 110px; width: 132px;
min-width: 110px; min-width: 132px;
float: left; float: left;
margin-right: 12px; margin-right: 12px;
} }
.changelog-container { .update-container, .info-container, .button-container, .webring-container {
padding: 8px 24px; padding: 8px 24px;
border: 2px var(--color-highlight) dashed; backdrop-filter: blur(var(--blur-radius-background));
flex: 2;
} }
.changelog-header-link { .update-container, .button-container, .webring-container {
text-decoration: none; border: var(--border-dash-size) var(--color-highlight) var(--border-style);
}
.changelog-header-link:hover {
text-decoration: underline dashed 2px var(--color-highlight);
} }
.changelog-header { .info-container, .button-container {
margin-top: 8px; border: var(--border-dash-size) var(--color-highlight-alt) var(--border-style);
}
.info-container {
flex: 1;
}
.info-container > h4, .button-container > h4 {
color: var(--color-highlight-alt);
}
.info-container p, .info-container a {
font-size: 1.0rem;
line-height: 1.4rem;
} }
.webring-container { .webring-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: center;
flex: 3;
/* flex-wrap: wrap; */
/* gap: 8px; */
padding-top: 16px;
padding-bottom: 16px;
}
.update-header-link {
text-decoration: none;
}
.update-header-link:hover {
text-decoration: underline var(--border-style) var(--border-dash-size) var(--color-highlight);
}
.update-header {
margin-top: 8px;
} }
.gradient-title { .gradient-title {
@@ -135,6 +245,12 @@
background-clip: text; background-clip: text;
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
padding-bottom: 12px; }
.page-subtitle {
/* padding-bottom: 12px; */
width: fit-content;
margin: 4px 0 12px 0;
display: block;
} }
</style> </style>

View File

@@ -0,0 +1,39 @@
<script lang="ts">
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
import GalleryRow, { type GalleryRowEntry } from "$lib/lists/gallery-row.svelte";
const subpages: GalleryRowEntry[] = [
{
title: "Drawing Gallery",
description: "Some cool things I've drawn!",
img: "drawings/banner.webp",
altText: "Several Faber-Castell Polychromos colour pencils lined up with markings next to them in the same colour on a sheet of paper.",
link: "drawings",
},
{
title: "Discography",
description: "Small stories about my past music",
img: "/main/hypertext.webp",
altText: "",
link: "music",
},
];
</script>
<svelte:head>
<title>Art | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Art"
banner="banner.webp"
bannerAlt="A rainbow-like holographic effect produced by bending a reflective sheet of cardboard."
subtitle="my creative side" />
<p>Here I have collected the products of some of my creative endeavours. Check them out below!</p>
<GalleryRow entries={subpages} />
</Content>

View File

@@ -0,0 +1,137 @@
<script lang="ts">
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
import { type Drawing, drawings } from "./drawings";
</script>
<svelte:head>
<title>Drawing Gallery | denizk0461</title>
</svelte:head>
{#snippet drawingGalleryEntry({d}: {d: Drawing})}
<div class="gallery-entry">
<div class="gallery-entry-img-container">
<img src="{d.img}" alt="{d.imgAlt}">
</div>
<div class="gallery-entry-info">
<p class="gallery-entry-title">{d.title} <span>{d.date}</span></p>
{#each d.notes as note}
<p class="gallery-entry-note">{note}</p>
{/each}
<a href="{d.img}">view full-size</a>
</div>
</div>
{/snippet}
<Content>
<Banner2
title="Drawing Gallery"
subtitle=""
banner="banner.webp"
bannerAlt="Several Faber-Castell Polychromos colour pencils lined up with markings next to them in the same colour on a sheet of paper." />
<p>I started drawing at the start of 2026 and this is my page to show off what I make! I've mostly drawn on paper so far (I like the feel and resistance of pens on paper as well as the <a href="/blog/2026/0129">limitations</a> it imposes), but I got into digital art with Krita recently!</p>
<p>Why have I created this page, you may wonder? to pressure myself to draw more</p>
<p>If you're interested, here's a post about me <a href="/blog/2026/0205">drawing every day for 28 days</a> to learn to draw. You may recognise some of the drawings there; I picked out my favourite drawings and added them here!</p>
<div class="drawing-container">
{#each drawings as d}
{@render drawingGalleryEntry({d})}
{/each}
</div>
</Content>
<style>
.drawing-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 8px;
}
.gallery-entry {
position: relative;
height: 340px;
}
.gallery-entry-img-container {
overflow: hidden;
}
.gallery-entry-img-container, .gallery-entry-info {
border-radius: 16px;
}
.gallery-entry-img-container, .gallery-entry-info {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: 0;
height: 100%;
width: 100%;
}
.gallery-entry img {
width: 100%;
height: 100%;
object-fit: cover;
transition: scale var(--duration-animation) var(--anim-curve);
}
.gallery-entry:hover img {
scale: 1.2;
}
.gallery-entry:hover .gallery-entry-info {
opacity: 1;
}
.gallery-entry-info {
opacity: 0;
display: flex;
flex-direction: column;
transition: opacity var(--duration-animation) var(--anim-curve);
background-color: var(--color-header-highlight);
padding: 12px 8px;
gap: 4px;
box-sizing: border-box;
justify-content: center;
outline: var(--border-style) var(--border-dash-size) var(--color-highlight-alt);
}
.gallery-entry-info * {
margin: 0;
width: fit-content;
}
.gallery-entry-title {
font-family: var(--font-mono);
font-weight: 700;
}
.gallery-entry-title span {
font-size: 0.8rem;
line-height: 0.9rem;
font-weight: 500;
}
.gallery-entry-note, .gallery-entry-info a {
font-size: 1.0rem;
line-height: 1.3rem;
}
@media screen and (max-width: 1000px) {
.drawing-container {
grid-template-columns: 1fr 1fr;
}
}
@media screen and (max-width: 600px) {
.drawing-container {
grid-template-columns: 1fr;
}
}
</style>

View File

@@ -0,0 +1,90 @@
export interface Drawing {
title: string;
date: string;
notes: string[];
img: string;
imgAlt: string;
}
export let drawings: Drawing[] = [
{
title: "Krita #1",
date: "2026-03-10",
notes: [
"ok i changed my mind on digital art. it's awesome.",
"My first drawing using Krita! I went with my usual methods but tried refining some things and adding (hopefully not overly misplaced) shadows too. I ended up really liking the ability to use layers, and colour in digital art just pops so nicely.",
"Initially, I drew the left arm in front of her body but later changed this to avoid drawing the hand.",
],
img: "2026/0310.webp",
imgAlt: "A digital drawing of a girl with long brown hair in a ponytail. She has green eyes and is wearing a cropped shirt with stripes, an orange spaghetti top underneath, and dark trousers. She is holding her hands behind her back.",
},
{
title: "SMILE! :D",
date: "2026-03-04",
notes: [
"This is actually the construction sketch of a drawing I later went over with a fineliner and coloured pencils. However, I kind of prefer the pencil sketch.",
"This was my first attempt at a head-on perspective. I had fun drawing details like the scrunchie, the jeans, and the smile!",
],
img: "/blog/2026/0205/27-1.webp",
imgAlt: "A drawing of a girl with her head tilted towards her right shoulder. She is smiling with her eyes closed and is holding up a victory sign with her left hand. She has her hair in a ponytail and is wearing jeans with shoulder straps, and there is a scrunchie on her left wrist as well.",
},
{
title: "Cyborg Arm",
date: "2026-02-27",
notes: [
"Possibly my favourite sketch from the drawing challenge, because she looks cool, but also because her design deviates from the other characters a bit.",
],
img: "/blog/2026/0205/22.webp",
imgAlt: "A pencil sketch of a girl with a ponytail, crop top, and track pants with a slightly shocked look on her face. She is looking at her right arm, which is a cyborg part.",
},
{
title: "Porter Robinson fanart",
date: "2026-02-26",
notes: [
"I drew the Worlds hand for practice and then decided to draw Po-Uta's head as well. I realised then that learning to draw gave me the ability to draw fanart.",
"I had never considered that possibility before.",
],
img: "/blog/2026/0205/21.webp",
imgAlt: "Two pencil sketches traced over with a black fineliner. The left one is of a hand with a cube in its palm, sketched after the hand on the cover of Porter Robinson's album Worlds. Beneath it is an emoticon used on the same cover. To the right is a manga-style head with green eyes and wavy hair, meant to resemble Porter Robinson's Vocaloid mascot Po-Uta.",
},
{
title: "Emilia",
date: "2026-02-23",
notes: [
"My first character with the new style of drawing eyes I picked up from a manga drawing book!",
"I named her Emilia because she looked like a more nice and caring character.",
],
img: "/blog/2026/0205/18.webp",
imgAlt: "A pencil sketch of a girl holding up a V sign with her left arm. She is wearing a long-sleeve shirt, jeans, and her hair is tied up in a ponytail. She is winking, the other eye is coloured green. Her body is tilted towards the right side of the paper. In the top right corner is a lightly-drawn sketch of the girl's pose.",
},
{
title: "Elizabeth",
date: "2026-02-18",
notes: [
"She's the product of me trying to re-draw the character I drew on day 1 of my drawing challenge, and I was really glad to see that I had actually improved!",
],
img: "/blog/2026/0205/13-2.webp",
imgAlt: "A pencil drawing of a girl looking to the left. She is wearing a cropped loose tee and jeans, while her right hand is hinted to rest on her hip.",
},
{
title: "bread girl",
date: "2026-01-30",
notes: [
"I drew her during a game of Wizard. I initially wanted to make her chew on a whole loaf but I didn't know how to draw that.",
"Wasn't really sure how to convey that her mouth is full either, but in retrospect, I could have exaggerated the bow in her lower eyelids to do so.",
"I like her eyes. Her head could be taller, actually.",
],
img: "2026/breadgirl.webp",
imgAlt: "An anime-style girl chewing on a piece of bread. She wears a ponytail and a sleeveless top.",
},
{
title: "test",
date: "2026-01-29",
notes: [
"A small sketch (only like 4cm wide) that I drew with a ballpoint pen on pink paper. The fact that I was able to sketch this, without any prior practice, plus an intrinsic want to be able to draw made me seriously consider learning to draw.",
"Having learned just a little bit about drawing, I can say now (a month and a half later) that this isn't great, but it served its purpose of making me start to draw!",
],
img: "/blog/2026/0129/girl.webp",
imgAlt: "A small drawing of an anime-style girl's head. She has a ponytail and is looking towards the left with a concentrated gaze.",
},
];

View File

@@ -0,0 +1,20 @@
<script>
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
</script>
<svelte:head>
<title>My Tracks | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="My Tracks"
subtitle=""
banner=""
bannerAlt="" />
well this is awkward. there's nothing here yet. come back later?
<!-- <p>Fun fact: this page is named 'my tracks' because the folder on my PC where I store my finished songs is called 'my tracks' and it's been like this for a very long time.</p> -->
</Content>

View File

@@ -11,12 +11,14 @@
if (entry.post.banner && entry.post.banner !== "") { if (entry.post.banner && entry.post.banner !== "") {
banner = `/blog/${entry.key}/${entry.post.banner}`; banner = `/blog/${entry.key}/${entry.post.banner}`;
} }
return { return {
title: `${entry.post.title}`, title: `${entry.post.title}`,
subtitle: `#${posts.length - index} // ${entry.post.date}, ${entry.post.time}`, subtitle: `#${(posts.length - index).toString().padStart(2, '0')} // ${entry.post.date}, ${entry.post.time}`,
img: banner, img: banner,
link: `/blog/${entry.key}/`, link: `/blog/${entry.key}/`,
imgAlt: `Preview image for ${entry.post.title}`, imgAlt: `Preview image for ${entry.post.title}`,
description: entry.post.description,
}; };
} }
</script> </script>
@@ -31,5 +33,5 @@
banner="robert.webp" banner="robert.webp"
bannerAlt="View at a tram bridge rising and then curving to the left." /> bannerAlt="View at a tram bridge rising and then curving to the left." />
<Gallery entries={entries} reverseTextOrder /> <Gallery entries={entries} />
</Content> </Content>

View File

@@ -1,123 +0,0 @@
<script lang="ts">
import ImageSubtitle from "$lib/image-subtitle.svelte";
</script>
Recently, I finished a nearly four-month abroad semester in Portsmouth, UK. I wanted to ramble on about my experiences in more detail. While I already have to write a report about my experience as part of the ERASMUS program which funded most of the trip, they aim for 'at least 3 pages' and my first draft exceeded that by nearly 200%...
![](clouds.webp)
![](gunwharf.webp)
## The Trip
My trip to Portsmouth went surprisingly well. German trains are usually known for their delays, but both the EC to Cologne as well as the ICE to Brussels were pretty much perfectly on time.
Taking the Eurostar was a weird experience. Having to go through security checks is strange, both because the UK *should* still be in the EU (it was such a strange and genuinely terrible decision to leave) and because I was boarding a *train*, not a plane. The checks were quite quick though, just a scan of the luggage, then a passport check, and then it's off to the waiting area. You're only allowed to board the train about 20 minutes before departure, but you must arrive to the security checks at least 30 minutes ahead 90 minutes are recommended, and it's honestly probably a good decision to come this early. The waiting area did not have *nearly* enough seats for everyone, but it was fine.
For my trip, I bought an Interrail ticket. They have tickets specifically for ERASMUS students that allow you 4 or 6 days of travel within 6 months instead of just one, but you're only allowed one outbound and one inbound trip to your home country. The ticket is great because it gives you complete freedom over which trains to use **except** the Eurostar, as you *must* book a seat in advance. Those cost 32€. The good thing is that you have a safe seat. It's important to book somewhat early (2 weeks prior is probably fine) and manually pick a seat, as the system can place you on a window-side seat with no view.
The Eurostar trip was quite pleasant. Less pleasant was the ride from London St. Pancras to London Waterloo, for which I took the Northern tube line. I needed to switch branches, so I had to take the tube the opposite way to Euston before switching over to another train headed towards Waterloo. Kind of annoying, but it didn't take overly long.
The last train of the day was the Southwestern to Portsmouth. The ride was fine, though crowded (it departs from London, after all), though I dislike how a lot of British trains have a 3+2 seat layout; within a single row, there are 3 seats on one side, and two more on the other. Since the trains aren't any bigger than they are in Germany, the seats have to be narrower, and the walkway between them is smaller as well. If you have someone sitting right next to you, both of you will be very cramped, even if you're slim. It's an all-around uncomfortable experience.
So, my train rides were fine, right. Everything went well. Except the very last part of my trip. After 12 hours of train travel, I was preparing to take the number 13 bus that runs to Langstone campus. This bus, however, departed mere minutes before I arrived. At least partially at fault were probably the ticket gates (that the UK likes to place at a lot of train stations (despite the fact that staff does check tickets on board)) as well as the bridge that was awkwardly fenced off and required a longer walk as the ticket gates were obviously retrofitted.
What did I do after missing the bus? I walked. As the 13 runs hourly, it didn't make sense to wait. Given how that walk went though, I kinda wish I had waited. For the entire 40-ish minute walk, during which I of course had to carry my heavy luggage, I had to bear the UK's terrible infrastructure. Sidewalks that were crooked and constantly pulled my rolling luggage towards the street as well as traffic lights that effectively penalised walking by delaying on-foot traffic made the trip quite miserable. No lie, I was already regretting the abroad semester by this point, and I hadn't even made it to my flat yet.
## Student Housing
I lived in Langstone West. The housing was decently nice, but the first impressions were quite bad.
I was first greeted by a rather dilapidated campus. Green patches were interrupted by uneven foundations that have seemingly been rotting away for years. An array of shipping containers blocked the view to the north end of the campus. Worst of all was the tall-standing building, the *Barnard Tower*, which looked as if it had been abandoned for a decade. I was mentally preparing for the tower to be my home for the next few months until someone let me know that the student halls were actually further north on the property.
![View at the Langstone campus site from the north end.](langstone.webp)
When I arrived, I met a security officer at the reception who handed me my keys and led me to my room. Weirdly, the literal second I turned my back on him as I tried pushing my luggage into my room, he left. This felt pretty unfriendly and was quite surprising considering the actual reception staff was nothing like this. They were genuinely so nice and understanding and forthcoming about everything you mentioned to them. They greeted you when you passed them, they were up for chitchat, they were just super friendly. One time, our microwave broke, and they literally handed us a new one on the spot. Never had issues with them.
The accommodation was the second-cheapest available (cheapest with individual bathrooms), so I was worried what would await me, but to my surprise, the flats were actually pretty nice. We had a big kitchen with two ovens, two fridges, two sinks, a big stovetop and a lounge area with a TV. The rooms were decent too pretty small (around 10m²) but you had everything you needed for the short stay. The walls were not very insulating, which was quite noticeable in winter when the nightly temperatures dropped near freezing and the cold crept into the rooms overnight. The electric heaters were good though; you could tune them by the degree and even program them so that they would turn on and off at specific times.
Something that I found odd during my stay and especially once I returned to my flat in Germany was how the room inventory seemed fit for smaller people. The chair was much smaller than my IKEA Markus (which, when I first sat in it after my abroad semester felt as if it hugged me); the desk is set very low and crossing my legs beneath it was near-impossible (often cut off my blood flow because of it); the mirror in the bathroom hung lower; the shower was smaller; even the ceiling hung lower than at home!
## The Environment
Living at Langstone was a mixed experience.
The most impactful negative aspect was that there were no supermarkets nearby. A Premier store was at the southern end of the campus, but it's a really tiny one, and Premier isn't exactly a place where you can go to do your shopping in my mind, it's just a shop for alcohol and snacks that for some reason also sells household items and vegetables. The next Co-Op was a 16-minute walk away; Lidl, Tesco, Aldi were almost half an hour away on foot.
I also think that there wasn't a lot to do at Langstone? There was nothing noteworthy nearby. Milton Common was the nearest thing to a park, and aside from that, all you had was residential area. Both the university as well as Commercial Road and Gunwharf Quays (meaning virtually all shops) were on the far end of the island.
However, a 20-minute walk brings you to Eastney beach a great spot for when you need a quiet spot outdoors that offers a pretty view at the Solent with the Isle of Wight on the other side. It's a rocky beach (pebbles instead of sand). In fact, all along Portsea Island's perimeter you had some very nice beaches; South Parade Pier was quite nice with the Rock and Rose Gardens nearby, and the waterfront area at Gunwharf Quays was quite pretty too. The beaches are currently being renewed; Portsmouth is reinforcing its sea defences, and while doing that, they're going a step further by redeveloping waterfront areas. It's quite nice and well worth the visits.
If you want to party and don't mind noise, you may want to look for another accommodation though, as Langstone itself was quite a serene place. It's a quiet place where you can really live a stress-free life. At least that's the experience I had, and I quite liked that.
## The City
![](portsdownhill_dark.webp)
![](portsdownhill.webp)
![](spinnakertower.webp)
## The Trouble With Buses
Something I really didn't like about the UK and that I have, in great detail, already told many people about against their wishes was public transport.
Firstly, ownership of the transport companies plays a big role. It sounds odd, but for example: my city has a 100% stake in the public transport company running out trams and buses. This allows them to have their say in how public transport is ran, which is important since the politicans (ideally) want good transport options for their citizens.
![German illustration about public transport passengers being eligible voters from the magazine Der Spiegel. It depicts a huge amount of passengers crammed into an overfull bus as well as a long line of people still trying to get on the bus.](fahrgaeste.webp)
<ImageSubtitle content="The headline translates to: 'Small tip for big politicians: 15 millions passengers are 15 million voters'" />
In the UK, however, the buses are almost always privatised, and so it feels as if the bus companies are weighing profits too high and customer care too low.
I found it particularly strange when cities have more than one company operating their network, especially since these companies usually don't exactly cooperate. Portsmouth had two First Bus and Stagecoach and it's just such a mess. No one publishes a proper map for their services, all their apps are rubbish and of course don't help you for services provided by other companies, the tickets are different between providers and have different validity areas, timeframes, lines you can take... ugh...
Trying to learn the routes was so annoying because no one provided a half-decent map. Stagecoach publishes one of just their services but without individual stops listed. The city of Portsmouth provides a combined map of all services, but it's extremely hard to read as all lines are coloured green, so they effectively mark streets where buses run on, but not the stops they actually serve, which is nonsensical because some lines run routes that suggest you can change over to another service, but they don't actually stop anywhere near the crossover section. One of the worst offenders for this is the 18, which runs on the roundabout between Pier Road and Duisburg Way where it crosses the lines 23 and 25, but it **just runs straight through with no stop!!** What fucking idiot came up with this?? Stagecoach runs all of these lines themselves! Oh and, First Bus can't be arsed to provide *any* map whatsoever. None at all. They should genuinely be embarrassed.
The services operated really weirdly as well. I saw many instances of bus lines from different operators directly competing for passengers. And as if that wasn't already bad enough; buses compete for passengers with other bus lines and with **trains** too!! Portsmouth had this too, with the First Bus X4 and X5 lines to Southampton as well as the Stagecoach 700 to Chichester. Serving stops in-between major train stations is important, sure, but the trains stopped really frequently anyway almost as if they were genuinely viewing the buses as competition...
I was particularly badly hit by the lack of good public transport options. Langstone Campus was served by only two lines: the 13, and the U2.
The 13 ran hourly, but it felt as if the timetable was seen as a recommendation, given that it liked to show up 10 minutes late or even 5 minutes early, and you can never really predict what it'll be. The 13 fucked me over particularly with its early departures, which meant I frequently had to wait for the next 13 in an hour or walk. Plus, the 13 didn't run at all on some days during the holidays. No service whatsoever. Apparently, however, this is a normal thing in the UK and even the **LONDON TUBE COMPLETELY STOPS RUNNING** around Christmas! How one of the biggest cities on this planet can handicap itself this badly, I will never understand. Run a reduced service, of course but **NO SERVICE, WTF??**
The U2 was even worse. It was free but I wouldn't have wanted to pay for a service this atrocious anyway.
First off, it ran every 50 minutes. *Fifty!* For one, this was insanely inconvenient. Also, this didn't even line up with the university timetable, as all lectures (as far as I could tell) started on the hour.Considering the U2 is a **university bus line**, I cannot grasp how the university can willingly pay to run a service this awful. Having a lecture at 14:00 was the worst, because it meant you'd have to take the bus at 12:50. That's 70 minutes before the lecture starts, for a route that takes 19 minutes. And if your bus didn't show up, as had happened to me tough luck, you're missing your lecture. As an added bonus, the 50-minute frequency meant that layover times at the end stops were too short to catch up with the frequent delays, or just give the drivers any kind of rest, really.
![Interior view of a First Bus on the U2 service](u2interior.webp)
Seccondly, the bus was terrible. They always ran with the oldest bus First Bus had, which would *vibrate heavily* and loudly all throughout the ride. It was also woefully undersized for some of the crowds, especially considering the U1 got electric double deckers running every 15 minutes despite the fact that *almost no one was using them*. Having only a single door where everyone had to scan their ticket made call times at certain stops extremely long too, as you'd have to wait for everyone to get up which in Portsmouth they apparently don't do until after the bus driver has opened the door then leave, then everyone has to get on, scan their tickets...
Thirdly, the bus doesn't have announcements! Or at least it didn't. After I wrote a *very* long e-mail to the university estates team about how genuinely awful their bus service was, they pretty much ignored everything I said, *but* they silently introduced announcements! I was shocked when I saw and heard them on the U2. A standard feature on literally any bus, literally absent from this bus, but finally no more?
Kind of. In the end, only like a third of the buses had the announcements. They also hardly worked. From day to day, new issues would arise where the displays skips stops or even introduces new ones that aren't actually served by the line.
![Close-up of the U2 university bus heads-up display showing the next few stops](u2hud.webp)
Oh and, the buses didn't run at all during the entire holiday period a *month*. The last bus of 2025 ran on the 19th of December, and the first bus in 2026 ran on the 12th of January. It seems that no one at the university cares about the students living in halls during the holiday period. I was very negatively affected by this, since Langstone campus is *so* remote; the nearest supermarket is a 25-minute walk away.
It genuinely felt as if the university either didn't care about its students, or they are trying to get rid of the buses. The latter I definitely think to be true; apparently it's normal in the UK to have students pay for the university buses (such bullshit). Portsmouth is the exception, but even they are giving up on this, as staff now has to pay for the Portsmouth university buses. Plus, the uni's estates team complained about the cost of running the buses when I contacted them (duh, how about don't build a campus on the other side of the island?). I'm assuming they are trying to actively reduce ridership so that it sinks to a level where they can 'justify' cutting the service entirely.
![Two Routemaster buses parked in front of Euston station in London](routemasters_euston.webp)
My experiences outside of Portsmouth weren't exactly great either. Cardiff charged me nearly 3€ for riding five stops on the line 6, and even London's Routemasters weren't that great. I only took one on the line 68 to get from Waterloo to St. Pancras International, but the ride felt representative of the London bus experience.
For example, the driver wasn't unfriendly, but definitely quite impersonal. When I asked him whether my tap-on had gone through, he only communicated in hand gestures, ending with a thumbs-up. Although I guess that was all the information I needed, so it can't have been too bad.
The interior of the bus was worn, not at all how I'd expect London's premier buses to look. Functional, but not a super pleasant experience. It was also a double decker, of course...
Okay, not sure if this is a hot take, but I dislike double decker buses. I do think the concept is quite cool, and I do like sitting up top for the view. However, they're inaccessible, they lengthen call times at stops, and it's just really hard to get up or down, especially when the bus is moving! I found them to be an even bigger issue in Portsmouth, where I frequently saw double deckers that were completely empty on the upper deck, with everyone sitting downstairs. A significant chunk of ridership in Portsmouth is seniors probably because a) the buses are unattractive for anyone needing reliable transport, and b) they can ride for free and they quite literally cannot access half the bus.
I did appreciate the flat £1.75 fare on London buses though probably an incentive to take some pressure off the tube, I imagine. Way better value than Portsmouth's £3 "capped" fare.
## The Return Trip
<!-- swr not really offering luggage spaces, had to sit next to the toilet
eurostar 45min delay fuck you, missed my connecting train and had to wait 2h for the next one in brussels. -->
After being away from Germany for so long, was I glad to see ICEs and other German trains again.
![An ICE 3neo calling at Cologne Central Station, Germany, covered in some snow](ice3neo.webp)
<ImageSubtitle content="The snow was the icing on the cake." />
What's crazy is how positively I raved about German public transport. We are *by no means* perfect. There are lots of issues especially in rail transport, and there are a lot of improvements to be done in local too. But in comparison to the UK, it's literally night and day. Like the fact that the bus right in front of my house runs every 7.5 minutes from 6:00 to 18:00, and still pretty frequently outside of those hours. Or that, if I don't want to take that bus, I can take the tram that's right nearby as well, and in a year's time, there will be a second tram line running here. Or that we have the '[Deutschlandticket](https://deutschlandticket.de/)' that allows us to use virtually all of Germany's public transport without trying to figure out ticket validity zones and whatnot. Or that we have way more than just buses trams, S-trains, underground trains and they're not just reserved for the capital. Even our damn ferries are cheaper by orders of magnitude.

View File

@@ -14,8 +14,7 @@ I'm posting this to hold myself accountable and to actually pull through instead
image="01.webp" image="01.webp"
altText="Drawing of day 1. A girl looking to the left. Her shoulder-long hair is flowing free. She is wearing a cropped t-shirt and a pair of jeans. Her left hand is on her hip." altText="Drawing of day 1. A girl looking to the left. Her shoulder-long hair is flowing free. She is wearing a cropped t-shirt and a pair of jeans. Her left hand is on her hip."
subtitle="Result of day 1. I think she's pretty cool." subtitle="Result of day 1. I think she's pretty cool."
alignment="left" alignment="left" />
/>
<span class="date-marker">2026-02-06, 18:47</span> <span class="date-marker">2026-02-06, 18:47</span>
@@ -30,3 +29,696 @@ Arms are troubling too, not because they're insanely difficult to draw, but beca
I was too afraid to colour the drawing, worried I'd ruin it, but if I had done so, I'd have given her purple eyes. Don't know why, but that's the one colour detail about this drawing that I was sure of. I was too afraid to colour the drawing, worried I'd ruin it, but if I had done so, I'd have given her purple eyes. Don't know why, but that's the one colour detail about this drawing that I was sure of.
Not sure what to draw next, but I think I'll either go for another person but from a different perspective, or an object. Not sure what to draw next, but I think I'll either go for another person but from a different perspective, or an object.
## Day 02: Struggle
<SubtitledImage
image="02.webp"
altText="Drawings of day 2. The drawings include a black silhouette of a girl taken from the Bad Apple music video, a smiling water tower, a tuna fish, a tuna fish can, a character with shoulder-length hair looking to the right, and one without hair looking somewhat straight."
subtitle="Day 2 was a day of struggling."
alignment="right" />
<span class="date-marker">2026-02-07, 20:52</span>
Well... I persevered. That's probably the most positive thing I can say for today. Urge to delete the post and quit the challenge was strong.
I didn't really know what to draw, so I started copying a frame from the beginning of Bad Apple, which I first wanted to detail but then decided to fill black because the details looked bad.
Out of ideas, I looked up above my monitor and stared at the vinyl record sleeve for underscores' Fishmonger album, so I drew the water tower on the cover. Fittingly, I tried copying a tuna fish I found online, and then drew the can with no reference (can you tell?).
I was then *slightly* motivated after watching [this video on drawing](https://youtu.be/XeIR7P82aPU) by pikat and drew first the head in the bottom left, then the one bottom centre. I kinda like the head shape of the bottom left one.
I think something that's definitely hindering me is a lack of direction, and possibly motivation too, just like with my other projects. I don't really know what to draw, how to draw, what to improve. I'll try watching some more videos, but I'm a bit afraid of falling into the tutorial trap and not being able to draw things without 1:1 reference. I do actually have a handful of ideas I'd like to draw, but I feel I'm not skilled enough to successfully draw them, so I'm kind of holding off on trying them.
Honestly: this felt super stressful to do today! I felt like I had to perform, but I kept postponing all day, just to feel the need to churn out something in the final hours of the day. Being done for the day feels like a relief, but tomorrow's attempt is already looming on the horizon.
## Day 03
<SubtitledImage
image="03.webp"
altText="A copy of Asuka from Neon Genesis Evangelion."
subtitle="An attempt was made."
alignment="left" />
<span class="date-marker">2026-02-08, 11:45</span>
Last night, I remembered some screencaps I took of Neon Genesis Evangelion as reference material for 3D modelling and decided I could try to use it as reference for drawing as well. So I did! I tried to draw Asuka.
I started with the head shape and definitely immediately screwed up, as I made her chin way too long. The eyes didn't turn out too bad; definitely a little better than yesterday's attempt at perspective.
Tried to do shadows/shading as well, and it turned out kind of neat, though obviously without much thought as it's clearly just a carbon copy.
I'm wondering whether I should try to trace some art, just to get a feel for dimensions? Again though, I don't want to depend on tracing, so I'm a bit wary of trying it.
## Day 05: An Uptick
<span class="date-marker">2026-02-10, 18:55</span>
Listening to some good music. Signing my work contract so I'll be out of unemployment from tomorrow (don't worry it was planned). I'm in a good fucking mood, here we go.
I didn't draw yesterday unfortunately, but I didn't do this to quit the challenge! I was just really busy I was out and about from 9 in the morning to 9 in the evening, and considering how bad I felt after day 3 of drawing, I didn't exactly feel like picking up the pencil this late in the day either. I bought an IKEA [Tertial](https://www.ikea.com/de/de/p/tertial-arbeitsleuchte-dunkelgrau-50355395/) lamp which gives way better lighting for drawing than my room lights do. Yay to setup improvements!
<SubtitledImage
image="05.webp"
altText="An array of anime faces, all looking to the left. A few eyes are also in the corner. The references used for the faces are displayed as well, bearing some but not too much resemblance."
subtitle="A few cute faces, drawn using references but not relying on them 100%!"
alignment="right" />
I drew a couple of faces again. It looks like this is the direction I'm heading in. Before I started drawing anything, I watched one of PewDiePie's videos on how he learned to draw I don't usually watch his videos, but I remembered that he challenged himself to learn to draw as well, and that he was quite successful. It managed to spark some motivation in me, so the first thing I did was try to copy one of the girls he drew (she's on one of his thumbnails as well). I changed some small things like placing the ear a little higher. I don't like this type of style quite *as* much (see the note about the nose next to the drawing) but it still turned out quite cool and I like her.
I then experimented with some eyes, from open to closed. The big closed eye at the bottom was actually copied from a screenshot of [Laura with her eyes closed](/projects/projectn5/devlog/2025/1022/#blinking)! I then used this very screenshot as a reference to draw Laura as well!
It was pretty cool to draw my own character, I gotta say. I drew her head noticeably shorter than on the screenshot, which resulted in a more chibi-style look. It's cute, I think.
The third girl, in the bottom left, was half-freely drawn. I drew her eyes and then her head shape while trying to draw a smiling/happy girl. I then had no idea for the hair, so I used a reference I got from [a pikat video](https://youtu.be/XeIR7P82aPU?t=91) for that. I specifically wanted to draw a girl with a different style of nose than the PewDiePie reference, and it worked out!
I found that I tend to draw some things too big. Noses turn out too long, eyebrows turn out too wide or too high. It might also be because I keep drawing with dull pencils. I like that they're easily erasable, but the lines are never as sharply defined as I'd like them to be, so I keep redrawing lines which just makes them thicker. That's a problem I didn't have with [my first drawing](/blog/2026/0129/); maybe I should try to draw with different pens as well? I was even thinking of trying digital, I even installed Krita on my Surface tablet, but I haven't dabbled much with that yet.
All the girls I drew are also looking towards the left. I'm assuming this is because I'm right-handed and it's easier to draw the lines I need for a left-facing face than for a right-facing one. Nevertheless, I should definitely try to draw some right-facing characters as well. I think it'll help with symmetry (something I also struggle with).
Overall feeling very good about today's drawings much better than two days ago!
## Day 06
<span class="date-marker">2026-02-11, 20:56</span>
I didn't have any kind of clear goal for today, but I did enjoy the sketching. After watching [Eddy Burback's video](https://youtu.be/nnsyGSTKlw0) on how he locked away his phone and lived a largely more enjoyable life because of it, I chose to not listen to music or watch any video while drawing. It was quite a serene experience.
<SubtitledImage
image="06.webp"
altText="An assortment of hands, legs, bodies and heads sketched on a piece of paper using a pencil."
subtitle="today was a rubberless% kinda run"
alignment="left" />
For the most part, I was just testing thing without sticking to just faces. Most importantly perhaps: no perfectionism! I didn't use my eraser *once!* The focus was on trying more rather than perfecting one single drawing. It did work to my benefit, in a way; I drew bodies, heads, even hands.
I talked to a friend of mine earlier today about drawing. Thing is, she's a pro at it. She's been doing it for ages, she's studying art too, and she does insanely cool paintings. She did give me quite a few tips when we talked, but I did notice that a bit of it was way above my level. At one point, she started sketching a realistic eye, telling me about minute details like the positioning of eyelashes, and while I didn't see a direct connection between her advice and my drawings, I listened and watched in awe as she drew a really good-looking eye from what I assume is just experience and possibly my eyes as a partial reference.
We also talked about perfectionism and how it can be beneficial to draw without erasing constantly like how I drew [my drawing from two weeks ago](/blog/2026/0129/) using a ballpoint pen instead of a pencil. No going back using that. I did intend to use a gel pen today, but I kind of shied away from it for now. Thinking about it now, a ballpoint pen may be better actually, because it draws finer and less bold lines.
She also encouraged me to take a sketchbook with me wherever I go. I mostly already do that, but today for example I didn't as I didn't bring my backpack with me. I should have a small notebook lying around somewhere one that I intended to use for drawing years ago but never used so I'll try and find that.
She also encouraged me to try figure drawing; using nude(ish) human bodies as drawing references to learn anatomy and things like body flow. I may try that soon, because I definitely find myself struggling to draw characters in poses.
To comment a bit on the drawings: the heads look weird, I think I'll practice them a little more tomorrow, maybe. The body went in a decent direction but the hips look like they're pointed in the opposite way than I intended. For the big hand, I used my own left hand as a reference, but with the details it started to look kind of witch-like. The smaller hand I drew right after looks a little cuter. The legs up top, which actually were the first thing I drew today, look okay. I like the curvature in the right foot.
## Day 07: \\__*
<span class="date-marker">2026-02-12, 21:55</span>
I found the small notebook and went for ballpoint pen sketches today.
Patrick was the first drawing today, completely separate from all the other stuff too. I kind of just drew him to show some people at university as an IRL reaction sticker. Still wanted to include him here.
<SubtitledImage
image="07.webp"
altText="An assortment of sketches drawn using a blue ballpoint pen. On the left is Patrick from the show SpongeBob showing a thumbs-down in a booing pose. On the right are some heads, one of which mimicking the look of the musician Jaron on the cover of his album LIGHTYEARS. A hand and two attempts at drawing crossed legs are also depicted."
subtitle="seven days a week, it's time to make it count"
alignment="right" />
I looked at some people on the bus today (shocker, I know) and one person on my way back home from uni made me realise that I had kind of fucked up ear placement, neck flow, and head shape for a while. From a 45-degree angle, the ear is fully visible but it's still mostly within the head silhouette. I then drew the drawing in the top left to try this out, and it did look more natural. I think the head turned out a little too narrow, but quite decent still.
Although I just looked at myself in the mirror and what I just wrote wasn't exactly what I'd seen so I'm not entirely sure.
As I was listening to *LIGHTYEARS* by Jaron, I stared at Jaron's face on the album cover when I decided I could try to draw him. **HIM??**
yeah i drew a guy for the first time. 7 days in.
The first try went pretty goblin with a massively oversized ear, so I tried again, and it's definitely recognisable, I'd say. I found it interesting how his head is drawn with way straighter lines than all the girls I had drawn up to now, where all shapes are much more curvy and wavy. Just look at his neck; it's so straight and thick compared to, say, the head in the top left.
I also tried drawing his right hand fully as in, not obscured by his head and it went eeeehhh
Lastly, I attempted to draw crossed legs from a front perspective. Turns out, I really didn't know what I was doing lol. Trying to figure out where the legs go, where and how they cross, and how they connect to the body is a challenge, and I was doing it with no reference! Probably a mistake.
## Day 08: Bulbous Buttocks
<span class="date-marker">2026-02-13, 21:30</span>
Today felt quite forced again.
<SubtitledImage
image="08.webp"
altText="Some faces drawn with a blue ballpoint pen. Some of them are not filled with facial features, and some are scribbled over. The bottom of Captain Qwark as seen in the game Ratchet & Clank: Tools of Destruction is also drawn."
subtitle="these impeccable glutes and bulbous buttocks!"
alignment="left" />
I waited with drawing until late in the day again unfortunately, which meant I felt this need to draw despite not really having the motivation to do so.
Actually, I did have one thing I wanted to try and draw; I saw a person standing at the tram stop earlier today, wearing a beanie, and I wanted to try and draw her. My version definitely doesn't look like her, but I mostly wanted to use the opportunity to try and draw a) a beanie, b) the hairstyle, and c) eyes from a side perspective.
I then tried copying another one of PewDiePie's sketches (I still had the tab open) and failed lol. I then messed up trying to copy another drawing. After that, I wanted to draw Captain Qwark but ended up drawing his rear end because it was the first picture of him I could find on my PC.
Minor looking through my Pinterest pins got me to try and draw a guy wearing a Mario hat and looking up at the sky, which went poorly, and then I also kind of messed up drawing the type of head I thought I could do kind of okay.
Not the best day, and I am once again questioning why I am doing this challenge, but I guess I gotta see this through to the end.
## Day 09: Gaining Perspective
<span class="date-marker">2026-02-14, 21:36</span>
<SubtitledImage
image="09-small.webp"
altText="An anime face, an outline of a face, and a scribbled-out head shape drawn with a blue ballpoint pen, and a head shape drawn with a pencil. Only the last one has construction lines creating a depth effect."
subtitle="freely drawing. no guidance. no goal. kind of demotivating."
alignment="right" />
Today, I had some ideas for things I could try to copy (still abstaining from tracing!). Among those things were a picture of Anna (Anna_Chess) and Kevin (Call Me Kevin) as well as a random anime-style girl I probably screenshotted a few days ago for this specific purpose. The first one didn't work out AT ALL because of how little I knew about perspective, and the second one turned out... okay.
I then decided to look up tutorials, which was a *very* good idea.
I found someone recommending mikeymegamega's videos, so I checked out his channel. I found a lot of videos, most of them too advanced for me and also quite... horny... but nonetheless very interesting. I ended up watching [this video](https://youtu.be/_05or04sGAo) on mapping characters' heads and faces. I think this video assumed knowledge of prior videos, which I obviously haven't watched yet, but it was still pretty simple to follow along.
<SubtitledImage
image="09-big.webp"
altText="Anime-style heads drawn using a pencil. All of them have construction lines and are looking in different directions, which are distinctly recognisable."
subtitle="following mikeymegamega's tutorial. i'm actually able to learn perspective and proper drawing techniques through this..?!"
alignment="left" />
You can notice the point at which I started following along with the tutorial because I switched back to my pencil and started using construction lines (see I'm learning terminology!!). I also switched to my A5 notebook because the pocket-sized one was too small; in fact, in retrospect I wish I had drawn much bigger, like almost page-filling, because these small drawings + using a somewhat dull pencil starkly inhibited my ability to draw details.
It was actually quite fun to follow along and see drawings come 'alive' through my own doing. 'Alive' is relative here as watching the whole tutorial reveals the skill level mikeymegamega's at, and the final results are insane. It's crazy what someone can do with just a pencil and some paper.
He talked about perspective, head shape, face proportions, and it stuck just a bit better since I was able to follow along at the exact spots where these things were relevant. My drawings are nowhere as good as his, but I'm still quite happy about how these went, and they kind of motivate me to keep going!
I'm not the type to watch tutorials very often, but this proved to me once again that it can be really helpful to do that sometimes; especially when you're struggling with motivation!
Oh and also, very important: this tutorial of his quite literally started with drawing a simple circle for the head, which I struggled with so much I almost got frustrated. While practicing it though, I discovered that it's way easier to draw a shape like a circle when I'm using my arm to draw instead of my wrist! Drawing big shapes with your wrists is difficult because they need to bend weirdly to stretch to the dimensions needed, whereas the arm allows for a much smoother motion with these sizeable shapes.
## Day 10
<span class="date-marker">2026-02-15, 22:02</span>
<SubtitledImage
image="10.webp"
altText="Two anime-style heads. Both are looking to the left, but one has their head tilted to the right. Both are drawn using a pencil and contain construction lines to mark out the general shape."
subtitle="picking a cool pose can make quite the difference."
alignment="right" />
For today's part of the challenge, I mostly tried to continue with mikeymegamega's approach I learned yesterday. It went okay!
I first did the head on the right. The head actually looks quite big, gives me Megamind vibes maybe some hair would make it blend better. I think it turned out okay overall, though a bit boring. Perhaps the ear is a bit small.
The second drawing, on the left, looks more interesting, I think. I went back to the video and used a still image as a reference. I found myself erasing and re-tracing a lot. Since I had a *bit* more of a goal here than I did a few days ago, I wasn't quite as bothered by this though. The perspective isn't ideal (nose/mouth look a tiny bit off), but the pose makes me like the second one quite a bit more!
I was actually kind of bothered by my tools today more so than by my skills. I noticed that my eraser kept leaving red marks, and the paper of the notebook I'm using is pretty thin, so previous drawings shine through (more noticeable in-person than on the scan). Worse yet, when I try to finalise lines and draw them with more pressure, they press through to 2-3 pages after. I'll get a new eraser tomorrow probably, but we'll see about the notebook, I don't want to chuck away this one after only having used it for a couple of days.
I wonder what I should draw next. Maybe I'll try using a photo as a reference pic and draw the head of a person using this technique; learn how to evaluate and draw poses on my own, without the guidance of a tutorial.
That type of freedom is my end goal.
## Day 11
<span class="date-marker">2026-02-16, 21:45</span>
Getting up to draw today was not easy. It's not that I dreaded drawing necessarily, but I feel it going the same way as my other hobbies: it's so hard to start. I don't know why I always struggle with motivation like this, but I haven't found a fix for it yet either.
Admittedly, I didn't draw quite as much today as I need to head to bed soon; I have to go to work early tomorrow. Still, I could have drawn earlier in the day, when I had time for it... I did plan to do exactly that, actually. For several days now, actually. I can never muster up the motivation to do it, unfortunately.
<SubtitledImage
image="11.webp"
altText="The head of a character looking upwards. To their right is a tube as well as a cube with the text 'BLENDER DEFAULT CUBE'."
subtitle="they're looking up, kind of, but i'm not sure what exactly they're looking at."
alignment="left" />
Anyway: I drew this head with no direct reference! I mostly drew it freely and only looked back at yesterday's drawings to confirm some positioning. I also used a fineliner to draw the final lines instead of using excessive force with my pencil. Created some nicer lines, though of course it makes them 100% final, so there's a big risk of fucking up.
I used a little test drawing (in the top left) to roughly sketch out the perspective, and it worked out decently.
Afterwards, I didn't really know what to do because I'm kind of getting bored of drawing the same heads with no changes really, and I don't know how to properly draw something else either. I watched another one of mikeymegamega's videos, this one on [basic shapes](https://youtu.be/gMjpAYASbC8), so I drew some *forms*. Of course the cube reminded me of a much more familiar cube.
mikeymegamega's "Beginner Drawing Tutorial" series continues with videos on shading and perspective; I'm not sure whether I'll watch them soon, because they don't feel right for me currently. Something something too advanced, also not the direction I want to head right now. They did remind me of school, however. I remember that in art class, we often had to do things like draw a scene in a vanishing point perspective, or try to copy our own eye or something. Retrospectively... I felt very underprepared for that. I hardly knew how to draw, so trying these things, while fun, wasn't exactly ideal. I do recall others struggling with the perspective in particular and finding the challenge frustrating rather than enjoyable. Who knows whether that influenced their perspective on creating art.
## Day 12: Close Your Eyes
<span class="date-marker">2026-02-17, 22:32</span>
So I bought this book today.
<SubtitledImage
image="12-book.webp"
altText="The book 'Manga zeichnen leicht gemacht' by HIkaru Hayashi. It's a German version and it depicts three manga-style girls on its cover."
subtitle="this one" />
I went to a flea market store (yes that's not a mistake; an indoor flea market-like business) with friends earlier today, and I discovered this book on drawing manga characters. It's issue 5 in its series and focusses on 'bishoujo' characters, which the book also refers to as 'beautiful girls'. I'll be honest I felt a bit awkward picking up this book, especially since some of its contents are kind of... horny-coded. Not unlike mikeymegamega's videos, I suppose. But there are a lot of cool references and tips in this book, like on dimensions of body and face parts, positioning and its respective effects, etc. I initially put the book back down, but after like 10 minutes of thinking that I'd kinda like to take the book with me, I finally bought it. Finding *this* book, a guide for a style I personally want to go for, in the middle of a drawing challenge? It can't have been coincidence.
<SubtitledImage
image="12.webp"
altText="Three drawings of manga-style girls, all with closed eyes. The top left one has shorter hair and a content facial expression. The top right one is drawn from a side profile view and is shouting. The bottom drawing is of one with long tied-up hair."
subtitle="I like the top two ones; the right one shouting, and the left one completely content"
alignment="right" />
I had a look through more than half the book and found some drawings I wanted to try and copy. Of course, I used the technique (singular) I had previously learned to accomplish this, and it worked out quite decently.
I still struggle with perspective, that's for sure. The bottom one isn't quite looking in the direction I intended her to, though she still looks ok. I quite like the top left one. There's a bit of authenticity in the drawing with the construction lines, which I oddly like. I also drew the top right one just because it looked fun and I wanted to try it. I like the exaggerated emotions you can depict in this artstyle; not something I'm *quite* ready to experiment with yet I am still lacking lots of basics but I copied this one just to get a feel for it.
Honestly? I think the heads I draw look pretty alright. I think if I keep practicing just the heads, it'll get boring, so I may try to do bodies/torsos next, just to keep things interesting. Combine torsos and heads to match their sizing. I feel like I'm slowly getting the hang of both drawing and finding resources for drawing.
Oh, and hair. Hair is a big challenge. mikeymegamega has a video on that; I may watch that tomorrow. I think hair can make the drawings look SO much more interesting, so I'm both afraid (due to its difficulty (I assume)) and excited for it.
On a related note, sometimes I look at the framed picture of Snatcher from A Hat in Time on my desk and I think to myself that I'd like to draw him. Now I'm thinking that I'd like to draw him in this manga style.
I would fucking love that.
## Day 13: A New Hope
<span class="date-marker">2026-02-18, 23:08</span>
Had a small crisis. Still had a really good drawing day. Let's go.
So as I had written yesterday, I wanted to start to practice drawing bodies today. In order to learn how to do that, I first turned to mikeymegamega to find a video on the topic. This was already a pretty tough task.
Most of his videos are so... horny. Yeah I can't think of a better word. *So many* videos on drawing huge female features, when I just want to learn how to draw a body at all. Add to this the fact that the one video of his from 11 years ago I found where he mostly went over the basics of drawing a body, he still went with the 'now let's draw some huge boobs' shtick, plus he used some pretty derogatory language, and that evoked enough discomfort to make me find a different way to learn what I wanted to learn.
<SubtitledImage
image="13-1.webp"
altText="Pencil sketches of three female bodies drawn using a method where a triangle represents the torso, from the shoulders to the crotch, and then the rest of the outline is filled in afterwards. The first one has a raised right leg, while the other two ones are standing straight. The middle one has the comment 'too long?' written next to it, while the right one is noted as 'better'."
subtitle="my initial body drawing trials. they went pretty decently actually"
alignment="left" />
I then wanted to find another YouTube video on the topic, but I don't like going through random videos because they could be of dubious quality. That's something I can evaluate well when it's a topic I know a lot about, but with drawing I really need some good guidance.
Then I thought... I just bought that book on drawing manga characters. There's a section on drawing bodies. Might as well make the most of it. And so I did!
The book went with the approach of drawing a triangle between the shoulders and the crotch to represent the torso, and then adding curves for the shoulders and hips. It's pretty simple, actually, so I didn't really need more guidance than the few reference pictures on the page. I started off by copying one of the drawings (on the left), which had a girl sitting with her legs crossed, though I did not draw the other leg. I then tried two bodies of my own.
It's so important to just freely practice, because it allows you to identify areas you need to work on. I don't do it enough. Here I noticed that my first body drawn without reference (middle) looked too long for my liking, so I fixed it in the second one (right)!
After that, I wanted to combine my learned knowledge and draw a body *with a head!* But what exactly should I draw...?
<SubtitledImage
image="13-2.webp"
altText="A pencil drawing of a girl looking to the left. She is wearing a cropped loose tee and jeans, while her right hand is hinted to rest on her hip. The drawing starkly resembles the girl drawn on day 1 of the challenge."
subtitle="it's day 1 girl and she looks SO MUCH BETTER i'm so enamoured with her"
alignment="right" />
And then I had an idea.
*What if I try to re-draw one of my previous drawings?*
And so I did!
I drew a fresh interpretation of [the girl I drew on day 1](#day-01), and I gotta say it turned out *so good.* I really *really* like it because this has given me the chance to compare my skill at the start of the challenge to my skill now. It honestly feels like a huge change already.
I think the biggest changes are dimensions and shape. Facial features and her overall body are just sized more appropriately than before. The rounded body shape, especially around her torso and hips, looks way more interesting. There's perspective too!! Her shirt flows more nicely. At the front of her trousers, there's a small curve that gives just a hint of depth. Her shoulders are tilted and it looks *so* cool. I'm actually really glad I re-drew the initial body triangle early on to give her that tilted pose.
I decided to omit the hands because I figured I'd screw them up (haven't learned them yet, after all), and I *really* didn't want to fuck up this drawing. I also didn't go over the sketch with a fineliner to trace the outlines, also because I was worried I'd fuck up the drawing.
Don't get me wrong, this isn't a masterpiece by any stretch of the imagination. I'm just so hyped because this may just be one of the best things I have drawn so far, and it shows that I have genuinely made progress in this challenge.
This has me really excited for what's to come. Maybe this hasn't all been in vain? Maybe all of this effort might *actually* lead to an improvement in my drawing skill after all?? There's finally some method to my madness, and it's visibly starting to pay off. I'm now very motivated to learn more about drawing body parts (which I also wrote next to the sketch lol) to make my future drawings even better.
Also, just on a side note: I finally bought a new eraser, and it's way better than my previous one. Leaves way less residue after erasing too. I did also notice though that I've sketched more lightly than I did these past few days, which I think is a good thing.
## Day 14
<span class="date-marker">2026-02-19, 22:06</span>
<SubtitledImage
image="14.webp"
altText="A head drawn using a pencil. It has sketch lines and a roughly-sketched short hairstyle."
subtitle="trying to get better at hair"
alignment="left" />
This is just a quick drawing to show that I did anything at all today. I considered skipping because I was, frustratingly, busy for longer than I'd have liked today, and I'm also not feeling super well. I figured though that it would be better to do any amount of drawing because it'll keep me in the rhythm.
I started following a mikeymegamega tutorial on hair (trying to pick out the tutorials that aren't horny af) and followed along with drawing the first head. It's interesting so far because I haven't really had a feeling for three-dimensionally mapping out hair yet. It feels like something that could be quite complicated, but I'm in for the ride.
## Day 15: sick
<span class="date-marker">2026-02-20, 20:50</span>
No drawing today. I'm feeling unwell and I can't get myself to start drawing. It feels like I'm on the tail end of a sickness, but this only started yesterday, so I don't know where this is going, but I do trust my immune system to get me back up to speed soon.
<SubtitledImage
image="15-paper.webp"
altText="A Gerstaecker-branded art pad."
subtitle="this paper is almost too nice for my drawings."
alignment="right" />
I did go outside early-ish in the day today, partly to catch some fresh air (which did make me feel a little better), and also to get new art supplies! Nothing too fancy; I bought an art pad with higher-weight paper than what my current notebook has: 180g/m² instead of 80g/m². This'll most assuredly help with the sketches shining through pages. It also has a different paper texture. It's a little rougher. Actually, each sheet has a finer and a rougher side, which is pretty cool.
I bought this at an art supply store, which felt a bit odd to do. Last time I went there, I was there with a friend who's really into art (also studying art and painting her own paintings, really cool stuff). I never really had a reason to go to that store unfortunately, because my hobbies just didn't align with their inventory. Until now!
I wasn't, and still am not, sure whether a pad is better than a book, because it means I'll have loose sheets instead of a cohesive book. I can't carry this with me quite as easily. However, not having a book means I'll be less worried about fucking up a drawing and 'spoiling' the book (which is a silly concept anyway).
Anyway, I'll try to rest for the remainder of the day. I'll drink some tea and lie in bed. Hopefully be back with cool drawings tomorrow.
ok... you get a small doodle. just so i did *something* today.
<SubtitledImage
image="15-doodle.webp"
altText="Facial features drawn on top of blue text that reads 'credits'. There are eyebrows, bright green eyes, a nose, and a frowning mouth. The face is facing left."
subtitle="the left eye almost matches the perspective. almost" />
## Day 16
<span class="date-marker">2026-02-21, 20:08</span>
I'm back at it! Still kind of sickly, and occasionally a little light-headed too, but my body has been hard at work to get me back to my usual self. And I wanted to *draw!*
I used my new paper for today's drawings, which was very nice to sketch on. I also liked how complete it felt when I had filled out the page. I know the sketchbook also had individual pages, it's not like an endless paper sheet... but it still felt different.
<SubtitledImage
image="16.webp"
altText="Pencil sketches. There is a big head of a girl with a ponytail, smiling with her teeth showing and looking to the right. A smaller head of a girl with open hair and green eyes. Two individual eyes, one open wider, another one more closed and coloured green. Two bodies are also depicted, one facing the viewer and raising their left arm, the other one from a 90-degree side angle. The page is dated 2026-02-21."
subtitle="the big-head-small-head look gives this entry movie poster vibes, i find."
alignment="right" />
I decided to not go for the hair tutorial today and mostly draw on my own accord. The two heads are based on drawings from the [manga drawing book](#day-12-close-your-eyes); one from a hair page, and the other from the cover. I think they both turned out alright, though I don't quite like the hair of the top one, and it feels to me that, after my brief absence, I needed a bit of warming-up to get back into it, and the second (bottom) one looks better as a result. I actually drew the bottom head *without* the construction line-based approach!
I definitely didn't copy the drawings exactly (not for a lack of trying), but it made me put the drawings kind of into my own style... am I allowed to say that already? Do I have my own style?
Aside from that, two tries at drawing a body. The left one ended up with spaghetti arms, and I don't know how accurate both of them are. I drew them without reference. I know I *should* look at more references to study, but I *really* want to be able to do my own thing, so my stubborn mind often refuses to look up reference images.
Also, the individual eyes on the right; I really like how the bottom one in particular turned out. I actually managed to sketch the kind of expression I had in mind, and the colour enhances it.
When I was at the art supply store yesterday, I bought a Faber-Castell 'Polychromos' colour pencil. I only bought one to try, in 'light phthalo green', and they're kind of expensive at 1.95€ a piece, but I *really* like the colour. You may have already seen it in the little sketch I posted [yesterday](#day-15--sick).
The drawings today made me find a style of iris that I quite like; with the reflection spots and a half-dark, half-colour approach. I used this approach in the bottom head and the bottom individual eye. Think I'm gonna keep drawing eyes like that.
## Day 17
<span class="date-marker">2026-02-22, 20:24</span>
<SubtitledImage
image="17.webp"
altText="Three pencil sketches of girls' heads. The top left one has a shocked expression with her mouth overdrawn. The top right is crying. The bottom one is a side profile of one with her eyes closed."
subtitle="trying to be more expressive with my characters... even though these aren't my characters, i guess."
alignment="left" />
I'm feeling pretty unwell today. Sickness has been taking a toll on me; sparing the details, light-headedness is probably the most impactful symptom. I am confident, though, that today'll be the 'worst' day and that I'll probably be fine come Tuesday.
In this perpetual state of light-headedness though, I have had enough windows of lucidity to not only cook for today *and* tomorrow, but also to draw. Here's what I did today!
I went with the less original route today and copied some drawings I found on Pinterest. Wanted to try some expressions, and it went pretty okay. Hair is still one of my biggest difficulties; I'm pretty much somewhere between freestyling it and copying it stroke-for-stroke from the references at the moment.
I do want to be able to do the types of expressions at the top as well in addition to the more traditional manga-style, not instead of because I think they look quite cool and are, theoretically, simpler and quicker to draw. They're also super expressive because they're so stylised.
I'm stating the obvious. My brain is fried. I'll go to bed now. I have a medium-sized project planned for next week (unrelated to drawing) that I'd love to get started on tomorrow!
Also: I want to try a bit more with colour soon. I know I'm not exactly perfect on the basics so far, but I think adding colour can add a lot to the drawings, and my motivation too as seen in yesterday's drawings.
## Day 18
<span class="date-marker">2026-02-23, 22:22</span>
I'm (almost) back to my regular energy! I got a lot better since yesterday and I was able to do things like go shopping, clean my flat, and even start another project which I may reveal soon if things go well... and of course, I drew again. And I'm really happy about today's attempt!!
I had a specific pose in mind for a character I wanted to draw today, and I ended up making her the sole focus of today. In fact, I spent close to two hours drawing her, but that also includes small (thinking) breaks and 'research'. I started with a sketch (top right) to preview my vision, and that did indeed help when drawing. In fact, I could even have referred back to it more than I ended up doing.
<SubtitledImage
image="18.webp"
altText="A pencil sketch of a girl holding up a V sign with her left arm. She is wearing a long-sleeve shirt, jeans, and her hair is tied up in a ponytail. She is winking, the other eye is coloured green. Her body is tilted towards the right side of the paper. In the top right corner is a lightly-drawn sketch of the girl's pose."
subtitle="she's so cool! and i drew her all by myself!! how cool is that??"
alignment="right" />
For this drawing, I referred to the manga drawing book a lot, though not because I copied a character from it (there's no character like this in the book). Rather, I tried to find references for positioning and stylistic inspiration (in other words, the outfit). It sort of helped. Although, I did mirror an approach to hair I saw in the book, and I gotta say: I *really* like how her hair turned out! Looking back on it, maybe some more thicker, outline-defining lines would have helped sell the vision of layers, but hey, it's all a learning experience.
She didn't turn out exactly the way I had first envisioned; I first wanted to draw her wearing a skirt, for instance, but I hadn't practiced that before, so I went with jeans instead. I wasn't entirely sure about the top either. Not wanting to copy the drawing from [a few days ago verbatim](#day-13--a-new-hope), I went with a long-sleeve shirt instead of a tee. Creative, I know! But it did allow me to try my hand at cloth folds. I had the idea that, on her left arm, the sleeve should fall down because her arm was lifted up. I quite like the way the folds look. Though writing this now, I realise why the right arm looks so odd. It looks like the right arm is nude, but that might be because the folds on the left arm don't look like a long sleeve (there's not enough excess material), so my mind expects a shorter sleeve on the right arm too, which I didn't draw in, thinking it would go all the way up to the right hand because it's supposed to be a long sleeve. Oh well, something to keep in mind for next time.
The winking was actually not intended at all, either. It's just that while erasing and re-drawing, I noticed that the upper eyelid looked nice on its own like a winking eye, in fact. So I made it a feature.
Also: while I do have other coloured pencils, I only have the one fancy green colour pencil, so that's the only colour I'm currently using. I would like to use more colour to spice up these drawings. However, I do like the side effect of all my characters having bright green eyes. Kinda neat.
Can I just say... it's *so cool* that, two and a half weeks into this challenge, I can already draw characters like this. Never in my life did I expect I would be able to draw like this. I never really was able to go beyond stick figures and unshapely humanoid-ish characters, although I guess I didn't try very hard. Seeing what I am able to produce now is *insane*.
## Day 19
<span class="date-marker">2026-02-24, 21:40</span>
<SubtitledImage
image="19.webp"
altText="A pencil sketch of a girl from the back looking to the left. Her head is tilted slightly downwards. She is wearing a long-sleeve shirt and jeans, and her long hair is tied up in a ponytail. Her one depicted eye is coloured green. In the top right corner is a lightly-sketched version of the girl's pose."
subtitle="epic pose but not really the skill for pulling it off correctly so it looks a bit awkward"
alignment="left" />
Today's drawing is halfway between original and derivative. I also didn't really 'finish' it? It's derivative because I pretty much ended up drawing yesterday's girl again, but it's original because I put her in a completely different pose and did that without a direct reference!
I'm pretty happy with this. It's a bit odd that her trousers look so detailed compared to her shirt, but I think that's kind of in the nature of that type of clothing. The shirt is basic, but jeans are inherently more complex, given their stitching. I took a photo of the trousers I'm wearing right now to use as reference for those details, and I think it turned out not half bad.
Also, hands. They're so difficult to pose. I initally wanted her to sort of wrap her left hand around her thigh, but after a couple of tries, I gave up completely because I could not draw a shapely hand for the life of me. In fact, I ended up skipping the hands entirely today. Definitely something I'll have to revisit.
I also realise now that her head looks pretty much exactly 90 degrees turned around, which is unnatural. In retrospect, I should have erased some of the jaw line at the very least. Oh well!
To be honest, half the reason I didn't finish this today was because I still have other stuff to do, and it's getting late, lol. But there's also no point obsessing over details, especially when I barely know how to draw these details. In the coming days, I should try to do more to learn those. Hands, for example...
## Day 20: those weird things at the ends of my arms
<span class="date-marker">2026-02-25, 21:51</span>
I dared tackle the big topic today that I've been avoiding for weeks. *Hands*.
<SubtitledImage
image="20.webp"
altText="Pencil sketches of five hands in different poses. The drawing is accidentally dated 2025-02-25, one year earlier than it was drawn."
subtitle="hands can look SO cool if they're drawn well. these are not (but they're getting there)"
alignment="right" />
I followed [this mikeymegamega tutorial](https://youtu.be/xV3PmbBU9c0) on drawing hands and just followed along trying to draw all of the hands he drew. They didn't turn out perfectly and that, naturally, did feel a little discouraging. However, just like with the heads, it gave me pretty good baseline for how to view hands as a drawing subject (like what to pay attention to and whatnot), and I feel better prepared for drawing hands now than I did before. Very cool!
In the beginning of the video, he said *"You probably hit a stage where you're hiding the hands behind the back of your character"* and OOF... that hit hard tbh
Hand 1 has pretty thick fingers, but it was my first try so whatever. Hand 4's fingers might be a little short? I definitely fucked up hand 5, but that was mostly due to not leaving enough space on the A5 sheet, so I had to squish it into the top right corner, and I ended up drawing the fingers too short as a result. I think hand 3 is my favourite, especially after drawing in thicker 'final' lines (which I only did for hands 3 and 4).
Went pretty well! No idea what I'll do tomorrow, but it's going well. If I'm really daring, I'll do another character (that'll hopefully take less time...) and try to add some cool hands. Jazz hands would be funny ngl
Oh a bit of a tangent: I just looked at my drawing from [two days ago](#day-18) again, and that made me feel really good. I'm *so happy* about that drawing in particular and my progress in general. *I created these drawings!!* How cool is that?? AI images could never evoke the joy in me that I am feeling when I look at my sketches.
## Day 21: we'll see creation come undone
<span class="date-marker">2026-02-26, 22:21</span>
I tried my new hand drawing technique today, and I used a very prominent hand for reference: the hand on the cover of Porter Robinson's *Worlds!*
<SubtitledImage
image="21.webp"
altText="Two pencil sketches traced over with a black fineliner. The left one is of a hand with a cube in its palm, sketched after the hand on the cover of Porter Robinson's album Worlds. Beneath it is an emoticon used on the same cover. To the right is a manga-style head with green eyes and wavy hair, meant to resemble Porter Robinson's Vocaloid mascot Po-Uta."
subtitle="let me go on record to say that i was unfortunately not listening to porter robinson while drawing"
alignment="left" />
This was actually surprisingly fun and easy to draw, now that I had a rough guide for how to draw hands. I started with a circle, drew in the small circles for the finger positions, drew a guide line for the max finger length (about the same as the palm's length), and then tried to follow the finger shapes from the reference. Outer finger edges (where the bone is) are straighter, inner edges (where the skin is softer) are rounder. It was surprisingly trivial. I am aware I picked a fairly simple pose to draw, and that was definitely on purpose, but I can't imagine other poses to be much more difficult if you have a reference.
Just the hand wasn't really enough for an entire day's worth of drawing, so I had the idea to draw Po-Uta (Porter's Vocaloid mascot)! I stuck to their face (and not their hand lol), and it turned out quite nice! I gave them bright green eyes, of course, because that's the one colour pencil I currently have, and it actually kind of serves as a signature detail for my drawings, in a way.
I fucked up the hair lol. It's not *that* bad, but I clearly had no idea what I was doing, and just freestyled the curls. I think tracing over some major lines with the fineliner helped a bit because it visually marked off hair sections, and it doesn't look *that* bad.
Oh yeah, and I dared trace over the drawings with a fineliner this time! I did it for the hand primarily because having the final traces in looks way better than leaving the sketch in its construction stage, and then I just figured I'd do the same for Po-Uta. Filling in their irises half-black may not have been the smartest move, but from a slight distance, it actually looks pretty good.
I also want to note that I was happily drawing this when a realisation suddenly dawned on me: I was drawing fan art. Me! Fan art! That's something I've only ever seen skilled people do on the internet!
...it's kinda cool that I can do this now too.
And if you're wondering: Nurture is my favourite Porter Robinson album, but I do like all eras. I used to listen to Unison (and the Knife Party Remix) a lot back in the day, and Particle Arts (the Virtual Self song) used to be my most-played song on Spotify for a *long* time. Porter is also the only artist I've seen live (plus his support acts)! I went to his Nurture show in Berlin (with support from James Ivy) and his SMILE! :D tour stop in Hamburg (with support from underscores!!!). The crowd didn't seem to feel underscores' tracks as much as I did, which was a big shame, and I felt a bit awkward going hard just on my own, but I still really enjoyed being able to see her live as well.
## Day 22
<span class="date-marker">2026-02-27, 23:03</span>
Today was another one of those days where I found it super difficult to get started and even lightly considered skipping, but once I did get started, I had immense fun and thoroughly enjoyed the experience. I don't know why this is so common with me...
<SubtitledImage
image="22.webp"
altText="A pencil sketch of a girl with a ponytail, crop top, and track pants with a slightly shocked look on her face. She is looking at her right arm, which is a cyborg part."
subtitle="she has a cool style. i feel like her personality would be distinctly different from the previous characters i drew"
alignment="right" />
Most days, I come up with my drawing idea only shortly before I actually draw, which has pretty much exclusively been in the evening. Today was no exception. I had the idea of drawing a girl looking at her right cyborg arm with a somewhat shocked and not necessarily cheery expression like a lot of the previous ones I drew. The implication should be that she lost her organic arm and had it replaced with a mechanical part without her knowledge. No, that doesn't [sound familiar at all...](/projects/projectn5/devlog/2024/1127/#the-new-storyline)
I didn't *quite* nail the perspective/orientation I had aimed for, but I think it actually still turned out super cool. Again, I drew this with no direct reference! I looked up some inspirations for the hair, right arm, and track pants (which are clearly Adidas-lookalikes).
I think her outfit is cool. I didn't want to do the same long-sleeve-jeans combo again, and I ultimately wanted to draw this girl to look like a distinctly different person from the previous ones. I picked a sporty outfit, the idea for which I somewhat took from a drawing of mine I drew before I begun my drawing challenge, but after [the sketch that kicked off my drawing arc](/blog/2026/0129/). I didn't exactly re-draw her, like I did with my [day 1 drawing](#day-13--a-new-hope), but let's just say I did because that's kinda cool.
The lines marking the collarbones are a very late addition to the drawing, but I really like them as a small extra detail. Kind of shows to me that I'm trying to apply my existing knowledge while also still adding new things, in small steps. She also got an earring, for instance. A simple one, but it adds character.
I also used this drawing to try drawing a hand on a person! And it kind of worked out. It looks a little wonky still, but better than the ones before. I'm also partially blaming the small size at which I drew the hand, so small mistakes have a bigger impact than on a larger hand.
Some other noteworthy things include the hair, where I picked a hairstyle that exposes the forehead. I was inspired by [yesterday's Po-Uta](#day-21--we-ll-see-creation-come-undone), who also had a hairstyle that didn't cover up the forehead. I also added an eyelid line beneath her left eye, which ended up a little *too* thick, but still does its job of portraying the shock in her face. Kind of like she woke up from a coma or hibernation. [Wait...](/projects/projectn5/devlog/2024/1127/#the-new-storyline)
This girl's not meant to be Laura, just so we're clear. I think. I might change my mind on this. In fact, I should give names to the characters I draw. That would be a cute detail.
Oh! I just realised that my manga drawing book has a page on cyborgs! that would have come in handy...
## Day 23
<span class="date-marker">2026-02-28, 22:14</span>
<SubtitledImage
image="23-0.webp"
altText="Pencil sketches. In the top left is a right hand loosely hanging downwards. The other three sketches are of pleated skirts. The two sketches on the right are of skirts only, the third includes a torso and legs."
subtitle="change of wardrobe!"
alignment="left" />
Today, I decided I want to finally learn to draw skirts. I wanted to do this because it allows me to bring more variety into my characters' outfits, as opposed to having them all wear jeans or something. I picked out a video for this, though at that time I was listening to [Safety! by acloudyskye](https://acloudyskye.bandcamp.com/track/safety-2), a 10-minute song. I didn't want to pause in the middle of it, so I found a hand on Pinterest and practiced drawing that first. Turned out alright!
I watched [another mikeymegamega video](https://youtu.be/jS7ib3-ET5M) for the skirts, though I pretty much only stayed for the first skirt and then bailed. I also took notice of a comment that said that the first skirt was drawn too low, so I took this into consideration for my drawings. I started with skirts only, though for the third one (in the bottom left), I drew a body and then attempted to make it wear a skirt. I had some issues with the perspective, and although it looks quite nice now (I'd say), it looks like it's facing towards the right, when I initially tried to make it face left. No big deal though.
I really like how the third skirt turned out! So floaty, just how I had hoped it would turn out.
<SubtitledImage
image="23-1.webp"
altText="A pencil sketch that is meant to resemble the music artist Jaron as seen on the cover of his album LIGHTYEARS. The drawing is distinctly manga-styled compared to the cover photo, notably through a rounder head."
subtitle="let me simmer down and cover up for i am cooking broth"
alignment="right" />
I also tried drawing Jaron again, but kind of in the style that I've been going for lately. It turned out fairly okay. I think the back of his head really changed his appearance and cute-ified him. I also drew the hands too low compared to the cover photo I used as reference. Still, I think this looks cool. I was also able to make some use of my new hand drawing techniques to make these ones look like actual hands. The right hand (on the left of the drawing) still proved a bit challenging, but it looks *way* better than [my previous try](#day-07------).
Although I have to say that my previous attempt almost looked more like the guy... I guess it makes sense because I tried copying him exactly back then, whereas this time I mostly went on my own and only checked the reference for posing and some minor details, like the ear shape.
On another note, I actually have a really cool idea for a drawing that I want to do soon, but for that I need some more supplies namely, larger paper. It'll be a bigger thing, so I'm saving it up, though that means I need to fill the time until then with other drawings. Drawings that won't require me to expand the scope of the big drawing... you'll see soon, I hope.
## Day 24: the rest of the damn body
<span class="date-marker">2026-03-01, 22:33</span>
<SubtitledImage
image="24.webp"
altText="Pencil sketches. In the top left are two pairs of legs with socks, one facing straight, the other from a side view and with one foot up on a box. Below those are two more pairs of legs with visible construction lines. One of those is wearing green socks, the other one has solid lines drawn using a black fineliner. To the right is a drawing of Clank from Ratchet & Clank. It's a view of his back as he is walking away. Above him is the text: (triangle button) Send Clank to the Underground Caverns."
subtitle="giving my characters the ability to run away, one sketch at a time"
alignment="left" />
So I played Ratchet & Clank 3 earlier, and on Qwark's Hideout, you're prompted to "Send Clank to the Underground Caverns". I thought this sounded really funny, so I tried sketching a sad-looking Clank walking away. For this, I used a still from the final cutscene of Ratchet & Clank (2002) where he walks away with a broken arm. I ended up drawing his torso way too long, but oh well.
I also noticed that Insomniac gave Clank a unique walking animation that really shows that he's a mechanical robot and not a squishie. He pretty much lifts one foot at a time while keeping them level to the ground, not rolling his feet as there is no flexible part to roll. In theory that kind of animation is to be expected, especially of Insomniac, but I had just never noticed that before, and I thought that was pretty neat.
Something I wanted to practice today was lower bodies! I have put a lot of focus on the head (face especially) and torso lately, and I do want to be able to draw complete bodies. I started with the two pairs of legs in the top left, which I drew with no tutorial watched prior. I picked a random image on Pinterest as reference for this, though that image only really covered the feet, so I improvised on the legs and hips.
Then, I followed up by watching [this mikeymegamega tutorial on drawing legs](https://youtu.be/TONhhhuevsA). I didn't watch it all the way through; he does some speed sketches at the end I *may* watch these tomorrow, as I am interested in the perspectives he is drawing there. Still, I followed along for the first two pairs of legs, and I think they turned out pretty neat. Even gave the first one a green pair of socks. That one is REALLY V-tuber-like, which he also admitted to in the video, but I figured I should just follow along as practice. Can't hurt, after all.
While the technique is very much appreciated and I think it'll help me immensely going forward, I'm quite glad to see that I evidently wasn't *too* far off with my sketches before watching the tutorial. I kind of already knew where I had to put curves and how the legs should look. Still, the ones I drew post-tutorial look quite a lot better.
I definitely need more practice, but: in theory I have now practiced all parts of the body, and I am now able to draw a complete human being! And I will! Soon.
## Day 25
<span class="date-marker">2026-03-02, 22:36</span>
Today, I had some fun shopping and got myself some art supplies. I bought an A4 pad for larger sketches (all my sketches have been on A5 and sometimes A6 thus far), a few more of those cool coloured pencils, a new sharpener (my previous one doesn't work properly anymore), and I also bought a folder to put all my sketches into! They've kind of just been floating around my desk so far, and I wanted to give them a proper spot to keep them safe, so now I have that sorted too.
<SubtitledImage
image="25.webp"
altText="Pencil sketches. At the top are three pairs of legs, one looking to the left, one from a back view, and one with crossed legs viewed from the front. At the bottom is a drawing of a girl. Her head and her torso are visible. She has shoulder-length hair, green eyes, and is wearing a dress shirt and a red tie. She is looking downwards with a slightly surprised facial expression."
subtitle="business mode"
alignment="right" />
Today, I did as I said yesterday (for a change) and drew the remaining legs from mikeymegamega's video. It was quite fun and I could notice myself already realising how to draw the curves more or less appropriately, though I don't yet have a proper understanding for how legs should look from different perspectives hence the practice. I also kept drawing the knees too slim, which resulted in some odd dimensions. I tried fixing that, but they still look a bit odd.
I also deviated from mikeymegamega in that I chose to draw my legs wearing socks instead of high heels. I figured I should practice that, since I'll probably draw flat feet more frequently than feet in high heels. This is probably most noticeable in the pair of legs on the right, where the feet are much more rounded off compared to how mikeymegamega drew them.
I also wanted to practice drawing the upper half of a character again, just so I don't forget. Plus, I wanted to use my new coloured pencils. In order to do both, I had the idea of drawing a character with a tie, so that I'd have a good use for red.
I drew this character while referencing one from the manga drawing book, but I again wasn't following the reference too closely! I tried to do my own thing as much as I could. For instance, I pretty much did the eyes all by myself, I added the ear (with the signature hook I have for some reason grown accustomed to drawing), and the tie wasn't part of the reference at all, so I added that loosely based on random reference images on Pinterest of characters wearing ties.
The colours really pop, I gotta say. Those pencils have, if I understand it correctly, oil-based leads which give a really vibrant and consistent finish. They look superb. I also do like giving my drawings only little colour to have it really stand out, though I *may* try to do more colour eventually. I got a brown pencil for hair too, so we'll see.
I 100% only drew a tie to use the red pencil, though I did stick with green for the eyes. I like that consistent detail. On the other hand, I would like some change too, so I'll probably draw future characters with other eye colours. I bought a vibrant blue pencil too which I look forward to using.
Also: after tracing all the lines with a fineliner, I for once erased the construction lines, and I was honestly kind of surprised by how nice the drawing looked once I did that. I've left them in all my drawings so far because I thought it looked cool to see how I got to the finished drawing and whatnot, but the clean look of the fineliner traces and the colour makes me reconsider that choice.
I really gotta give my characters names. I've been thinking about that for a while now, and I feel that [day 18 girl](#day-18) is *definitely* Emilia, and [day 13 girl](#day-13--a-new-hope) *may* be Elizabeth.
I'm still struggling with whether or not [day 22 girl](#day-22) is Laura or not.
## Day 26
<span class="date-marker">2026-03-03, 21:51</span>
Today, I decided I wanted to challenge myself!
I was actually very slightly frustrated before drawing because I felt that I'm getting to a stage where my expectations exceed my skill level so I won't be able to draw what I want to be able to draw. And while I still am no pro, I am actually quite satisfied with what I was able to accomplish today.
<SubtitledImage
image="26-0.webp"
altText="On the left is a drawing of a girl from the back, looking slightly towards the left. She has brown hair tied up in a high bun and is wearing a grey spaghetti top, a green skirt, and grey sports socks. Her left hand is forming a fist. On the right is a floating face with big eyes and a big smile holding up a victory sign."
subtitle="i wonder what she's thinking about. oh wait i guess i'm the one to decide that"
alignment="left" />
The challenge for today was to draw a full(-ish) body in a perspective I wasn't familiar with. More challenging even: no front perspective! To be fair, this meant I didn't have to draw a face, but to be honest, I like drawing faces.
I ended up drawing a girl from the back and at a slight angle facing left. It took a while, but no longer than, say, the drawing from [day 22](#day-22). I also had to erase and redraw quite a lot. I started with the head, then the torso, then the hips, but I wasn't happy with the hips so I looked up a reference image on Pinterest. After drawing the new and improved hips, I noticed that the torso was *way* too long, so I made the difficult decision to erase the head and move it down. I quite liked how I managed to draw the head the first time around, but honestly, I think I did a pretty good job on the second try as well. I'm also really glad that I did this, because the fixed torso size looks pretty good, while the previous one would likely have ruined the sketch.
I didn't even manage to fit the entire body on the page. In the end, I only had to cut off the bottom part of the feet though, so it wasn't too bad. The only part I *really* struggled with were the hands. I *could not manage* to draw the hands the way I wanted, and I am entirely blaming the tiny scale for this. I ended up drawing a fist instead to avoid drawing fingers. The thumb still turned out decently, I think, given the circumstances.
<SubtitledImage
image="26-1.webp"
altText="A pencil sketch showing the previous drawing in an earlier stage. The drawing has not yet been traced and no colour is added yet."
subtitle="bonus: the sketch before i traced it with the fineliner and erased the construction lines. notice the extra sketching in the hip area"
alignment="right" />
A lot of what I did in this drawing was a first. I tried a completely new hairstyle, for instance. I drew this type of spaghetti top for the first time. I also did legs with my new technique and without a direct reference. Some more details like the shoulder blades and the indent for the spine I added here for the first time. Plus, of course, the perspective I have never done before. I paid attention to the layering: the arms are the best example for that. The left arm is at the front, then the torso, and then the right arm is mostly obscured because it's furthest back. I remember screwing this up way back at the start of the challenge, so I learned from it and avoided making the same mistake again!
Also: I used more colour this time!! I wasn't entirely sure whether I should, but then I decided to give her hair colour as well. The brown I had was *really* dark and I actually had to re-trace the fineliner lines after colouring in that section. I didn't do this for the skirt, though you can still see that the pencil lightly covers the traces. I like the light green skirt colour. The drawing also, again, looks quite clean because I erased the construction lines.
I can't really tell what kind of pose I gave her. I think the arms contribute a lot, but I'm never sure where to put the arms. With them down like this and with the fist, this looks like a bit of an angry pose, like she's walking away from something that frustrated her.
First I drew fanart, now I'm creating my own lore. This is great! I wouldn't want it any other way.
Overall, I'm really happy with today's drawing. Now that I theoretically have all the parts of a human body and practiced them, I really wanted to draw a full person. While I picked a really challenging pose to try today, I think I pulled it off pretty decently, all things considered. Especially since I drew this with no direct reference at all! Just a loose reference for the hips and another for the bun.
Just for fun, I also wanted to draw a little reaction face with a victory sign, so I tried that. Ended up quite cool, I find!
It's weird to think that this challenge is almost over... and that I've made it so far already. I really thought I'd give up less than a week into it. Now I'm here, sketching humans largely from my own imagination. How cool is that?
## Day 27
<span class="date-marker">2026-03-04, 21:39</span>
Wait a second, I'm one day away from finishing the challenge???
<SubtitledImage
image="27-0.webp"
altText="In the top left is a drawing of a girl with her head tilted towards her right shoulder. She is smiling with her eyes closed and is holding up a victory sign with her left hand. She has red-brown hair in a ponytail and is wearing blue jeans with shoulder straps, and there is a green scrunchie on her left wrist as well. In the bottom right is a pencil sketch of a right hand, looking at the palm. The fingers are slightly spread out."
subtitle="smile for the camera!"
alignment="left" />
Genuinely, I just added the header for this section and realised that today is day 27... of 28. I really thought day 28 would be on Friday. This is wild.
Anyway, I had some more fun with colours today! In a very cheerful move, I drew a girl with a big smile holding up a victory sign. I saw this technique for drawing a teeth-showing smile somewhere a week or two ago and wanted to try it worked out well! I also wanted to try and draw a face head-on, because all of my previous ones have been drawn at an angle. I think that went quite well too!
Only thing I'm not entirely happy with is the hair after colouring. It just looks kind of odd and not as light as it did in the draft sketch. I even tried erasing and redrawing it a bit after colouring, which unfortunately left some pretty visible artifacts. In fact, I can't quite decide whether I like the draft sketch more or the final result.
<SubtitledImage
image="27-1.webp"
altText="A pencil sketch showing the girl in an earlier drawing stage. No tracing and no colours have been added yet."
subtitle="the draft sketch"
alignment="right" />
Although I do like the popping blue jeans and the green scrunchie as a detail really want to draw more accessories so that my characters look more interesting.
I'm overall very happy with this! Seeing the sketch come to life made me smile irl too. Even the hand turned out decently well. Even the hand!!
I decided to keep it short for today, as I had a long day at work (for which I got up late lol), though I did try to draw a bigger hand as well, just as practice. It turned out okay. Not as good as I would have liked, which is why I didn't end up tracing it with the fineliner, but I didn't want to erase it either because it's practice and I shouldn't erase things like that.
Day 27 done. I guess this means I'll have to draw that 'big' drawing tomorrow. I've been thinking about it for a while, and it's really not *that* special, but I am still slightly concerned whether I'll be able to perform. Definitely looking forward to tomorrow, one way or another!
## Day 28: finale
<span class="date-marker">2026-03-05, 23:59</span>
This is the end. The challenge is over.
This feels so strange to me. In a way, this has become such a habit that I've totally normalised drawing being a part of my day. But at the same time, it feels as if I've only just begun.
This has been such an enjoyable experience. While the beginning was actually pretty stressful, as I barely managed to get anything halfway decent onto paper, I think I made huge strides once I started going for tutorials and references. Still, I think it was a good choice to try and do my own thing as much as I could. Only that revealed to me the weak points my drawings had, and still have. This will be an ongoing battle, but it's one I feel more prepared to face now.
Should you be reading this and asking yourself whether you would want to do something like what I've done, let me ask you this: do you want to learn how to draw? Then do it! Trying this challenge literally enabled me to draw characters something I've never been able to do before, at least not on the level I am now.
The beautiful thing about drawing is that you need very little to get started. I begun the challenge by using a pencil I've had for some years and a notebook I got for free a week earlier. There's always the option to upgrade your equipment, and that's what I did too, though not to a huge extent. I bought fancier paper and a new eraser. In fact, I used the very same pencil from start to finish.
I think the two biggest reasons for why the challenge was so successful were:
- routine, and
- accountability.
Knowing well that I will dedicate a certain time slot to drawing each day allowed me to solidify drawing as a habit. At the same time, publishing my results in this blog format meant I **had** to deliver something every day something I am relieved is no longer the case, as it does create a little bit of pressure to perform, but I think I'll miss it as well. I'm not good with sticking to routines.
I definitely want to continue drawing. I've really been motivated just by seeing what I was able to accomplish all by myself (with some help from the internet!), and I feel like there's so much more I'll be able to do. I want to do more with colour, add more detail to my drawings to make them more visually interesting, I want to try digital art too! I need to learn posing, and drawing shadows, and perspectives! I tried challenging myself these past few days by drawing things I wasn't sure I'd be able to pull off, and I do want to continue doing exactly that. It's a great way to make progress, although it does come at the detriment of damaging your ego if you do fail. Failing shouldn't be seen as a bad thing, though! It's trite to call it a learning experience, I know, but it really is one. In fact, every drawing is a learning experience, even the best ones.
I will definitely post more on my website once I draw more cool things. I may not post quite everything I draw unless I do another challenge but the coolest ones will definitely get a spotlight. Maybe I'll create a gallery page?
For now, I will say, thank you if you've read this far. This was a blast and I am so happy to have stuck through until the end. The challenge is complete.
<SubtitledImage
image="28.webp"
altText="Fineliner-traced drawings of three girls. It's the girls from days 13, 18, and 22. The left one, from day 22, looks away annoyed. The right girl, from day 18, is smiling. Both are holding up one half of a sign that reads 'CHALLENGE COMPLETE!'. In the middle is the girl from day 13, smiling with her eyes closed as she is the centre of attention."
subtitle="22 // 13 // 18" />

View File

@@ -0,0 +1,32 @@
Lately, I've not been able to do the things I'd like to do. I've had plenty of time, don't get me wrong I finished my university assignments back at the start of January, cleaned my entire flat after coming back from my abroad semester, haven't been employed for months (though I'll soon have a job again) and university doesn't start again for me until April. And even then, I only have a single course left to take until October to finish my bachelor's.
Yet, I've made little progress on many of my projects and project ideas. [My game](/projects/projectn5) has been dormant for, at this point, almost two months, even though I've been thinking about it almost every day. Electronics projects I've been meaning to start, like a portable Raspberry Pi Zero 2W music player, I have barely begun working on. My 3D printer has seen almost no use even after I returned. I used to make music for a decade but now it's been 5 years since the last time I wrote a song.
I'm also still invested in trying to learn 3D modelling. How to model human characters, environments, items. Texturing. Rigging. Animation. There are studios employing entire teams for **each** of these fields, and I am trying to do all of them by myself.
And then there are the things I *do* spend time on currently, like updating my website. Maintaining my web server and learning how to use `systemd` and `docker-compose`. Moving over to self-hosted services and Linux to lessen big tech's grip on my data. At one point, I even tried things like writing a `REST` API in `Go` (a language I have never used before), and I was thinking of building my own Matter server for smart home stuff up until very recently too. I'm also still trying to configure a Raspberry Pi as a backup server. And if you wanna go that far, you may even include Cities: Skylines here, because trying to learn how to build a functioning city is an amount of work that could span a combined bachelor's and master's programme.
Now that I've started trying to learn [how to draw](/blog/2026/0205), I wonder: am I picking up too many hobbies all at once? Am I even able to create fulfilling work in all these hobbies? I'm just one human being, after all, and it's starting to feel a little overwhelming.
Maybe I should learn to reduce. Put some things on pause. It's difficult to decide to stop pursuing hobbies, but maybe by making a clean cut instead of having them linger on, I can make time (and space in my mind) for the things I'd rather do.
So I'm deciding now:
- I want to spend more time on my game. That's staying. It should become my main priority, in fact.
- My server is running fine, it doesn't really need constant maintenance. Some things I would like to change before I leave it to be though, like trying to use Docker for my Nginx install to make the installation more portable. I'm also considering getting rid of my Nextcloud installation and instead embracing copyparty for files and using my email provider for task synchronisation. Maybe set up an integration so that my website auto-updates whenever I push to Gitea. Saves the extra SSH login.
- I do like updating my website but I should settle on the current style (it looks pretty decent now anyway) and focus on adding content.
- Electronics projects are on pause.
- Playing around with random languages (like the `GO` API thing) is gonna go.
- I want to 3D print a coat hook for my flat door, so I'll do that and then not touch FreeCAD for a while.
- Trying to develop a music album is pretty difficult, and I already have a game to take care of. Music is officially on pause from now on (not that I could install FL Studio natively on Linux anyway...).
- And maybe I'll play games other than Cities: Skylines for for now.
And then there's drawing... cynical me wants to put that on hold too. But I do think that it could help me in developing my game. My idea is to be able to draw concept art, sketch down ideas instead of having them vanish before I manage to create them in Blender. Also, if I actually manage to take this to a level I can be somewhat happy with, I believe that drawing can serve as a fulfilling small hobby, in contrast to gamedev, which is a much bigger task where ideas take longer to come to fruition.
To sum up, I will focus on:
- Project N5
- Website
- Learning to draw
Let's see where this takes me :)

View File

@@ -0,0 +1,30 @@
<script lang="ts">
import SubtitledImage from "$lib/components/subtitled-image.svelte";
</script>
Earlier today, I went through `journalctl` on my server to view some copyparty logs when I discovered that the `ssh` logs were *swamped* with login attempts. Day and night, no more than a few seconds apart from one another, thousands of login attempts from random IP addresses trying to log onto my server with any kind of username they could think of: `root`, `admin`, `mysql`, `denizk0461`, `gmodserver`, `git`, etc.
I thought I was safe from this; after all, I quite vividly remember talking to my former boss about my server and having him tell me how **incredibly unsafe** it is to use password-based authentication, and telling him reassuredly that I set up my server so that I would log in using an `ssh` key and a password. I also remember when I set up my server through Hetzner's website, I specifically said I'd use it via `ssh` and they didn't mail the `root` user password to me because of this.
All of this was and still is true. But then I remembered: when I set up `ssh` on my Raspberry Pi recently, I followed a guide that said you had to manually disable password-based authentication in a config file. And I don't remember doing that on my public-facing server...
<SubtitledImage
image="logins.webp"
altText="A screenshot of a terminal emulator logged onto a remote server displaying log messages. The messages all display different IP addresses unsuccessfully attempting to log in with different usernames. There are over a dozen requests within a single minute on February 14, 2026."
subtitle="intruders trying pretty much any kind of username that would make sense and some I didn't really understand" />
So I checked the config file at `/etc/ssh/sshd_config` and found the line `#PasswordAuthentication no`. It was commented out, as it is by default! This means that anyone could try to brute-force my account passwords on my server! And I never noticed because I never needed the password; I'm logging in via `ssh` keys, after all. Only after trying to connect to the IP without the key did I find out that this was actually possible all this time.
So I uncommented the line, reloaded the service via `sudo systemctl reload ssh`, verified that my key-based login was still working, then tried the password-based login and was greeted with the message *"Permission denied (publickey)."*
<SubtitledImage
image="404.webp"
altText="A screenshot of a terminal emulator logged onto a remote server displaying log messages. It displays 404 messages for different URLs containing the letters 'env', suggesting that some was unsuccessfully attempting to discover server secrets."
subtitle="phishing for sensitive data eh! tough luck, the water is completely empty!"
alignment="right" />
Satisfyingly, all the login attempts documented in `journalctl` are now suffixed with *"[preauth]"*, meaning the people can't even get to the login prompt anymore because they're missing my private keys. I know I'm not 100% safe... but it feels a lot safer now than it did before.
It's worrying to think about what damage one of them may have been able to do if they had gotten in. Especially since some were apparently looking for files containing sensitive data that were left in the open; one was really eager to find `.env` files, likely to try and discover some kind of password or other secret.
Lesson learned: if you have some kind of publicly-facing server, check that unwanted people are restricted from even attempting to log onto it. If you're only *kind of* sure, check!

View File

@@ -0,0 +1,247 @@
<div class="callout-warning">
<p><b>Note</b>: as I'm constantly learning new things, this blog post is sort of outdated now. The information is still correct, but it feels inefficient and leads into a dead-end. I dislike this, as I wanted to write a guide that provides an expandable base. Therefore, I'll likely either update or replace this article and trim it down to focus on the important bits.</p>
<p>Expect a Go API.</p>
</div>
*Hey!*
Do you want to develop a web application in SvelteKit? Do you want this application to access a PostgreSQL database on a remote server? Do you struggle with CORS (cross-origin resource sharing) and CSRF (cross-site request forgery) and keep receiving error 403? Well, I did, and I couldn't find ***ANYTHING*** on the internet going beyond a test running locally. This is why I'm writing this guide.
Let me preface this by saying: what I did isn't perfect. It's also likely incomplete; I would give bad advice in a complete guide for sure. What this is, is a guide covering the key aspects for setting up a relatively minimal setup to get your application online successfully, upon which you can expand by adding more features. The important distinction from other guides I've found online is that this guide doesn't deploy the backend locally, but instead sets it up online, ready to use.
## The Guide
### What You Need
- a device, such as a laptop or a desktop, with the following installed:
- an IDE
- `npm`
- `ssh` keys for the server, if you're accessing it remotely
- a remote server instance set up with some software:
- Nginx
- Docker Compose
- an idea for what kind of app you wanna make
### Getting Started
#### SvelteKit
For creating a SvelteKit app, I recommend the guide [Getting Started](https://svelte.dev/docs/svelte/getting-started) by the Svelte team. You won't need more than the first four commands to create the app and get it up and running. During the setup, I recommend you pick the `adapter-node`.
#### Backend
For the backend, which will run on your remote server, it's very easy to use Docker Compose to get started. Once you're `ssh`'d into the server (or physically sitting at the terminal), create a folder where the data will live in, then create a file named `compose.yml` (for instance, by typing `nano compose.yml` into the terminal) and paste this into the file, then use `docker compose up -d` (or if that doesn't work, try `docker-compose up -d` with a hyphen) to start the container:
<pre class="code-block">
version: '3'
services:
api:
image: postgrest/postgrest
restart: always
ports:
- 3100:3000
environment:
PGRST_SERVER_HOST: '0.0.0.0'
PGRST_DB_URI: 'postgres://authenticator:password@database:5432/postgres'
PGRST_DB_SCHEMAS: 'api'
PGRST_DB_ANON_ROLE: 'web_anon'
PGRST_SERVER_CORS_ALLOWED_ORIGINS: "https://app.natconf.dev"
depends_on:
- database
database:
image: postgres
restart: always
ports:
- 5432:5432
environment:
POSTGRES_USER: 'username'
POSTGRES_PASSWORD: 'password'
POSTGRES_DB: 'database_name'
volumes:
- ./postgresql:/var/lib/postgresql
</pre>
Important notes:
This `compose.yml` covers both the PostgreSQL database itself as well as a program called [PostgREST](https://docs.postgrest.org/), which connects to a PostgreSQL database and acts as a [REST](https://developer.mozilla.org/en-US/docs/Glossary/REST) api. This is advantageous, as it means you won't need modules such as [Postgres.js](https://github.com/porsager/postgres) to send raw SQL queries from SvelteKit to the database. With PostgREST, you can use a regular URL to access and modify database data using HTTP verbs such as GET (for getting data) and POST (for sending new data).
Some environment variables need to be set: `PGRST_SERVER_CORS_ALLOWED_ORIGINS` decides from which domains requests are allowed. Setting it to `"*"` allows all domains. Change this to the domain your application is running on. Set `POSTGRES_USER` and `POSTGRES_PASSWORD` to the data you'll use to log in as your admin account. Also, `PGRST_DB_ANON_ROLE` is the user that will be used when making requests to the database without credentials. This user's permissions will decide whether GET, POST, etc. requests will go through. You don't need to change this, but if you do, you'll also have to change `web_anon` later in this guide.
In `PGRST_DB_URI`, the link uses the username `authenticator` and a password. Replace the word 'password' with the actual password you'll use for the `authenticator` role. You will set up this role [later](#configure-the-database). This is *not* the same password you'll set for `POSTGRES_PASSWORD`!
The ports may differ on your machine. The `database` service runs on port 5432. You only need to change this if this port is already used by something on your server. Keep in mind to change the **left** number only! The left number is the port that faces outwards, the right port is the one used internally by the container. Since PostgreSQL is running on port 5432 by default, and since there is nothing else running inside the container that's also on port 5432, we don't need to change the right side at all. If you change the left port, be sure to change the port used in the `api` service's `PGRST_DB_URI` as well, as this URI is used by PostgREST to connect to the database.
I did change the port for the `api` service, however. PostgREST runs on port 3000 by default. This is problematic, as Node (which we will use for the SvelteKit application later) also runs on port 3000 by default. I chose to change PostgREST's port to 3100 here to avoid conflict, but you can pick any non-privileged port (any between 1024 and 65535 is good).
Keep in mind that you will not need to open up any of these ports on your firewall. Why? This is why:
#### Nginx
I'm using Nginx as a reverse proxy here. What does this mean? It means that we can send a human-readable URL to Nginx, such as this: `https://files.natconf.dev`, and Nginx will *internally* route us to the place the service is actually running on: `http://localhost:3923`. This has several advantages: as the end user, we won't need to remember the IP address or the port of the services we connect to. As the server administrator, we will only need to expose a minimal number of ports. In this example, port 3923 is actually closed off from the public, meaning that bypassing Nginx and connecting to the service directly, e.g. by typing `https://natconf.dev:3923`, is impossible. The only open port is 443, which is a standard port for websites served over encrypted HTTPS. Your browser will always try to connect to a website starting with `https://` on port 443, unless you specify another port. Port 80 is actually also open on my server, as it accepts requests through the unsafe `http://`, but it only redirects to `https://` on 443.
I configured Nginx to run both the SvelteKit app as well as the PostgREST backend from the same subdomain. You don't *need* to do this, and I *think* it should even work if you put, for example, the database on a different subdomain, but I can't guarantee it.
<!-- &#123; == {. if this is not encoded, sveltekit will try to interpret it as code and throw an error -->
<pre class="code-block">
server &#123;
listen 443;
server_name app.natconf.dev;
location / &#123;
proxy_pass http://localhost:3000;
}
location /customers &#123;
proxy_pass http://localhost:3100/customers;
}
}
</pre>
This `server` block serves two functions:
- it serves our SvelteKit app, which by default runs on port 3000, from the root directory of the subdomain (e.g. `https://app.natconf.dev`), and
- it serves the table `customers` from our PostgreSQL database, which is accessible through PostgREST on port 3100, on the subpage `/customers` (`https://app.natconf.dev/customers`).
- If your table has a different name, replace `customers` with that table's name.
- If you want multiple tables to be accessible, copy the entire `location /[tablename]` block and paste it in as often as you need, replacing `[tablename]` with the names of the tables.
Be sure to change `natconf.dev` to your own domain, as this will otherwise not work.
### Configure the Database
Once you have the database running, we need to create a table to store data in. You can log into the database on your server by running this command to enter the PostgreSQL console: `docker exec -it [service-name] psql -d postgres -U [username]`. `[container-name]` is the name of the PostgreSQL service, which you will see popping up in the terminal after running `docker compose up -d`. It will likely look something like `foldername_database`. `[username]` is the name of the privileged user defined in `compose.yml` under the environment variable `POSTGRES_USER`. This is basically your admin account.
You're best off following [the official guide for PostgREST](https://docs.postgrest.org/en/v14/tutorials/tut0.html#step-3-create-database-for-api). Important steps: create the schema, name it `api` (that's the publicly-accessible schema because we set `PGRST_DB_SCHEMAS: 'api'` in the `compose.yml`), create a table (name has to start with `api.` but can be anything after that, e.g. `api.customers`), insert test data, create the roles `web_anon` and `authenticator` and then quit by typing `\q`. That's all. Welcome back!
You can now access the database data on `https://app.natconf.dev` (if you replace my domain with yours). Keep in mind that the PostgREST guide only grants read access (GET) to the database; in order to POST data to the database, you need to grant `INSERT` privileges to `web_anon`: `grant insert on api.customers to web_anon;`.
If you want a kind voice to guide you through this process, I found [Ian Wootten's video on setting up PostgREST](https://youtu.be/RxuofiZNhtU) to be very nice to follow along.
### POST Data From SvelteKit
The difficult part is done. Sending data from SvelteKit to be inserted into the database is pretty easy, fortunately. You can use `fetch` to do this:
<pre class="code-block">
const response = await fetch(`https://$&#123;API_HOST}/$&#123;API_DB}`, &#123;
method: "POST",
headers: &#123;
"Content-Type": "application/json",
},
body: JSON.stringify(customer),
});
if (response.ok) &#123;
console.log("success");
} else &#123;
console.log("an error occurred: " + response.statusText);
}
</pre>
In this example, I set up two environment variables: `API_HOST` and `API_DB`. Those are secrets that won't be published to your Git provider when you push your changes (if your .gitignore is set up correctly!). `API_HOST` is the fully-qualified domain, e.g. `https://app.natconf.dev`, and `API_DB` is the name of the table, e.g. `customers`. Doing this is not necessary, but it's good practice to keep secrets, especially once you get to the stage of needing passwords or authentication keys. If you want to use environment variables, create a file named `.env` in the root directory of your application, add the variables as such:
<pre class="code-block">
API_HOST="https://app.natconf.dev"
API_DB="customers"
</pre>
...and then import them into your script:
<pre class="code-block">
import &#123;
API_HOST,
API_DB,
} from '$env/static/private';
</pre>
Keep in mind that the `fetch` call is async, meaning that if you wrap this in a function, you will have to declare the function as such, e.g. `async function insertCustomer(...)` and call it using await: `await insertUser(...)`.
Also, the `customer` variable I declared is basically one database entry with the exact same properties as you set it up in PostgreSQL, except for the primary key (likely named `id`). You shouldn't send this in a POST request, as `id` will be auto-generated by the database to be a unique value. That is, unless you *want* to generate these values yourself, in which case, go ahead.
This should now work fine to POST data to the database...
### Fix Error 403 On SvelteKit
...except in production. Once you deploy the application on your server, you may face error *'403: Cross-site POST form submissions are forbidden'*. This is an issue caused by a security measure implemented in the browser that forbids accepting data unless the server sends the correct headers. You will only see this issue in a production build as SvelteKit disables these security measures when you're running a development build. The way I fixed this in production is by adding the domain of my backend to the `trustedOrigins` inside the `kit` block of my `svelte.config.js`:
<pre class="code-block">
kit: &#123;
adapter: adapter(),
csrf: &#123;
trustedOrigins: [
"https://app.natconf.dev"
],
},
},
</pre>
**This is the crucial bit.** Only by adding the URL of my backend to the `trustedOrigins` was I able to fix the 403 errors. Is this the correct way of doing it? Frankly, I don't know. But I do know that you should definitely not put `"*"` as one of the trusted origins, as this would mean your app accepts data from anywhere, and that is *definitely* unsafe.
If you just came here to get a solution for the 403 error that's it! We're done :) But read on for an extra piece of advice as well as my struggle to get this working.
### Your Data Will Be Public
**Important:** the contents of the database will be publicly visible, as we've granted GET (and possibly INSERT) permissions to `web_anon`. You will need to do a little more work to create a safe API that only exposes required data. Use either [PostgREST's guide](https://docs.postgrest.org/en/v14/tutorials/tut1.html) or [Ian Wootten's video](https://youtu.be/RxuofiZNhtU) for guidance on how to restrict and grant access safely.
## The Rant
If you only came for the guide, you've finished it. What follows is me ranting about how difficult it was to get this information.
### Why Did I Write This?
I was building a small SvelteKit application for a project I'm doing together with a friend. I figured it'd be easy, as it's just like building my website, except I'll also make some requests to a backend on my server. I was right... kind of. I have spent *two days* trying to figure out how to do this successfully.
The requests were working fine when I was running the development build of the SvelteKit app on my PC. Once I deployed it though, I was facing *'403: Cross-site POST form submissions are forbidden'* errors for every single request. I couldn't figure out why. I scoured the internet for answers, trying anything I could. I configured `Access-Control-Allow-*` headers in Nginx. I set the `ORIGIN` parameter in the app's `.env`. I ran the app and the database on the same subdomain. Nothing worked. When I tried looking for tutorials, there was *nothing* explaining how I could set up what I had in mind.
How could this be? I'm doing web development 101 here! This isn't some advanced toolchain I'm using, it's the bare minimum for a working application with a backend! Somehow, no resource I could find covered this. Any website I read and any video I watched only ever ran those services locally. Docker containers were spun up on the development client, the client apps were run in development mode (which disables CORS/CSRF security features), and there was never a *live* example given.
### Stupid Gaslighting AI Slop
These days, when looking up tech problems in particular, most of the online resources are AI-generated slop. It was genuinely extremely difficult to avoid them, as they were not just prevalent, but almost entirely dominating the search results. There was this one page that I particularly despised. The worst part? It was actually several pages.
If you stumble upon a page such as `w3tutorials.net` or `tutorialpedia.org`, *run*. Do not take in their information. Avoid at all costs. In fact, these pages both use the very same CSS styling with their dark blue background and fade-in title animation upon page load, and you will find even more domains using this exact same template.
But why run? Is it really that bad? Maybe the information is useful?
I'm going to prove why you should avoid generative AI at all costs. Let's go through the article I read: "How to Fix 'Cross-site POST Form Submissions Are Forbidden' Error in SvelteKit: Dev Server Works, Build Fails". Extremely long title, but it in fact describes my exact problem. Four 'fixes' are given:
1. Use Relative Form Actions
This 'fix' describes using relative paths to access form URLs. Instead of `https://app.natconf.dev/customers`, I should just use `/customers`.
This doesn't work.
2. Include the CSRF Token
This 'fix' explains that the issue may be caused by the lack of a CSRF token included in the form that would verify the validity of the submission. The solution is to import the token into the app using `import { csrfToken } from '$app/stores';` and then including the token in a hidden `<input>` named `_csrf`.
*What in the hell* did this AI smoke to hallucinate this? There is no such thing as an importable CSRF token, and it wouldn't make sense for the solution to just be 'send the token along with the request'. Who's validating the token? How would they know it's valid? You would need server-side validation of the token, which is a real thing, but you'd need to code that yourself or use a library for it. You can't just send a random string and say "this request is real, here's some random text to prove it".
3. Configure `ORIGIN` and Environment Variables
Ignoring the fact that their markdown styling doesn't work correctly and shows the \` marks on text that is supposed to be monospaced, this 'fix' alleges that setting the `ORIGIN` environment variable needs to be set to the domain the application is running on so that SvelteKit is aware of this domain.
This *may* work? SvelteKit documentation does [make mention of an `ORIGIN` variable](https://svelte.dev/docs/kit/adapter-node#Environment-variables-ORIGIN-PROTOCOL_HEADER-HOST_HEADER-and-PORT_HEADER) used in the Node adapter. However, as far as I could tell, this had no effect on my app.
4. Check Server Hooks (Handle Function)
This 'fix' accuses you, the developer, of explicitly deleting the required headers for CSRF validation using code such as: `delete event.request.headers.origin;`. *Excuse me?* You little piece of shit. How dare you accuse me of something like this? No, of course I haven't explicitly deleted the headers from my request!
Actually, now that I think about it, this is a very odd thing for an AI to produce. Usually, they are overly positive towards the user. I guess this one was still positively phrased and only indirectly accusing the reader of the mistake. Still, the implication is ridiculous.
### No Surprise Stack Overflow is Dying
Alas, I couldn't find anything helping my cause. In my most desperate moment, I came up with an idea I never thought I'd pursue: *asking a question on Stack Overflow*. **THE** Stack Overflow! The place where arrogant people get high on the most minuscule amounts of power or so I've heard. It can't be that bad.
I wasn't entirely sure whether my problem lied in my SvelteKit, Nginx, or PostgreSQL setup, so I documented them briefly but with the necessary detail in my question. I described my plan and my previous attempts at fixing the issue at hand, including links to the resources I had used. I formatted the entire thing and structured it so that it would be relatively simple to digest. It also had a concluding question to summarise my problem at the end. I read their entire stupid article on 'writing a good question'. What a ridiculous article.
I submitted it to the Staging Ground, which is apparently a Stack Overflow-exclusive thing where new users are forced (?) to submit their questions for 'experienced' users to judge them (which is such a fucking weird concept) and give advice. Fair enough, I thought, I have a fairly open mind and I'd gladly receive constructive feedback so that others could answer my question better.
What instead happened was that within less than 10 minutes of posting my question, two users deemed my question 'off-topic' with the reason 'this question is not about programming or software development' and closed it before it went public. wow. One of them at least had the decency of giving me the advice to post in either Server Fault or Database Administrators. Seeing that this *definitely* wasn't a database problem, I deemed the latter suggestion misguided at best, but I did try Server Fault instead. I copy-pasted my question, submitted it directly (they had no such thing as a Staging Ground), and proceeded to receive no answers.
The best part: once I figured out the solution to my problem on my own, it became abundantly clear that my problem was caused by SvelteKit. This means:
- the question was actually off-topic on Server Fault
- the question was indeed correct to be posted on Stack Overflow
- whoever judged my question to be 'off-topic' likely only wanted to exercise their virtual 'power' and didn't even bother reading and understanding my question while expecting me to read paragraphs on 'how to ask a good question'
You know what? Stack Overflow can burn in hell. No wonder its user base is continually shrinking. What a horrible, toxic place. I'm saying this mostly because of the things I've *heard* about Stack Overflow, but my short first-hand experience clearly showed that those things are true.

View File

@@ -0,0 +1,32 @@
<p class="lightyears-text">The world looks so different now. The world looks so different now. The world looks so different now.</p>
## Background
One of my favourite music artists, [Jaron](https://youtu.be/GXvqQ5-P82I), released his album LIGHTYEARS a little over a year ago. For his visuals, he uses a variety of symbols in place of Latin letters, and there's a converter on [his website](https://jaronsteele.com/) too. Only problem is that my browser can't seem to display most of the characters because the characters aren't included in most fonts.
That's why I made a font! It allows you to type Latin characters from `A-Z` as well as numbers `0-9` and `!?` in the LIGHTYEARS style. Like this:
<p class="lightyears-text">trans rights!</p>
The font exclusively uses characters from the Noto font family. Many of the Noto varieties have been stitched together to recreate the whole LIGHTYEARS alphabet.
To create the font, I used [FontForge](https://fontforge.org). Finding this tool was both a blessing and a curse, as it was exactly what I needed, but it kept. crashing. all. the. time. I tried both the AppImage as well as the release on `dnf` and both had the same issues. I managed to make it work, but it took a lot of patience. Eventually I figured out that importing Noto Maths gave me a 3-8 second window before the editor crashed. The project file would forget the imported font, but if I had copied any glyphs it would keep those.
## Download & use
[Download the font here](https://files.natconf.dev/public/lightyears.woff2). It's in the web-optimised `woff2` format and has most characters stripped to minimise its file size it's less than 20 kilobytes in size! Uppercase and lowercase letters are the same.
For use on your website, put the font into your resources/static/similar folder and then add this block of code to your CSS file:
<pre class="code-block">
@font-face &#123;
font-family: "LIGHTYEARS";
src: url("/fonts/lightyears.woff2");
font-weight: 400;
font-style: normal;
}
</pre>
Then you can change any element's font by setting `font-family: 'LIGHTYEARS', sans-serif;`. Because it's the Latin characters and Arabic numbers that have been changed, you can type text in regular English and people can 'decrypt' the messages by copy-pasting the text somewhere else!
You do **not** need Jaron's converter to type stylised text! The converter returns the actual symbols from other scripts, whereas this font only changes how letters look.

View File

@@ -0,0 +1,7 @@
I'm switching my website domain from `denizk0461.dev` to `natconf.dev`!
All I can say for now about this change is that I came up with this domain name a while back and I liked it more so than `denizk0461.dev` , so I've been thinking about migrating.
I'm updating things as I go. All links on this website now point to the new domain, and all services have been moved over too. As of right now, they're also still accessible via the old domain, but I will be disabling that soon. Instead, I'll set up redirects, which will be in place until the domain expires on 2026-06-04.
I *may* change up some visual elements in the process, but it won't be a major redesign.

View File

@@ -1,7 +1,7 @@
<script> <script>
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
export let data; export let data;
</script> </script>

View File

@@ -4,7 +4,7 @@ import { posts } from "../posts";
const xml = () => `<rss version="2.0"> const xml = () => `<rss version="2.0">
<channel> <channel>
<title>denizk0461's Blog</title> <title>denizk0461's Blog</title>
<link>https://denizk0461.dev/blog/</link> <link>https://natconf.dev/blog/</link>
<description><![CDATA[denizk0461 blogs about stuff here]]></description>${getEntries()} <description><![CDATA[denizk0461 blogs about stuff here]]></description>${getEntries()}
</channel> </channel>
</rss>`; </rss>`;
@@ -16,8 +16,8 @@ function getEntries(): String {
<item> <item>
<title><![CDATA[${entry.post.title}]]></title> <title><![CDATA[${entry.post.title}]]></title>
<description><![CDATA[${entry.post.description}]]></description> <description><![CDATA[${entry.post.description}]]></description>
<link>https://denizk0461.dev/blog/${entry.key}</link> <link>https://natconf.dev/blog/${entry.key}</link>
<guid isPermaLink="true">https://denizk0461.dev/blog/${entry.key}</guid> <guid isPermaLink="true">https://natconf.dev/blog/${entry.key}</guid>
<pubDate><![CDATA[${new Date(`${entry.post.date}T${entry.post.time}`).toUTCString()}]]></pubDate> <pubDate><![CDATA[${new Date(`${entry.post.date}T${entry.post.time}`).toUTCString()}]]></pubDate>
</item>`) </item>`)
entries.forEach(entry => { entries.forEach(entry => {

View File

@@ -23,20 +23,68 @@ export interface BlogPostLink {
export const posts: BlogPostLink[] = [ export const posts: BlogPostLink[] = [
// ["2026/0128", { {
// date: "2026-01-05", key: "2026/0326",
// time: "13:00", post: {
// banner: "langstone.webp", date: "2026-03-26",
// title: "Portsmouth Postmortem", time: "20:50",
// description: "", banner: "banner.webp",
// }], bannerAlt: "White light blurs on a darker background.",
title: "Moving On",
description: "It's time to switch domains.",
}
},
{
key: "2026/0325",
post: {
date: "2026-03-25",
time: "22:22",
banner: "banner.webp",
bannerAlt: "A sunset captured from an Autobahn exit.",
title: "I made a LIGHTYEARS font",
description: "I feel electric and it's only getting brighter!",
}
},
{
key: "2026/0317",
post: {
date: "2026-03-17",
time: "17:00",
banner: "banner.webp",
bannerAlt: "A Microsoft Surface Pro 8 displaying a Blue Screen of Death.",
title: "How To: Set Up SvelteKit Frontend + PostgreSQL Backend",
description: "How to set up a web application with a backend on a remote server without getting error 403.",
}
},
{
key: "2026/0214",
post: {
date: "2026-02-14",
time: "19:46",
banner: "logins.webp",
bannerAlt: "A curved stick from a tree with some dry leaves attached. Its form resembles an entity with two legs, a spine, and no arms, leaning over and looking sad.",
title: "SSH Woes",
description: "About how I was shocked to learn that my server was open for attacks for well over a year.",
}
},
{
key: "2026/0208",
post: {
date: "2026-02-08",
time: "17:45",
banner: "sadstick.webp",
bannerAlt: "A curved stick from a tree with some dry leaves attached. Its form resembles an entity with two legs, a spine, and no arms, leaning over and looking sad.",
title: "Am I doing too much?",
description: "I'm trying to pursue too many hobbies all at once and it's a struggle.",
}
},
{ {
key: "2026/0205", key: "2026/0205",
post: { post: {
date: "2026-02-05", date: "2026-02-05",
time: "22:55", time: "22:55",
banner: "", banner: "banner.webp",
bannerAlt: "", bannerAlt: "A Leuchtturm-branded notebook with a copper-coloured cover. An eraser, a pencil sharpener, and a Faber-Castell pencil are lying on top.",
title: "Drawing Challenge", title: "Drawing Challenge",
description: "Challenging myself to draw something every day for 4 weeks.", description: "Challenging myself to draw something every day for 4 weeks.",
} }
@@ -64,9 +112,3 @@ export const posts: BlogPostLink[] = [
} }
}, },
]; ];
// export function getDate(post: BlogPostDetails): string {
// var s = [post.year, post.date.split()].join("");
// s.
// return "";
// }

View File

@@ -1,27 +0,0 @@
import { type ChangelogEntry } from "$lib/components/changelog-entry.svelte";
export const entries: ChangelogEntry[] = [
{
date: "2026-02-06",
time: "18:47",
content: "Started a 28-day drawing challenge for myself! Updating the blog post every day with my new drawings.",
link: "/blog/2026/0205",
},
{
date: "2026-02-03",
time: "22:46",
content: "Created a new gallery widget for the main page and added a link to the new Gitea instance.",
},
{
date: "2026-02-03",
time: "15:48",
content: "Now running my own Gitea instance! It now also hosts my website repository.",
link: "https://code.denizk0461.dev/denizk0461/pages",
},
{
date: "2026-02-02",
time: "19:30",
content: "Updated some texts and moved my contact info to the about page. Also created this changelog!",
link: "/meta/about",
},
];

View File

@@ -1,151 +0,0 @@
<script lang="ts">
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
import { drawings, type DrawingData } from "./drawing-data";
let selectedDrawingIndex: number = $state(-1);
function selectDrawing(index: number) {
selectedDrawingIndex = index;
}
</script>
<svelte:head>
<title>Drawing Gallery | denizk0461</title>
</svelte:head>
{#snippet drawing({ drawing }: { drawing: DrawingData })}
<button class="drawing-link-container" onclick={(event) => selectDrawing(drawings.indexOf(drawing))}>
<div class="drawing-content-container">
<img class="drawing-img" src="{drawing.fileName}" alt="{drawing.altText}">
<div class="drawing-overlay"></div>
</div>
</button>
{/snippet}
{#snippet inspector({ index }: { index: number })}
{#if index == -1}
<p class="inspector-img-note">click on an image to view details about it</p>
{:else}
<a class="inspector-link" href="{drawings[index].fileName}">
<img class="inspector-img" src="{drawings[index].fileName}" alt="{drawings[index].altText}">
</a>
<p class="inspector-date">{drawings[index].date}</p>
<hr>
{#each drawings[index].notes as n}
<p class="inspector-paragraph">{n}</p>
{/each}
{/if}
{/snippet}
<Content>
<Banner2
title="Drawing Gallery" />
<p>I'm trying this to motivate myself to draw more now. Let's see where this takes us.</p>
<div class="page-container">
<div class="drawing-gallery">
{#each drawings as d}
{@render drawing({drawing: d})}
{/each}
</div>
<div class="inspector">
{@render inspector({ index: selectedDrawingIndex })}
</div>
</div>
</Content>
<style>
.page-container {
display: flex;
flex-direction: row;
}
.drawing-gallery {
display: flex;
flex-wrap: wrap;
width: 60%;
padding-right: 16px;
box-sizing: border-box;
}
.drawing-link-container {
display: flex;
height: 14vh;
flex-grow: 1;
overflow: hidden;
}
.drawing-content-container {
position: relative;
cursor: pointer;
}
.drawing-img {
max-height: 100%;
min-width: 100%;
object-fit: cover;
vertical-align: bottom;
transition: scale 0.06s ease-out, filter 0.06s ease-out;
}
.drawing-overlay {
opacity: 0;
transition: opacity 0.06s ease-out;
background-color: var(--color-background-highlight-hover-dark);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
pointer-events: none;
display: flex;
flex-direction: column;
justify-content: end;
}
.drawing-content-container:hover .drawing-overlay {
opacity: 1;
}
.drawing-content-container:hover .drawing-img, .inspector-link:hover .inspector-img {
scale: 1.1;
/* filter: grayscale(60%); */
}
.inspector {
width: 40%;
display: flex;
flex-direction: column;
}
.inspector-link {
width: 100%;
margin-left: auto;
margin-right: auto;
overflow: hidden;
}
.inspector-img {
width: 100%;
margin: 0;
transition: scale 0.06s ease-out;
}
.inspector-date {
font-family: var(--font-mono);
font-weight: 600;
color: var(--color-highlight);
margin: 2px 0;
}
.inspector-paragraph {
margin: 2px 0;
}
.inspector-img-note {
padding: 64px 16px;
background-color: var(--color-background-highlight);
}
</style>

View File

@@ -1,31 +0,0 @@
export interface DrawingData {
fileName: string;
altText: string;
// Format: yyyy-MM-dd
date: string;
notes: string[];
}
export let drawings: DrawingData[] = [
{
fileName: "2026/breadgirl.webp",
altText: "An anime-style girl chewing on a piece of bread. She wears a ponytail and a sleeveless top.",
date: "2026-01-30",
notes: [
"I drew her during a game of Wizard. I initially wanted to make her chew on a whole loaf but I wasn't sure if I could draw that.",
"Wasn't really sure how to convey that her mouth is full, but in retrospect, I could have exaggerated the bow in her lower eyelids to do so.",
"I like her eyes. Her head could be taller, actually.",
],
},
{
fileName: "2026/girl.webp",
altText: "An anime-style girl's head. She has a ponytail and is looking towards the left with a concentrated gaze.",
date: "2026-01-29",
notes: [
"Her nose is a bit high but I do like her focused gaze. I think I nailed the eyes, to be honest, at least the left one, considering the drawing is just 3x4cm.",
"I'm super happy with this, especially since it was my first try drawing in a long time and I only used a ballpoint pen (non-erasable!).",
],
},
];

View File

@@ -1,72 +1,72 @@
<script lang="ts"> <script lang="ts">
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
import LinkList, { type LinkEntry } from "$lib/lists/link-list.svelte"; import LinkList, { type LinkEntry } from "$lib/lists/link-list.svelte";
let favouriteAlbums: LinkEntry[] = [ let favouriteAlbums: LinkEntry[] = [
{ {
text: "acloudyskye <i>This Won't Be The Last Time</i> (placeholder for all albums Skye has made)", text: "acloudyskye <b>This Won't Be The Last Time</b> (placeholder for all albums Skye has made)",
link: "https://acloudyskye.bandcamp.com/album/this-wont-be-the-last-time", link: "https://acloudyskye.bandcamp.com/album/this-wont-be-the-last-time",
}, },
{ {
text: "Avicii <i>True</i> (first album I ever bought a physical copy of)", text: "Avicii <b>True</b> (first album I ever bought a physical copy of)",
link: "https://en.wikipedia.org/wiki/True_(Avicii_album)", link: "https://en.wikipedia.org/wiki/True_(Avicii_album)",
}, },
{ {
text: "bitbird artists <i>create together vol. 3</i> (amazing compilation)", text: "bitbird artists <b>create together vol. 3</b> (amazing compilation)",
link: "https://bitbird.bandcamp.com/album/create-together-vol-3", link: "https://bitbird.bandcamp.com/album/create-together-vol-3",
}, },
{ {
text: "brakence <i>hypochondriac</i>", text: "brakence <b>hypochondriac</b>",
link: "https://soundcloud.com/brakence/sets/hypochondriac-4", link: "https://soundcloud.com/brakence/sets/hypochondriac-4",
}, },
{ {
text: "femtanyl <i>CHASER</i>", text: "femtanyl <b>CHASER</b>",
link: "https://femtanyl.bandcamp.com/album/chaser", link: "https://femtanyl.bandcamp.com/album/chaser",
}, },
{ {
text: "Frost Children <i>SISTER</i>", text: "Frost Children <b>SISTER</b>",
link: "https://frostchildren.bandcamp.com/album/sister", link: "https://frostchildren.bandcamp.com/album/sister",
}, },
{ {
text: "Jane Remover <i>Frailty</i>", text: "Jane Remover <b>Frailty</b>",
link: "https://janeremover.bandcamp.com/album/frailty-2", link: "https://janeremover.bandcamp.com/album/frailty-2",
}, },
{ {
text: "Jane Remover <i>Census Designated</i>", text: "Jane Remover <b>Census Designated</b>",
link: "https://janeremover.bandcamp.com/album/census-designated", link: "https://janeremover.bandcamp.com/album/census-designated",
}, },
{ {
text: "Jaron <i>it's hard to see color [When You're So Impossibly Far Away*]</i>", text: "Jaron <b>it's hard to see color [When You're So Impossibly Far Away*]</b>",
link: "https://jaronsteele.bandcamp.com/album/its-hard-to-see-color-when-youre-so-impossibly-far-away", link: "https://jaronsteele.bandcamp.com/album/its-hard-to-see-color-when-youre-so-impossibly-far-away",
}, },
{ {
text: "Jaron <i>LIGHTYEARS</i>", text: "Jaron <b>LIGHTYEARS</b>",
link: "https://jaronsteele.bandcamp.com/album/lightyears", link: "https://jaronsteele.bandcamp.com/album/lightyears",
}, },
{ {
text: "kmoe <i>K1</i>", text: "kmoe <b>K1</b>",
link: "https://kmoethekid.bandcamp.com/album/k1", link: "https://kmoethekid.bandcamp.com/album/k1",
}, },
{ {
text: "leroy <i>Grave Robbing</i>", text: "leroy <b>Grave Robbing</b>",
link: "https://soundcloud.com/c0ncernn/sets/nonstop", link: "https://soundcloud.com/c0ncernn/sets/nonstop",
}, },
{ {
text: "Ninajirachi <i>I Love My Computer</i>", text: "Ninajirachi <b>I Love My Computer</b>",
link: "https://ninajirachi.bandcamp.com/album/i-love-my-computer", link: "https://ninajirachi.bandcamp.com/album/i-love-my-computer",
}, },
{ {
text: "underscores <i>fishmonger</i>", text: "underscores <b>fishmonger</b>",
link: "https://underscores.bandcamp.com/album/fishmonger", link: "https://underscores.bandcamp.com/album/fishmonger",
}, },
{ {
text: "venturing <i>Ghostholding</i>", text: "venturing <b>Ghostholding</b>",
link: "https://janeremover.bandcamp.com/album/ghostholding", link: "https://janeremover.bandcamp.com/album/ghostholding",
}, },
{ {
text: "xaev <i>TO-THE-CORE_153BPM</i>", text: "xaev <b>TO-THE-CORE_153BPM</b>",
link: "https://xaev.bandcamp.com/album/to-the-core-153bpm", link: "https://xaev.bandcamp.com/album/to-the-core-153bpm",
}, },
]; ];
@@ -78,7 +78,7 @@
}, },
{ {
text: "Bluesky", text: "Bluesky",
link: "https://bsky.app/profile/denizk0461.dev", link: "https://bsky.app/profile/natconf.dev",
}, },
{ {
text: "Codeberg", text: "Codeberg",
@@ -131,7 +131,7 @@
<LinkList entries={favouriteAlbums} /> <LinkList entries={favouriteAlbums} />
<p>Almost all the links lead to the artists' Bandcamp profiles because I buy my music files to listen locally on my phone and PC. I vastly prefer this over streaming services, not least because I can actually financially support the artists this way.</p> <p>Almost all the links lead to the artists' Bandcamp profiles because I buy my music files to listen to locally on my phone and PC. I vastly prefer this over streaming services, not least because I can actually financially support the artists this way.</p>
<h2 id="what">About this website</h2> <h2 id="what">About this website</h2>
@@ -147,11 +147,11 @@
<h4 id="hardware">Hardware</h4> <h4 id="hardware">Hardware</h4>
<p>I am using either my <a href="https://www.campuspoint.de/lenovocampus-ideapad-pro-5-14-akp-g10-83jl0011ge.html">laptop</a> or my PC, which I built myself in mid-2023 key specs are: AMD Ryzen 5700X, ASUS RTX 3070, 32 GB memory, 2 TB NVMe storage, 1 TB HDD. Both my computers are currently running <a href="https://fedoraproject.org/">Fedora</a> with the KDE Plasma desktop environment. It's a really solid Linux distro that allowed me to free myself from Micro$lop's Windows once and for all. There's a bit of setup required right after installing (for which I used <a href="https://github.com/devangshekhawat/Fedora-43-Post-Install-Guide">a guide</a>) but once that's done, using the operating system is just as simple as using Windows, except it's far less bloated and much more customisable. Look, I set my application launcher icon to Clank in his backpack form:</p> <p>I am using either my <a href="https://www.campuspoint.de/lenovocampus-ideapad-pro-5-14-akp-g10-83jl0011ge.html">laptop</a> (named <a href="https://acloudyskye.bandcamp.com/track/skull-eater">skulleater</a>) or my PC (named <a href="https://acloudyskye.bandcamp.com/track/overthrower-2">overthrower</a>), which I built myself in mid-2023 key specs of the PC are: AMD Ryzen 5700X, ASUS RTX 3070, 32 GB memory, 2 TB NVMe storage, 1 TB HDD. Both my computers are currently running <a href="https://fedoraproject.org/">Fedora</a> with the KDE Plasma desktop environment. It's a really solid Linux distro that allowed me to free myself from Micro$lop's Windows once and for all after using it for a while, I can wholeheartedly recommend it if you're looking to go Linux. There's a bit of setup required right after installing (for which I used <a href="https://github.com/devangshekhawat/Fedora-43-Post-Install-Guide">a guide</a>) but once that's done, using the operating system is just as simple as using Windows, except it's far less bloated, much more customisable, and doesn't force unwanted (AI) features down your throat. Look, I set my application launcher icon to Clank in his backpack form:</p>
<img alt="Screenshot of the taskbar of a Fedora KDE setup. There are multiple icons. From left to right: Clank as the application launcher icon, Firefox, fooyin music player, Dolphin file explorer." src="taskbar.webp"> <img alt="Screenshot of the taskbar of a Fedora KDE setup. There are multiple icons. From left to right: Clank as the application launcher icon, Firefox, fooyin music player, Dolphin file explorer." src="taskbar.webp">
<p>As for the server infrastructure: the website is hosted on a Hetzner server instance I am renting. It's a relatively cheap CPX22 node that costs me 7,72€ a month, and besides my website, it's also hosting things such as a Nextcloud instance and a Minecraft server. In order to host and update the website, I wrote a small bash script that pulls the changes from the <a href="https://code.denizk0461.dev/denizk0461/pages">Git repository</a>, builds the website as a Node server, and then exposes it via Nginx.</p> <p>As for the server infrastructure: the website is hosted on a Hetzner server instance I am renting. It's a relatively cheap CPX22 node that costs me 7,72€ a month, and besides my website, it's also hosting things such as a Nextcloud instance and a Minecraft server. In order to host and update the website, I wrote a small bash script that pulls the changes from the <a href="https://code.natconf.dev/denizk0461/pages">Git repository</a>, builds the website as a Node server, and then exposes it via Nginx.</p>
<h4 id="software">Tools & Software</h4> <h4 id="software">Tools & Software</h4>
@@ -163,21 +163,60 @@
<p>Posts in <a href="/blog">Blog</a> and the <a href="/projects/projectn5">Project N5 devlog</a> are generated from Markdown using <a href="https://mdsvex.pngwn.io/">mdsvex</a> by pngwn.</p> <p>Posts in <a href="/blog">Blog</a> and the <a href="/projects/projectn5">Project N5 devlog</a> are generated from Markdown using <a href="https://mdsvex.pngwn.io/">mdsvex</a> by pngwn.</p>
<p>Body text uses <a href="https://github.com/cadsondemak/Bai-Jamjuree">Bai Jamjuree</a> by Cadson Demak, headers and monospaced text use <a href="https://github.com/isaozler/kode-mono">Kode Mono</a> by Isa Ozler.</p> <p>Body text uses <a href="https://github.com/cadsondemak/Bai-Jamjuree">Bai Jamjuree</a> by Cadson Demak, headers and monospaced text use <a href="https://github.com/isaozler/kode-mono">Kode Mono</a> by Isa Ozler; both are licenced under the <a href="https://openfontlicense.org/open-font-license-official-text/">SIL Open Font License</a>. Emojis are designed by <a href="https://openmoji.org/">OpenMoji</a>, licenced under the <a href="https://creativecommons.org/licenses/by-sa/4.0/#">CC BY-SA 4.0</a> license.</p>
<p><a href="/robots.txt">robots.txt</a> and <a href="/ai.txt">ai.txt</a> are courtesy of <a href="https://baccyflap.com/res/robots/">baccyflap.com</a></p>
<p>The <a href="https://ratchetandclank.fandom.com/wiki/Ratchet">rat</a> in the bottom right of the screen is property of <a href="https://insomniac.games/">Insomniac Games</a>. Clicking it will bring you good fortune.</p> <p>The <a href="https://ratchetandclank.fandom.com/wiki/Ratchet">rat</a> in the bottom right of the screen is property of <a href="https://insomniac.games/">Insomniac Games</a>. Clicking it will bring you good fortune.</p>
<h2 id="contact">Where to find me</h2> <p>The style of the webring elements is adapted from a template provided by Rainbow Cemetery for the <a href="https://www.rainbowcemetery.com/devring/">Gamedev webring</a>. I adapted it into <a href="https://code.natconf.dev/denizk0461/pages/src/branch/master/src/lib/components/ring.svelte">a Svelte component</a> that allows setting the links, emojis, and arrows more easily.</p>
<p>Best to e-mail me if you want to get in touch I try to respond quickly!</p> <h2 id="contact">Contact / Where to find me</h2>
<p>Best to e-mail me if you want to get in touch it's the only way I'm currently reliably available!</p>
<LinkList entries={links} /> <LinkList entries={links} />
<p>You can also try messaging me on Discord (@denizk0461) <span class="small-supertext">but good luck i'm hardly active there lmao</span></p> <p>I removed my Discord username because I don't want to use Discord anymore, now that they <a href="https://www.zdnet.com/article/discord-age-verification-requirement/">ask for facial data and/or government ID that they force to be scanned by third-party AI</a> and then <a href="https://arstechnica.com/tech-policy/2026/02/discord-faces-backlash-over-age-checks-after-data-breach-exposed-70000-ids/">leak it...</a> Apparently they are also about to be <a href="https://www.zdnet.com/article/microsoft-may-be-poised-to-buy-its-next-community-discord/">bought up by Micro$lop</a>?? I prefer not to use Discord anymore, although I will admit I don't have any good alternative at the moment.</p>
<h2>Anything else?</h2> <h2>Anything else?</h2>
<p>hmm... maybe worth it to point out that this website and everything else I make comes straight from my own hands and brain. No generative AI is used, ever.</p> <p>hmm... maybe worth it to point out that this website and everything else I make comes straight from my own hands and brain. No generative AI is used, ever.</p>
<p><i>Last updated: 2026-02-02</i></p> <p>Have a small FAQ. No one ever asked these questions, but you may find the answer you didn't know you needed.</p>
<p class="faq-question">What does '0461' stand for?</p>
<p>It's a reference to Ratchet & Clank; Clank's designation is <a href="https://ratchetandclank.fandom.com/wiki/Clank">XJ-0461</a>. They started using that designation in <i>Ratchet & Clank: A Crack in Time</i> when Orvus is revealed to be Clank's father and he keeps calling him by his 'real' name.</p>
<p class="faq-question">If you could take 3 albums to a desert island, which ones?</p>
<p>acloudyskye's <a href="https://acloudyskye.bandcamp.com/album/there-must-be-something-here">There Must Be Something Here</a> as an emotional/melodic record, Jaron's <a href="https://jaronsteele.bandcamp.com/album/its-hard-to-see-color-when-youre-so-impossibly-far-away">it's hard to see color [When You're So Impossibly Far Away*]</a> for its pure hyperpop energy, and venturing's <a href="https://janeremover.bandcamp.com/album/ghostholding">Ghostholding</a> as an emotional/sad album.</p>
<p class="faq-question">Tell me a fun fact.</p>
<p>When I was recently replaying the original Ratchet & Clank (2002) in German, I noticed again that the dialogue translated into German is often longer than the original English dialogue, which makes characters' voice lines run into one another. This doesn't happen in the English original.</p>
<p>This is most noticeable in the cutscene that plays after you acquire the Hologuise on planet Kalebo III, where <a href="https://youtu.be/XIShUN7AUqg?t=3479">the narrator explains how the Hologuise works</a>. The narrations lags WAY behind the visuals, to the point that there's a brief black screen at the end while the narration is still ongoing, and then it just cuts off the narrator entirely.</p>
<hr>
<p><i>Last updated: 2026-03-26</i></p>
</Content> </Content>
<style>
.faq-question {
font-weight: bold;
color: var(--color-highlight);
font-family: var(--font-mono);
margin-bottom: 0;
}
.faq-question::before {
content: '↘ ';
}
.faq-question + p {
margin-top: 0;
}
</style>

View File

@@ -9,7 +9,7 @@
link: "/blog/feed.xml", link: "/blog/feed.xml",
}, },
{ {
text: "Project N5 devlog", text: "Homesick devlog",
link: "/projects/projectn5/devlog/feed.xml", link: "/projects/projectn5/devlog/feed.xml",
}, },
] ]

View File

@@ -13,7 +13,7 @@
<p>This page uses <b>no cookies</b> as of now. No data will be stored on your device while browsing this website. <b>No trackers</b> are used either <b>no analytics</b>, not even a visit counter of any kind. Not by a third-party, and currently, none I built myself either.</p> <p>This page uses <b>no cookies</b> as of now. No data will be stored on your device while browsing this website. <b>No trackers</b> are used either <b>no analytics</b>, not even a visit counter of any kind. Not by a third-party, and currently, none I built myself either.</p>
<p>The Godot and Unity projects on the <code>apps.denizk0461.dev</code> subdomain <i>may</i> cache compiled shaders on your device, I'm not sure. These files would only be used by your GPU to render visual effects for the game they were compiled for.</p> <p>The Godot and Unity projects on the <code>apps.natconf.dev</code> subdomain <i>may</i> cache compiled shaders on your device, I'm not sure. These files would only be used by your GPU to render visual effects for the game they were compiled for.</p>
<p>Last updated: 2025-09-10</p> <p>Last updated: 2025-09-10</p>
</Content> </Content>

View File

@@ -1,17 +1,17 @@
<script lang="ts"> <script lang="ts">
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import { entries } from "./changelog"; import { entries } from "./updates";
import ChangelogEntry from "$lib/components/changelog-entry.svelte"; import ChangelogEntry from "$lib/components/update-entry.svelte";
</script> </script>
<svelte:head> <svelte:head>
<title>Changelog | denizk0461</title> <title>Website Updates | denizk0461</title>
</svelte:head> </svelte:head>
<Content> <Content>
<Banner2 <Banner2
title="Website Changelog" /> title="Website Updates" />
<div> <div>
{#each entries as entry} {#each entries as entry}

View File

@@ -0,0 +1,86 @@
import { type UpdateEntry } from "$lib/components/update-entry.svelte";
export const entries: UpdateEntry[] = [
{
date: "2026-03-26",
time: "20:50",
content: "<b>Important</b>: my website is changing domains.",
link: "/blog/2026/0326",
},
{
date: "2026-03-25",
time: "22:22",
content: "I made a LIGHTYEARS font!",
link: "/blog/2026/0325",
},
{
date: "2026-03-17",
time: "17:10",
content: "a bit uncharacteristic, but I wrote a guide on setting up a SvelteKit app + backend because I found NOTHING of the sort online.",
link: "/blog/2026/0317",
},
{
date: "2026-03-11",
time: "19:21",
content: "new page: my drawings!",
link: "/art/drawings",
},
{
date: "2026-03-07",
time: "14:12",
content: "I fancied up some element animations, especially on the devlog and blog pages! The main page also got some love.",
},
{
date: "2026-03-05",
time: "23:59",
content: "My drawing challenge is complete I learned to draw!",
link: "/blog/2026/0205",
},
{
date: "2026-02-26",
time: "20:21",
content: "There's now a new Small Projects page where I gradually add some of my smaller projects.",
link: "/projects/small",
},
{
date: "2026-02-25",
time: "19:33",
content: "Added cool status markers to the projects page that show whether a project is currently active.",
link: "/projects",
},
{
date: "2026-02-21",
time: "16:25",
content: "My website is now also part of the no AI webring!",
link: "https://baccyflap.com/noai",
},
{
date: "2026-02-16",
time: "18:44",
content: "My website is now part of the bucket webring!",
link: "https://webring.bucketfish.me/",
},
{
date: "2026-02-06",
time: "18:47",
content: "Started a 28-day drawing challenge for myself! Updating the blog post every day with my new drawings.",
link: "/blog/2026/0205",
},
{
date: "2026-02-03",
time: "22:46",
content: "Created a new gallery widget for the main page and added a link to the new Gitea instance.",
},
{
date: "2026-02-03",
time: "15:48",
content: "Now running my own Gitea instance! It now also hosts my website repository.",
link: "https://code.natconf.dev/denizk0461/pages",
},
{
date: "2026-02-02",
time: "19:30",
content: "Updated some texts and moved my contact info to the about page. Also created this changelog!",
link: "/meta/about",
},
];

View File

@@ -1,180 +0,0 @@
<script lang="ts">
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
</script>
<svelte:head>
<title>Uses | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Uses"
banner="/projects/banner.webp"
bannerAlt="Closeup of the purple protagonist from Project N5"
subtitle="A list of the hardware and software I use for my creative tasks" />
<div class="container">
<div class="column">
<h2>Hardware</h2>
<ul>
<li>Self-built tower PC
<ul>
<li>Components include a Fractal Pop Mini Air case, an AMD Ryzen 5600 CPU, an Nvidia RTX 3070 graphics card, and 2 TB of Samsung NVMe storage</li>
<li>I also carried over the DVD drive from my old PC</li>
<li>Three monitors are plugged into my PC: a 32in Samsung M7 2160p smart monitor, a 24in 1080p Samsung TV from 2014, and a 24in 1200p 16:10 Dell monitor</li>
</ul>
</li>
<li>Lenovo IdeaPad Pro 5-14AKP G10
<ul>
<li>Currently running Windows 11, but I'm planning to install Fedora KDE!</li>
</ul>
</li>
<li>Logitech MX Master 3S mouse
<ul>
<li>Don't buy this. I kind of like the mouse, but the rubber is clearly taking a toll from regular use</li>
<li>Also, the left/right click buttons are cheap and WILL fail. I already replaced mine because the right click was far too unreliable (worked maybe 20% of the time). Replacing the microswitch requires soldering</li>
<li>Also also, it only has a 125 Hz polling rate, which is pretty low, especially when using a 120+ Hz display</li>
<li>As far as I read, the MX Master 4 is plagued by the same issues, except for the rubber, which was fortunately replaced with solid plastic</li>
</ul>
</li>
<li>Logitech MX Mechanical keyboard
<ul>
<li>I like this keyboard, despite the issues with the related mouse!</li>
<li>I should maybe have gotten the non-numpad version, because it is quite wide...</li>
<li>I do like having the numpad though</li>
</ul>
</li>
<li>Beyerdynamic DT 770 Pro headphones
<ul>
<li>Love these headphones. They're not the most stylish, but they sound <i>really</i> good</li>
<li>They're best suited for indoor use though</li>
</ul>
</li>
<li>Anker Nano 100W USB-C charger
<ul>
<li>I carry this with me everywhere. Since virtually all my devices use USB-C nowadays, I can charge anything using just this small brick</li>
</ul>
</li>
<li>Bambu Lab A1 mini 3D printer
<ul>
<li>Very easy-to-use 3D printer! Produces good results too</li>
<li>I don't really recommend it though. Bambu is pretty much the Apple of 3D printing; you'll be locked into their ecosystem</li>
</ul>
</li>
<li>Samsung Galaxy S20 FE
<ul>
<li>Bought this in 2021 and have no issues with it. Don't feel like I need a new phone anytime soon</li>
</ul>
</li>
<li>Samsung Galaxy Buds+
<ul>
<li>Reliable and good battery life despite their age, but one of the tips is starting to tear and the sound isn't that great anymore</li>
</ul>
</li>
<li>Sony DualSense controller
<ul>
<li>Gave away my PS5 but kept the controller. I like its weight and how it feels. USB-C is a big plus too</li>
</ul>
</li>
</ul>
</div>
<div class="column">
<h2>Software</h2>
<ul>
<li>Godot game engine
<ul>
<li>Switched over to this after the Unity runtime fee controversy in 2023</li>
<li>It's so enjoyable to use, I recommend it to pretty much anyone who wants to get into gamedev</li>
</ul>
</li>
<li>Blender 3D modelling suite
<ul>
<li>I'm more and more getting into 3D modelling, and Blender is really good for this</li>
</ul>
</li>
<li>Obsidian markdown editor
<ul>
<li>Switched over from Notion because I disliked having all my notes in Notion's proprietary standard and stored only in their cloud</li>
<li>Canvas is super cool for organising things in a pinboard style</li>
<li>The kanban plugin makes for a great TODO list</li>
</ul>
</li>
<li>Visual Studio Code
<ul>
<li>Great as an all-rounder code editor</li>
<li>This website is written using VS Code!</li>
</ul>
</li>
<li>Nextcloud
<ul>
<li>I self-host an instance as my personal cloud for syncing game assets and for tasks</li>
<li>I've been using tasks to organise myself a lot since 2015 or so</li>
</ul>
</li>
<li>paint.net
<ul>
<li>A simple-to-use image editor that I've been using for a very long time</li>
<li>Windows-only unfortunately</li>
</ul>
</li>
<li>Affinity image editing suite
<ul>
<li>For more sophisticated projects and for vector art, I use this instead</li>
</ul>
</li>
<li>PCSX2 PlayStation 2 emulator
<ul>
<li>Shoutout to this amazing emulator I use it to play Ratchet & Clank without needing my PS2</li>
<li>This emulator got really good in recent years and nowadays runs even difficult-to-emulate games (such as Ratchet & Clank) perfectly even on my laptop</li>
</ul>
</li>
</ul>
</div>
</div>
<p>Last updated: 2025-12-21</p>
</Content>
<style>
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.column {
margin: 0 16px;
flex-basis: 50%;
}
h2 {
font-size: 1.4rem;
}
li {
display: block;
}
li li {
font-size: 0.9rem;
margin-left: 16px;
line-height: 1.2rem;
margin-top: 0px;
margin-bottom: 0px;
}
a {
color: var(--color-text);
}
@media screen and (max-width: 800px) {
.container {
flex-direction: column;
}
.column {
margin: 0 0 16px;
}
}
</style>

View File

@@ -1,9 +1,27 @@
<script lang="ts"> <script lang="ts">
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
import { type Project, projects } from './projects'; import { type Project, games, hardware, apps, music, getStatusText, getStatusCode } from './projects';
import LinkList from "$lib/lists/link-list.svelte"; import LinkList from "$lib/lists/link-list.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import GalleryRow, { type GalleryRowEntry } from "$lib/lists/gallery-row.svelte";
const subpages: GalleryRowEntry[] = [
{
title: "Small Projects",
description: "Showing off the projects that don't get the spotlight",
img: "small/crate.webp",
altText: "A cardboard box filled with electronic components, tools, and screws. They are arranged in 3D printed Gridfinity containers.",
link: "small",
},
{
title: "Discography",
description: "Small stories about my past music",
img: "/main/hypertext.webp",
altText: "",
link: "/art/music",
},
];
</script> </script>
<svelte:head> <svelte:head>
@@ -14,34 +32,35 @@
<Banner2 <Banner2
title="My Disordered Projects" title="My Disordered Projects"
banner="/projects/banner.webp" banner="/projects/banner.webp"
bannerAlt="Closeup of the purple protagonist from Project N5" bannerAlt="An upside-down New 3DS XL lying open on a desk with a small USB-C breakout board attached to it, and a USB-C cable plugged in. The 3DS is glowing to indicate that it is charging."
subtitle="Things I have worked on" /> subtitle="Things I have worked on" />
<p>Welcome to my projects page! Here I show off all the things I have done. Projects are ordered by general topic, sorted reverse-chronologically, and have a status marker assigned that shows whether they are active or not. have fun browsing~!</p>
<p>The projects page also has two sister pages that go into detail about specific subgroups of projects:</p>
<GalleryRow entries={subpages} />
<TableOfContents /> <TableOfContents />
<h2 id="games">Games</h2> <h2 id="games">Games</h2>
{#each projects as project} {#each games as project}
{#if project.type == "game"} {@render projectSummary({ project: project })}
{@render projectSummary({ project: project })}
{/if}
{/each} {/each}
<h2 id="hardware">Hardware</h2> <h2 id="hardware">Hardware</h2>
{#each projects as project} {#each hardware as project}
{#if project.type == "hardware"} {@render projectSummary({ project: project })}
{@render projectSummary({ project: project })}
{/if}
{/each} {/each}
<h2 id="apps">Apps</h2> <h2 id="apps">Apps</h2>
{#each projects as project} {#each apps as project}
{#if project.type == "app"} {@render projectSummary({ project: project })}
{@render projectSummary({ project: project })}
{/if}
{/each} {/each}
<h2 id="music">Music</h2> <h2 id="music">Music</h2>
{#each projects as project} {#each music as project}
{#if project.type == "music"} {@render projectSummary({ project: project })}
{@render projectSummary({ project: project })}
{/if}
{/each} {/each}
</Content> </Content>
@@ -57,15 +76,16 @@
{#if project.banner} {#if project.banner}
<div class="project-banner-container"> <div class="project-banner-container">
<img class="project-banner" src="{project.banner}" alt="Overview banner for {project.title}"> <img class="project-banner" src="{project.banner}" alt="Overview banner for {project.title}">
{#if project.date}
<p class="date-marker project-date-embed">{project.date}</p>
{/if}
</div> </div>
{:else}
{#if project.date}
<p class="date-marker">{project.date}</p>
{/if}
{/if} {/if}
<p class="project-info project-status-c-{getStatusCode(project)}">
{#if project.date}
{project.date} |
{/if}
{getStatusText(project)}
</p>
{#if project.icon} {#if project.icon}
<img class="project-icon" src="{project.icon}" alt="Icon for {project.title}"> <img class="project-icon" src="{project.icon}" alt="Icon for {project.title}">
{/if} {/if}
@@ -84,21 +104,20 @@
.project-banner-container { .project-banner-container {
position: relative; position: relative;
width: fit-content; width: 100%;
margin-left: auto;
margin-right: auto;
} }
.project-banner { .project-banner {
margin: 0; /* reset left/right margins */ margin: 0; /* reset left/right margins */
width: 100%; width: 100%;
object-fit: cover;
max-height: 300px; max-height: 300px;
} }
.project-icon { .project-icon {
float: left; float: left;
margin: 16px 16px 16px 0; margin: 16px 16px 16px 0;
width: 20%; width: 19%;
} }
.project-date-embed { .project-date-embed {
@@ -106,4 +125,42 @@
left: 0; left: 0;
bottom: 0; bottom: 0;
} }
.project-info {
width: fit-content;
display: flex;
flex-direction: row;
margin-top: 16px;
background-color: color-mix(in srgb, var(--color-status) 6%, transparent);
border: var(--border-style) var(--border-dash-size) var(--color-status);
padding: 2px 8px;
backdrop-filter: blur(var(--blur-radius-background));
font-family: var(--font-mono);
font-size: 1.0rem;
font-weight: 700;
color: var(--color-status);
}
/* #region Project Status Colours */
.project-status-c-act {
--color-status: var(--color-highlight);
}
.project-status-c-ina {
--color-status: #B89751;
}
.project-status-c-aba {
--color-status: #D15555;
}
.project-status-c-fin {
--color-status: #5486D8;
}
.project-status-c-eol {
--color-status: #C353C1;
}
/* #endregion */
</style> </style>

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
</script> </script>
<svelte:head> <svelte:head>

View File

@@ -9,10 +9,11 @@
function mapEntries(entry: DevlogPostLink, index: number): GalleryEntry { function mapEntries(entry: DevlogPostLink, index: number): GalleryEntry {
return { return {
title: `${entry.post.title}`, title: `${entry.post.title}`,
subtitle: `#${posts.length - index} // ${entry.post.date}`, subtitle: `#${(posts.length - index).toString().padStart(2, '0')} // ${entry.post.date}`,
img: `/projects/projectn5/devlog/${entry.key}/preview.webp`, img: `/projects/projectn5/devlog/${entry.key}/preview.webp`,
link: `/projects/projectn5/devlog/${entry.key}/`, link: `/projects/projectn5/devlog/${entry.key}/`,
imgAlt: `Preview image for ${entry.post.title}`, imgAlt: `Preview image for ${entry.post.title}`,
description: entry.post.description,
}; };
} }
@@ -28,19 +29,20 @@
<svelte:head> <svelte:head>
<title>Project N5 | denizk0461</title> <title>Homesick | denizk0461</title>
</svelte:head> </svelte:head>
<Content> <Content>
<Banner2 <Banner2
title="Project N5" title="Homesick"
banner="/projects/projectn5/banner2.webp" /> banner="/projects/projectn5/banner2.webp"
bannerAlt="The protagonist Laura standing on a floating platform in the purple test level. Ziplines are all around her and the text 'When this text is spinning, the game is not paused' is frozen in the sky." />
<p>I am currently working on a game under the working title <b>Project N5</b>! I'm aiming for it to be an action-adventure jump-and-run game inspired by games such as Ratchet & Clank. Development started on <b>2023-09-16</b> and rebooted on <b>2025-05-16</b>.</p> <p>I am currently working on a game under the working title <b>Homesick</b> (fka Project N5)! I'm aiming for it to be an action-adventure jump-and-run game inspired by games such as Ratchet & Clank. Development started on <b>2023-09-16</b> and rebooted on <b>2025-05-16</b>.</p>
<h2 id="devlog">Development Log</h2> <h2 id="devlog">Development Log</h2>
<p>Development log entries in reverse chronological order (newest to oldest).</p> <p>Development log entries in reverse chronological order (newest to oldest).</p>
<Gallery {entries} reverseTextOrder /> <Gallery {entries} />
</Content> </Content>

View File

@@ -4,19 +4,19 @@
let builds: LinkEntry[] = [ let builds: LinkEntry[] = [
{ {
text: "2023-10-07 (Protagonist #1)", text: "2023-10-07 (Protagonist #1)",
link: "https://files.denizk0461.dev/projectn5/2023-10-07.zip", link: "https://files.natconf.dev/public/projectn5/2023-10-07.zip",
}, },
{ {
text: "2023-12-23 (Protagonist #2)", text: "2023-12-23 (Protagonist #2)",
link: "https://files.denizk0461.dev/projectn5/2023-12-23.zip", link: "https://files.natconf.dev/public/projectn5/2023-12-23.zip",
}, },
{ {
text: "2024-03-25 (Protagonist #3 with jump animations)", text: "2024-03-25 (Protagonist #3 with jump animations)",
link: "https://files.denizk0461.dev/projectn5/2024-03-25.zip", link: "https://files.natconf.dev/public/projectn5/2024-03-25.zip",
}, },
{ {
text: "2025-08-16 (Laura era) [same build as the web version]", text: "2025-08-16 (Laura era) [same build as the web version]",
link: "https://files.denizk0461.dev/projectn5/2025-08-16.zip", link: "https://files.natconf.dev/public/projectn5/2025-08-16.zip",
}, },
]; ];
</script> </script>
@@ -33,9 +33,9 @@ The good news is that I'm done with all of this! The bachelor's thesis in partic
I decided to upload some playable builds of **Project N5**! Now that the website is running on my own server instead of being hosted by GitHub or Codeberg, I have a lot more freedom here. I decided to upload some playable builds of **Project N5**! Now that the website is running on my own server instead of being hosted by GitHub or Codeberg, I have a lot more freedom here.
The game, in its state from 2025-05-16 (before the reboot), is available to play in-browser [right here!](https://apps.denizk0461.dev/projectn5) It's not a terribly great experience, though. Loading times are significantly longer and shader compilation regularly freezes the game for longer than in a locally-saved copy. Some shaders are also not functioning as intended, though this only has a minor visual impact. The game was never optimised to work on the web, after all. The game, in its state from 2025-05-16 (before the reboot), is available to play in-browser [right here!](https://apps.natconf.dev/projectn5) It's not a terribly great experience, though. Loading times are significantly longer and shader compilation regularly freezes the game for longer than in a locally-saved copy. Some shaders are also not functioning as intended, though this only has a minor visual impact. The game was never optimised to work on the web, after all.
I've also uploaded old builds of the game [here](https://files.denizk0461.dev/projectn5). You'll find the following builds, one for each protagonist: I've also uploaded old builds of the game [here](https://files.natconf.dev/public/projectn5). You'll find the following builds, one for each protagonist:
<LinkList entries={builds} /> <LinkList entries={builds} />

View File

@@ -0,0 +1,75 @@
<script lang="ts">
import SubtitledImage from "$lib/components/subtitled-image.svelte";
</script>
Been a while. Again.
<SubtitledImage
image="habitkit.webp"
altText="A screenshot of the app HabitKit zoomed in on an entry labelled 'Project Laura' and subtitled '2025 IS THE YEAR OF LAURA'. On the left half are red dots scattered, marking days of progress, whereas the right half is entirely blank."
subtitle="aaaaaaaaaaaaaa"
alignment="right" />
## What's Been Going On
Not a lot. Well actually, that's not true. I returned to Germany after a four-month abroad semester in the UK. I deep-cleaned my apartment. I switched to Linux. I worked on my website a bunch. I [learned to draw](/blog/2026/0205). But there's not been any hard progress on Project N5.
I use this habit tracking app, [HabitKit](https://www.habitkit.app/), and it (unfortunately) quite clearly displays the lack of work on the game. But this doesn't mean I've given up on the game. Maybe I'm just saying this because I'm too stubborn though.
## What I've Realised
<SubtitledImage
image="papertracker.webp"
altText="A calendar with the title 'HOMESICK Abroad Progress Calendar'. Close to half the days are marked with a cross, with no discernible pattern visible."
subtitle="proof of progress"
alignment="left"
smaller />
In and especially after my drawing challenge, I've realised something I wasn't 100% sure applied across the board for me: I struggle to get started even on the things I enjoy most. I knew before that I have a hard time starting work on the game but enjoying it once I do begin, but I found that the very same applies to drawing.
There's just something inside of me that hinders me from doing what I love.
I tried combating this when I lived in the UK; I had a physical version of the habit tracker printed out (on uni credit) that served as a looming reminder day and night. The fact I needed this to begin with is ridiculous, I gotta say. But it did help, in a way, I think? Judging by the way my progress looks on the tracker app, there was at least a small increase in productive days.
## What's There to Look Forward To
Something I was really looking forward to was [Godot 4.6](https://godotengine.org/releases/4.6/), which finally released a while back!
The change that'll probably impact me the most is the (re-)introduction of inverse kinematics! That's something I've been longing to be able to implement for quite a while. But there are more cool changes that'll have a more minor but still interesting impact, like those on tonemapping, glow, LOD generation, and also the added support for controller lights and the possibility to use the DualSense's adaptive triggers in a future update.
I've also been keeping my eyes open for resources, and I found a couple that piqued my interest; namely, two shaders, a [toon shader by Binbun](https://binbun3d.itch.io/godot-ultimate-toon-shader) that seems more customisable and a lot more visually interesting than the one I've been using so far, and [Sky3D by TokisanGames](https://github.com/TokisanGames/Sky3D) for very pretty skies.
I am also planning on potentially looking into root motion for animation, once I get to that. It feels like a larger undertaking, and I may not end up pursuing that after all, but it seems like a cool way of getting better and more fluid-feeling motion out of a character.
## What's Changing
Possibly the biggest change I can announce right now is the name of the project. I've been calling it by this name for a while, but to make it somewhat official: the game is now called ***Homesick***.
The old 'Project N5' hasn't felt right for a long time. It's a relic of a time when the game was meant to be more of a shooter, Ratchet: Gladiator-style, with a robot protagonist fighting other robots while travelling across different planets. This isn't what I had in mind for the project for a very long time now. ***Homesick*** is meant to represent Laura's feelings, Laura's struggles when she learns what has happened to the world she once knew.
I'll probably change the URL structure soon to read `/projects/homesick`, but I'll set up redirects so old URLs won't be dead ends.
## What I've Done
Even in my state of absence from the project itself, I kept it in mind I never forgot about it! Still, the actual progress I made is rather minor. I did implement metro stations back in December, which allow the player to travel between levels and even to set locations within a level. Aside from that, most other changes are pretty basic and not really worth mentioning, like tweaking parameters or simplifying code blocks.
Possibly the most significant progress I made was on starting to model Laura v3. Wait, what?
## What I'm Planning to Do
Something I started but made very little progress with is Laura's redesign. The *next* redesign. I think I learned a lot from the v2 model (or v4 model, as I had called it before), but there's more to improve mesh-wise. However, I also want to make bigger stylistic changes. I feel that a lot of what I criticised about Laura v1 still applies in some way: she just doesn't look that interesting as a character. There's so much more I can do with her, I think, and the v2 model is just iteration on the v1 design. I made a low-poly mockup back in December to dump my brain onto the 3D canvas:
<SubtitledImage
image="laura3-preview.webp"
altText="A low-poly model of a human with red hair in a ponytail wearing a black mask, dark grey shirt with long sleeves, green trousers, and white shoes."
subtitle="an idea for where laura may be headed" />
Some pretty drastic colour palette changes. Red top, brown hair, and black/white everything else is just *boring*. That's like the look I wear irl except red instead of green. I wanted to mix up things.
I also believe that my recent efforts in learning to draw gave me a better perspective at modelling human bodies. There are details I had to pay attention to that I think just aren't reflected very well in the current model. It's small things like not making her arms and legs straight as matches. Or the proportions. Or her face; I think I'll be able to improve her eyes in particular. I struggled with that on v2, but ESPECIALLY on v1. And maybe I'll do a little better at drawing textures too, who knows?
It feels weird to design Laura for a *third* time now, but I guess this would be no different in an actual game studio's production. There's no way you'll land on the perfect character on your first try, right? It's just that a game studio may do this in a week or two, and I'm much slower at this.
Something else I need to revisit is the amalgamation I built a while back to manage Laura's different movement states. I think the way I built it is somehow both completely overengineered and also insufficient for use as a foundation for Laura's movement. It works *now*, don't get me wrong, but it's so bad to maintain. I'm not even gonna show it lol
Something I also *finally* need to do is just sit down and write story bits. It's something I've just not done (enough), and the story obviously isn't gonna magically appear out of thin air. There are ideas floating around in my head and I need to capture, connect, and build upon them. It's just something I've not done much before, so I'm worried and I keep postponing it, but just like with all other hobbies of mine: *I just need to get started!*

View File

@@ -1,7 +1,7 @@
<script> <script>
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
export let data; export let data;
</script> </script>
@@ -16,7 +16,7 @@
<Banner2 <Banner2
title="{data.title}" title="{data.title}"
subtitle="Project N5 Devlog" subtitle="Homesick Devlog"
date="{data.date}" date="{data.date}"
banner="preview.webp" banner="preview.webp"
bannerAlt="{data.bannerAlt}" bannerAlt="{data.bannerAlt}"

View File

@@ -4,7 +4,7 @@ import { posts } from "../posts";
const xml = () => `<rss version="2.0"> const xml = () => `<rss version="2.0">
<channel> <channel>
<title>Project N5 Devlog</title> <title>Project N5 Devlog</title>
<link>https://denizk0461.dev/projects/projectn5/devlog/</link> <link>https://natconf.dev/projects/projectn5/devlog/</link>
<description><![CDATA[Development log for the game Project N5 by denizk0461]]></description>${getEntries()} <description><![CDATA[Development log for the game Project N5 by denizk0461]]></description>${getEntries()}
</channel> </channel>
</rss>`; </rss>`;
@@ -16,8 +16,8 @@ function getEntries(): String {
<item> <item>
<title><![CDATA[${entry.post.title}]]></title> <title><![CDATA[${entry.post.title}]]></title>
<description><![CDATA[${entry.post.description}]]></description> <description><![CDATA[${entry.post.description}]]></description>
<link>https://denizk0461.dev/projects/projectn5/devlog/${entry.key}</link> <link>https://natconf.dev/projects/projectn5/devlog/${entry.key}</link>
<guid isPermaLink="true">https://denizk0461.dev/projects/projectn5/devlog/${entry.key}</guid> <guid isPermaLink="true">https://natconf.dev/projects/projectn5/devlog/${entry.key}</guid>
<pubDate><![CDATA[${new Date(entry.post.date).toUTCString()}]]></pubDate> <pubDate><![CDATA[${new Date(entry.post.date).toUTCString()}]]></pubDate>
</item>`) </item>`)
entries.forEach(entry => { entries.forEach(entry => {

View File

@@ -11,6 +11,15 @@ export interface DevlogPostLink {
} }
export const posts: DevlogPostLink[] = [ export const posts: DevlogPostLink[] = [
{
key: "2026/0309",
post: {
title: "The Overdue Update",
date: "2026-03-09",
bannerAlt: "GDScript code zoomed in on a function called '_take_damage()' that checks whether the player has died and then reads: 'if is_dead: _die()'.",
description: "An excuse, a fresh character, and a new name.",
}
},
{ {
key: "2025/1207", key: "2025/1207",
post: { post: {

View File

@@ -1,6 +1,5 @@
export interface Project { export interface Project {
id: string; id: string;
type: string; // currently used types: game, app, hardware, music
isActive: boolean; // whether the project is currently active (true) or a past project (false) isActive: boolean; // whether the project is currently active (true) or a past project (false)
banner: string; banner: string;
icon: string; icon: string;
@@ -9,25 +8,67 @@ export interface Project {
subtitle: string; subtitle: string;
paragraphs: string[]; paragraphs: string[];
links: Link[]; links: Link[];
status: ProjectStatus;
}; };
export enum ProjectStatus {
ACTIVE,
INACTIVE,
ABANDONED,
FINISHED,
EOL, // end of life
}
export interface Link { export interface Link {
text: string; text: string;
link: string; link: string;
} }
export const projects: Project[] = [ export function getStatusText(project: Project): String {
switch (project.status) {
case ProjectStatus.ACTIVE:
return "active";
case ProjectStatus.INACTIVE:
return "inactive";
case ProjectStatus.ABANDONED:
return "abandoned";
case ProjectStatus.FINISHED:
return "finished";
case ProjectStatus.EOL:
return "end-of-life";
}
}
/**
* Returns static codes that can be used to reference same-name CSS classes
* without relying on display text.
*/
export function getStatusCode(project: Project): String {
switch (project.status) {
case ProjectStatus.ACTIVE:
return "act";
case ProjectStatus.INACTIVE:
return "ina";
case ProjectStatus.ABANDONED:
return "aba";
case ProjectStatus.FINISHED:
return "fin";
case ProjectStatus.EOL:
return "eol";
}
}
export const games: Project[] = [
{ {
id: "projectn5", id: "projectn5",
type: "game",
isActive: true, isActive: true,
banner: "/projects/projectn5/banner.webp", banner: "/projects/projectn5/banner2.webp",
icon: "", icon: "",
date: "September 2023 now", date: "September 2023 now",
title: "Project N5", title: "Homesick",
subtitle: "", subtitle: "",
paragraphs: [ paragraphs: [
"I'm currently working on a game developed using Godot, entitled Project N5! It's aiming to be an action-adventure 3D jump & run heavily inspired by games such as <a href='https://en.wikipedia.org/wiki/Ratchet_%26_Clank'>Ratchet & Clank</a>.", "I'm currently working on a game developed using Godot, entitled Homesick! It's aiming to be an action-adventure 3D jump & run heavily inspired by games such as <a href='https://en.wikipedia.org/wiki/Ratchet_%26_Clank'>Ratchet & Clank</a>.",
"I maintain a development log, feel free to check it out if you're curious! Or play some of the old builds available for download below.", "I maintain a development log, feel free to check it out if you're curious! Or play some of the old builds available for download below.",
], ],
links: [ links: [
@@ -36,18 +77,18 @@ export const projects: Project[] = [
link: "/projects/projectn5", link: "/projects/projectn5",
}, },
{ {
text: "Play an <b>old build</b> (developed until 2025-05-16)", text: "Play an <b>old web build</b> (developed until 2025-05-16)",
link: "//apps.denizk0461.dev/projectn5", link: "https://apps.natconf.dev/projectn5",
}, },
{ {
text: "Download the <b>old Windows builds</b>", text: "Download the <b>old Windows builds</b>",
link: "//files.denizk0461.dev/projectn5", link: "https://files.natconf.dev/public/projectn5",
}, },
], ],
status: ProjectStatus.ACTIVE,
}, },
{ {
id: "magician", id: "magician",
type: "game",
isActive: false, isActive: false,
banner: "/projects/magician/banner.webp", banner: "/projects/magician/banner.webp",
icon: "", icon: "",
@@ -61,13 +102,13 @@ export const projects: Project[] = [
links: [ links: [
{ {
text: "View the latest <b>Magician</b> build", text: "View the latest <b>Magician</b> build",
link: "//apps.denizk0461.dev/magician", link: "https://apps.natconf.dev/magician",
}, },
], ],
status: ProjectStatus.ABANDONED,
}, },
{ {
id: "projektike", id: "projektike",
type: "game",
isActive: false, isActive: false,
banner: "/projects/projektike/banner.webp", banner: "/projects/projektike/banner.webp",
icon: "", icon: "",
@@ -80,10 +121,10 @@ export const projects: Project[] = [
], ],
links: [ links: [
], ],
status: ProjectStatus.ABANDONED,
}, },
{ {
id: "swordsnstuff", id: "swordsnstuff",
type: "game",
isActive: false, isActive: false,
banner: "/projects/swordsnstuff/banner.webp", banner: "/projects/swordsnstuff/banner.webp",
icon: "", icon: "",
@@ -98,13 +139,13 @@ export const projects: Project[] = [
links: [ links: [
{ {
text: "Play <b>Swords & Stuff</b>", text: "Play <b>Swords & Stuff</b>",
link: "//apps.denizk0461.dev/swordsnstuff", link: "https://apps.natconf.dev/swordsnstuff",
}, },
], ],
status: ProjectStatus.ABANDONED,
}, },
{ {
id: "tads", id: "tads",
type: "game",
isActive: false, isActive: false,
banner: "/projects/tads/banner.webp", banner: "/projects/tads/banner.webp",
icon: "/projects/tads/icon.webp", icon: "/projects/tads/icon.webp",
@@ -118,17 +159,20 @@ export const projects: Project[] = [
links: [ links: [
{ {
text: "Play <b>TADS 1</b>", text: "Play <b>TADS 1</b>",
link: "//apps.denizk0461.dev/tads/1", link: "https://apps.natconf.dev/tads/1",
}, },
{ {
text: "Play <b>TADS 2</b>", text: "Play <b>TADS 2</b>",
link: "//apps.denizk0461.dev/tads/2", link: "https://apps.natconf.dev/tads/2",
}, },
], ],
status: ProjectStatus.FINISHED,
}, },
];
export const hardware: Project[] = [
{ {
id: "daisyfm", id: "daisyfm",
type: "hardware",
isActive: false, isActive: false,
banner: "/projects/daisyfm/banner.webp", banner: "/projects/daisyfm/banner.webp",
icon: "", icon: "",
@@ -145,17 +189,20 @@ export const projects: Project[] = [
}, },
{ {
text: "Get the <b>PCB and STL files</b>", text: "Get the <b>PCB and STL files</b>",
link: "//files.denizk0461.dev/daisyfm/", link: "https://files.natconf.dev/public/daisyfm/",
}, },
{ {
text: "View the code files on <b>Codeberg</b>", text: "View the code files on <b>Codeberg</b>",
link: "https://codeberg.org/denizk0461/daisy-fm-synth", link: "https://codeberg.org/denizk0461/daisy-fm-synth",
}, },
], ],
status: ProjectStatus.FINISHED,
}, },
];
export const apps: Project[] = [
{ {
id: "weserplaner", id: "weserplaner",
type: "app",
isActive: false, isActive: false,
banner: "/projects/weserplaner/banner.webp", banner: "/projects/weserplaner/banner.webp",
icon: "/projects/weserplaner/icon.webp", icon: "/projects/weserplaner/icon.webp",
@@ -177,10 +224,10 @@ export const projects: Project[] = [
link: "https://play.google.com/store/apps/details?id=com.denizk0461.weserplaner", link: "https://play.google.com/store/apps/details?id=com.denizk0461.weserplaner",
}, },
], ],
status: ProjectStatus.EOL,
}, },
{ {
id: "textbasic", id: "textbasic",
type: "app",
isActive: false, isActive: false,
banner: "", banner: "",
icon: "/projects/textbasic/icon.webp", icon: "/projects/textbasic/icon.webp",
@@ -201,10 +248,10 @@ export const projects: Project[] = [
link: "https://play.google.com/store/apps/details?id=com.denizk0461.textbasic", link: "https://play.google.com/store/apps/details?id=com.denizk0461.textbasic",
}, },
], ],
status: ProjectStatus.EOL,
}, },
{ {
id: "qwark", id: "qwark",
type: "app",
isActive: false, isActive: false,
banner: "", banner: "",
icon: "/projects/qwark/icon.webp", icon: "/projects/qwark/icon.webp",
@@ -222,10 +269,10 @@ export const projects: Project[] = [
link: "https://github.com/denizk0461/qwark", link: "https://github.com/denizk0461/qwark",
}, },
], ],
status: ProjectStatus.EOL,
}, },
{ {
id: "avhplan", id: "avhplan",
type: "app",
isActive: false, isActive: false,
banner: "", banner: "",
date: "April 2019 March 2020", date: "April 2019 March 2020",
@@ -248,10 +295,13 @@ export const projects: Project[] = [
link: "https://github.com/denizk0461/avh-plan-ios", link: "https://github.com/denizk0461/avh-plan-ios",
}, },
], ],
status: ProjectStatus.EOL,
}, },
];
export const music: Project[] = [
{ {
id: "dreamworld", id: "dreamworld",
type: "music",
isActive: false, isActive: false,
banner: "/projects/dreamworld/banner.webp", banner: "/projects/dreamworld/banner.webp",
icon: "/projects/dreamworld/icon.webp", icon: "/projects/dreamworld/icon.webp",
@@ -267,13 +317,13 @@ export const projects: Project[] = [
links: [ links: [
{ {
text: "Listen & download on my <b>copyparty</b> instance", text: "Listen & download on my <b>copyparty</b> instance",
link: "https://files.denizk0461.dev/my_tracks/Dreamworld/", link: "https://files.natconf.dev/public/my_tracks/Dreamworld/",
}, },
], ],
status: ProjectStatus.FINISHED,
}, },
{ {
id: "anewbeginning", id: "anewbeginning",
type: "music",
isActive: false, isActive: false,
banner: "", banner: "",
icon: "/projects/anewbeginning/icon.webp", icon: "/projects/anewbeginning/icon.webp",
@@ -287,13 +337,13 @@ export const projects: Project[] = [
links: [ links: [
{ {
text: "Listen & download on my <b>copyparty</b> instance", text: "Listen & download on my <b>copyparty</b> instance",
link: "https://files.denizk0461.dev/my_tracks/A%20New%20Beginning/", link: "https://files.natconf.dev/public/my_tracks/A%20New%20Beginning/",
}, },
], ],
status: ProjectStatus.FINISHED,
}, },
{ {
id: "soundcloud", id: "soundcloud",
type: "music",
isActive: false, isActive: false,
banner: "", banner: "",
icon: "/projects/soundcloud/icon.webp", icon: "/projects/soundcloud/icon.webp",
@@ -313,5 +363,6 @@ export const projects: Project[] = [
link: "https://soundcloud.com/djd4rkn355", link: "https://soundcloud.com/djd4rkn355",
}, },
], ],
status: ProjectStatus.INACTIVE,
}, },
]; ];

View File

@@ -0,0 +1,109 @@
<script>
import Banner2 from "$lib/banner2.svelte";
import SubtitledImage from "$lib/components/subtitled-image.svelte";
import TableOfContents from "$lib/components/table-of-contents.svelte";
import Content from "$lib/viewport/content.svelte";
</script>
<svelte:head>
<title>Small Projects | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="My Small Projects"
subtitle="the ones that don't get the spotlight"
banner="crate.webp"
bannerAlt="A cardboard box filled with electronic components, tools, and screws. They are arranged in 3D printed Gridfinity containers." />
<p>Not all of my projects are big, month-long endeavours. Some of them are short and sweet. Sometimes, they're even more rewarding than the bigger ones, because you end up with a finished 'thing' much quicker! And because I like my small projects just as much as my bigger ones, I figured it would be nice to give them a space on my website as well.</p>
<p>There's more to come here! This page is very new and I will add things here gradually.</p>
<TableOfContents />
<h2>3DS USB-C mod</h2>
<p class="subtitle">DIY charging port mod</p>
<p class="subtitle">October 2024</p>
<SubtitledImage
image="3ds-usb-c/showcase.mp4"
subtitle="it charges via USB-C! also do you like my A Hat in Time theme?"
video />
<p>I modded my New 3DS XL (SNES Edition) to give it a USB-C port to charge!</p>
<SubtitledImage
image="3ds-usb-c/finished.webp"
altText="A back view at a New Nintendo 3DS XL with a USB-C port added between the charging port and the right shoulder buttons."
subtitle="the USB-C port in all its glory"
alignment="right" />
<p>I used a small USB-C breakout I had lying around that is wired straight into the charging pads of the original charging port, which is left completely intact. The breakout board also has a 5.1kΩ resistor between ground and one of the CC pins (which I had to manually find because it's unlabelled) to allow for using C-to-C cables.</p>
<SubtitledImage
image="3ds-usb-c/hole.webp"
altText="At the top is a view at a USB-C-shaped hole cut into the back half of a New 3DS XL. At the bottom is a look at the same hole from the inside of the case. There are rough cutouts where the stylus slides in."
subtitle="a closer look at the holes I cut, and how they affect the stylus slot"
alignment="left" />
<p>What I wrecked in turn was the wrist strap loop, which I completely cut out to create the hole for the port. The stylus port also got cut down to make space, but my stylus is kind of broken and doesn't stay put when I put it into the system, so I didn't really care about that.</p>
<p>It works well! The hole isn't the prettiest but it was pretty simple to pull off, and extremely cheap as well. In turn I got a 3DS that I can charge using any USB-C cable and I no longer need to lug around the proprietary 3DS charger!</p>
<h2>deej0461</h2>
<p class="subtitle">PC companion audio source controller</p>
<p class="subtitle">August 2024</p>
<SubtitledImage
image="deej0461/finished.webp"
altText="A golden 3D printed shell with a slider on its left, two LEDs recessed, and four black buttons on its right. The buttons have symbols of speakers, monitors, and headphones printed on them. Three screws at the top are visible. A USB-C cable is plugged into the back of it."
subtitle="a handful of device for controlling a handful of other devices" />
<p>This little device was inspired by one a friend of mine built his own version of: a <a href="https://github.com/omriharel/deej">deej</a> volume slider panel. This thing allows you to control different applications with individual, <i>physical</i>, sliders. Super cool thing.</p>
<SubtitledImage
image="deej0461/printing.webp"
altText="A Bambu Lab A1 mini 3D printer in the middle of printing casing parts using a golden filament. The printer head has two googly eyes attached."
subtitle="googly-eyed printer hard at work"
alignment="left" />
<p>Except I didn't need all these sliders, really. A single slider would be cool, I thought. You know what I really wanted? Buttons to control the audio <i>source</i>, because I switch between speakers and headphones constantly, and that's at least 3 clicks every time I want to switch. So I built a device based on deej, but with some expansions.</p>
<p>I only used few components: a HID-enabled Arduino-compatible Pro Micro with USB-C controls the whole thing. Hooked up to it are four Cherry switches and a Soldering slider I had lying around from my <a href="/projects/daisy">Daisy project</a>, and I added two LEDs for good measure. It's all packaged into a 3D-printed enclosure I designed myself. The slider is screwed in tightly, and so is the top of the case; the key switches are clipped in from the top so they don't fall out; the Arduino and the LEDs are just hot-glued in. For extra flair, the four output buttons are marked with symbols for my outputs: two monitors, a pair of loudspeakers, and a pair of headphones. In the final device, they're arranged so that my two most frequently-used buttons are at the bottom for easier reach.</p>
<p>Software-wise, I set this up with the original deej software to control main volume. For the audio, I used a program called <a href="https://soundswitch.aaflalo.me/">SoundSwitch</a>. The program listened to key presses for the <code>F21-F24</code> keys, which the Arduino triggers when the output keys are pressed. The red LED lights up when a key is pressed; the white LED has no assigned function. This worked pretty well, but this is no longer the setup I use, since I switched to Fedora Linux, as I needed to adapt/change the software for the new OS!</p>
<SubtitledImage
image="deej0461/soldering.webp"
altText="An Arduino set into a 3D printed case with a slider, two LEDs, and four key switches soldered to it using wires. The components are spread out and hanging out the top of the case."
subtitle="no PCB? no problem"
alignment="right" />
<p>When pressing a keyboard's volume button, Windows raises or lowers volume in increments of 2. Fedora does 5. I found this much handier, so I stopped reaching for the slider and just defaulted to using my keyboard. This meant I didn't bother setting up the slider in Fedora. The buttons work, though, but they needed some adjustment. I think (and I might be wrong??) that Linux doesn't support function keys past F12, so I changed the Arduino script so the buttons trigger <code>Shift + F9-F12</code>. Instead of a separate program (which kept asking to be updated...), I now use KDE's built-in Shortcuts that trigger a script. The script is one line: <code>pactl set-default-sink [sink-name]</code>. The sink name is hard-coded into the file because, as extensive testing proved, Shortcuts does not allow arguments when entering a command. I currently only have two files set up: one for the primary monitor, one for the headphones.</p>
<p>I much prefer the setup now because it doesn't rely on third-party software anymore.</p>
<p>This thing is, no exaggeration, one of the handiest things I have ever built, because I use it quite literally <i><b>every single day</b></i>. I often switch between my monitor's speakers and my headphones, and being able to do that with the press of a single button is <i>unbelievably</i> handy. I don't even think about it anymore, I just reach for the buttons whenever I switch. It's a part of my routine now and I wouldn't want to miss it.</p>
</Content>
<style>
.subtitle {
font-family: var(--font-mono);
margin: 0;
font-size: 1.0rem;
line-height: 1.4rem;
font-style: italic;
font-weight: 700;
color: var(--color-highlight-alt);
}
.subtitle::before {
content: '<!-- ';
}
.subtitle::after {
content: ' -->';
}
</style>

View File

@@ -1,41 +0,0 @@
<script>
import SubtitledImage from "$lib/components/subtitled-image.svelte";
import Content from "$lib/viewport/content.svelte";
</script>
<Content>
<p>this is a test page. please disregard. or not i'm not your boss</p>
<SubtitledImage
image="/meta/about/taskbar.webp"
altText="taskbar"
subtitle="My taskbar with a little Clank backback on the left side because it's very cute. very cute. very very very cute indeed. very much indeed so. sample text. lorem ipsum. this text needs to break. how long can i make this text be? i need to write a lot to see how this text box handles very long text and if this actually looks good. let's see hmm what can I think of? nothing really. PUSH UR T3MPRR"
/>
<SubtitledImage
image="/projects/projectn5/devlog/2025/0427/laura-v4-full.webp"
altText="taskbar"
subtitle="old as fuck laura. very tall. very very very tall indeed. very much indeed so. sample text. lorem ipsum. PUSH UR T3MPRR"
alignment="left"
/>
<p>test text to see whether this aligmne tactually works afdsdfasjd iofjaopsid iofjasiop[d iofajiope juiorpfjah sidfokljasolkdjf ioajsu0oid kfjpzxj niujkhjozx jcio gjzoxij cviozjhxioc jvzxjc asdjfoasd iozxoic uoizxcu hoiwe oijfio aswjiofjo sajdj asd hnnhnhnhan han n nhnhnhnhnnhnh nhnh nggnhngh ng nhng nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdftest text to see whether this aligmne tactually works afdsdfasjd iofjaopsid iofjasiop[d iofajiope juiorpfjah sidfokljasolkdjf ioajsu0oid kfjpzxj niujkhjozx jcio gjzoxij cviozjhxioc jvzxjc asdjfoasd iozxoic uoizxcu hoiwe oijfio aswjiofjo sajdj asd hnnhnhnhan han n nhnhnhnhnnhnh nhnh nggnhngh ng nhng nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdftest text to see whether this aligmne tactually works nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdftest text to see whether this aligmne tactually works afdsdfasjd if asdf</p>
<SubtitledImage
image="/meta/about/taskbar.webp"
altText="taskbar"
subtitle="My taskbar with a little Clank backback on the left side because it's very cute. very cute. very very very cute indeed. very much indeed so. sample text. lorem ipsum. this text needs to break. how long can i make this text be? i need to write a lot to see how this text box handles very long text and if this actually looks good. let's see hmm what can I think of? nothing really. PUSH UR T3MPRR"
alignment="right"
/>
<p>test text to see whether this aligmne tactually works afdsdfasjd iofjaopsid iofjasiop[d iofajiope juiorpfjah sidfokljasolkdjf ioajsu0oid kfjpzxj niujkhjozx jcio gjzoxij cviozjhxioc jvzxjc asdjfoasd iozxoic uoizxcu hoiwe oijfio aswjiofjo sajdj asd hnnhnhnhan han n nhnhnhnhnnhnh nhnh nggnhngh ng nhng nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdftest text to see whether this aligmne tactually works afdsdfasjd iofjaopsid iofjasiop[d iofajiope juiorpfjah sidfokljasolkdjf ioajsu0oid kfjpzxj niujkhjozx jcio gjzoxij cviozjhxioc jvzxjc asdjfoasd iozxoic uoizxcu hoiwe oijfio aswjiofjo sajdj asd hnnhnhnhan han n nhnhnhnhnnhnh nhnh nggnhngh ng nhng nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdftest text to see whether this aligmne tactually works afdsdfasjd iofjaopsid iofjasiop[d iofajiope juiorpfjah sidfokljasolkdjf ioajsu0oid kfjpzxj niujkhjozx jcio gjzoxij cviozjhxioc jvzxjc asdjfoasd iozxoic uoizxcu hoiwe oijfio aswjiofjo sajdj asd hnnhnhnhan han n nhnhnhnhnnhnh nhnh nggnhngh ng nhng nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdftest text to see whether this aligmne tactually works afdsdfasjd iofjaopsid iofjasiop[d iofajiope juiorpfjah sidfokljasolkdjf ioajsu0oid kfjpzxj niujkhjozx jcio gjzoxij cviozjhxioc jvzxjc asdjfoasd iozxoic uoizxcu hoiwe oijfio aswjiofjo sajdj asd hnnhnhnhan han n nhnhnhnhnnhnh nhnh nggnhngh ng nhng nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdftest text to see whether this aligmne tactually works afdsdfasjd iofjaopsid iofjasiop[d iofajiope juiorpfjah sidfokljasolkdjf ioajsu0oid kfjpzxj niujkhjozx jcio gjzoxij cviozjhxioc jvzxjc asdjfoasd iozxoic uoizxcu hoiwe oijfio aswjiofjo sajdj asd hnnhnhnhan han n nhnhnhnhnnhnh nhnh nggnhngh ng nhng nhng nh na asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf</p>
<SubtitledImage
image="/meta/about/taskbar.webp"
altText="taskbar"
alignment="right"
/>
<SubtitledImage
image="/meta/about/taskbar.webp"
altText="taskbar"
/>
</Content>

3
static/ai.txt Normal file
View File

@@ -0,0 +1,3 @@
User-Agent: *
Disallow: /
Disallow: *

BIN
static/art/banner.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 446 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 698 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Some files were not shown because too many files have changed in this diff Show More