Compare commits

...

9 Commits

28 changed files with 549 additions and 290 deletions

View File

@@ -1,57 +1,43 @@
<script lang="ts">
import { type BannerContent } from './components/banner-content';
let {
title,
date = "", // date posted
dateUpdated = "",
dateIndeterminate = "", // raw date without an explanation marker next to it
subtitle = "",
banner = "",
bannerAlt = "",
tags = [],
pixelated,
content,
}: {
title: string;
date?: string;
dateUpdated?: string;
dateIndeterminate?: string;
subtitle?: string;
banner?: string;
bannerAlt?: string;
tags?: string[];
pixelated?: boolean;
content: BannerContent;
} = $props();
</script>
{#snippet titles({title, subtitle, date}: {title: string, subtitle: string, date: string})}
{#snippet titles()}
<div class="title-container">
<div class="title-text-container">
<h1 class="title">{title}</h1>
<h1 class="title">{content.title}</h1>
{#if subtitle}
<p class="subtitle">[ {subtitle} ]</p>
{#if content.subtitle}
<p class="subtitle">[ {content.subtitle} ]</p>
{/if}
{#if tags.length}
{#if content.tags && content.tags.length > 0}
<div class="tag-container">
{#each tags as tag}
{#each content.tags as tag}
<span class="post-tag">{tag}</span>
{/each}
</div>
{/if}
</div>
{#if date || dateUpdated || dateIndeterminate}
{#if content.date || content.dateUpdated || content.dateIndeterminate}
<div class="date-container">
{#if dateIndeterminate}
<p class="date">:: {dateIndeterminate}</p>
{#if content.dateIndeterminate && content.dateIndeterminate != "undefined"}
<p class="date">:: {content.dateIndeterminate}</p>
{/if}
{#if date}
<p class="date">posted :: {date}</p>
{#if content.date && content.date != "undefined"}
<p class="date">posted :: {content.date}</p>
{/if}
{#if dateUpdated}
<p class="date">last updated :: {dateUpdated}</p>
{#if content.dateUpdated && content.dateUpdated != "undefined"}
<p class="date">last updated :: {content.dateUpdated}</p>
{/if}
</div>
{/if}
@@ -59,13 +45,13 @@
{/snippet}
<div class="container">
{#if banner && banner !== ""}
<a class="banner-container" href={banner}>
<img class="banner {pixelated ? "pixelated-img" : ""}" src={banner} alt={bannerAlt}>
{#if content.banner && content.banner !== ""}
<a class="banner-container" href={content.banner}>
<img class="banner {content.pixelated ? "pixelated-img" : ""}" src={content.banner} alt={content.bannerAlt}>
</a>
{/if}
{@render titles({title, subtitle, date})}
{@render titles()}
<hr>
</div>

View File

@@ -0,0 +1,11 @@
export interface BannerContent {
title: string;
date?: string; // date posted
dateUpdated?: string;
dateIndeterminate?: string; // raw date without an explanation marker next to it
subtitle?: string;
banner?: string;
bannerAlt?: string;
tags?: string[];
pixelated?: boolean;
}

View File

@@ -1,5 +1,12 @@
<script lang="ts">
import {onMount} from 'svelte';
import { onMount } from 'svelte';
let {
type,
}: {
// possible values: none, 'side'
type: string;
} = $props();
interface TocEntry {
text: string;
@@ -63,7 +70,9 @@
{/snippet}
{#if tocEntries.length > 0}
<div class="toc-container blurred-background">
<div class="{type ? "toc-container-side" : "toc-container"} blurred-background">
<p class="toc-header">on this page</p>
<ul class="toc-list">
{#each tocEntries as entry}
{@render tocEntryLine({ entry })}
@@ -74,21 +83,39 @@
<style>
:global {
body {
--padding-indent-base: 44px;
--padding-level-indent: 24px;
.toc-container, .toc-container-side {
box-sizing: border-box;
padding: 16px 0;
border-radius: var(--border-radius);
}
.toc-container {
--padding-indent-base: 44px;
--padding-level-indent: 24px;
max-width: var(--width-toc);
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);
border-radius: var(--border-radius);
background-color: var(--color-background-highlight);
}
.toc-container-side {
--padding-indent-base: 20px;
--padding-level-indent: var(--padding-indent-base);
/* width: 300px; */
margin-left: 12px;
margin-right: 12px;
position: sticky;
top: 64px;
border-left: var(--border-style) var(--border-dash-size) var(--color-highlight);
}
.toc-container-side .toc-list a {
border-top-right-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);
}
.toc-list {
@@ -97,6 +124,14 @@
width: 100%;
}
.toc-header {
margin: 0 var(--padding-indent-base);
font-weight: 700;
font-style: italic;
color: var(--color-highlight);
font-family: var(--font-mono);
}
.toc-list a {
width: 100%;
font-size: 1.0rem;

View File

@@ -1,33 +1,78 @@
<div class="content">
<div class="side">
<slot name="side-left" />
<script lang="ts">
import Banner2 from "$lib/banner2.svelte";
import type { BannerContent } from "$lib/components/banner-content";
import ScrollTopButton from "$lib/components/scroll-top-button.svelte";
import TableOfContents from "$lib/components/table-of-contents.svelte";
import type { Snippet } from "svelte";
let {
children,
bannerContent,
}: {
children: Snippet,
bannerContent: BannerContent;
} = $props();
</script>
<div class="container">
<Banner2 content={bannerContent}/>
<div class="content">
<div class="content-sidebar-main-container">
{@render children()}
<ScrollTopButton />
</div>
<div class="side">
<TableOfContents type="side" />
</div>
<div class="main">
<slot name="main" />
</div>
</div>
<style>
.content {
max-width: 2000px;
margin: 0 auto;
display: flex;
flex-direction: row;
padding: 0 24px;
/* not elegant at all but it works */
:global {
.content-sidebar-main-container > *:nth-child(1) {
margin-top: 0 !important;
}
}
.container {
max-width: var(--page-width);
margin: 0 auto;
padding: 0 24px;
box-sizing: border-box;
}
.content {
max-width: var(--page-width);
width: 100%;
display: grid;
grid-template-columns: auto 300px;
}
.content-sidebar-main-container {
width: 100%;
}
.side {
min-width: 400px;
width: 100%;
margin-top: 32px;
margin-bottom: 8px;
}
@media screen and (max-width: 800px) {
.content {
padding: 0 8px;
flex-direction: column;
width: 100%;
grid-template-rows: auto auto;
grid-template-columns: 1fr;
}
.side {
min-width: 0;
max-width: 100%;
margin-top: 8px;
width: 100%;
order: -1;
}
}
</style>

View File

@@ -1,10 +1,23 @@
<script lang="ts">
import Banner2 from "$lib/banner2.svelte";
import type { BannerContent } from "$lib/components/banner-content";
import ScrollTopButton from "$lib/components/scroll-top-button.svelte";
import type { Snippet } from "svelte";
let { children } = $props();
let {
children,
bannerContent,
}: {
children: Snippet,
bannerContent?: BannerContent;
} = $props();
</script>
<div class="main-content">
{#if bannerContent}
<Banner2 content={bannerContent} />
{/if}
<ScrollTopButton />
{@render children()}
</div>

View File

@@ -323,15 +323,6 @@
font-family: var(--font-lightyears);
}
.horizontally-centre-aligned {
width: var(--media-width);
display: flex;
justify-content: center;
align-items: center;
margin-left: auto;
margin-right: auto;
}
.inline-img-left {
float: left;
max-width: 24%;

View File

@@ -7,12 +7,12 @@
<title>My Tracks | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="My Tracks"
subtitle=""
banner=""
bannerAlt="" />
<Content bannerContent={{
title: "My Tracks",
subtitle: "",
banner: "",
bannerAlt: "",
}}>
well this is awkward. there's nothing here yet. come back later?

View File

@@ -24,11 +24,11 @@
<title>Blog | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Blog"
banner="robert.webp"
bannerAlt="View at a tram bridge rising and then curving to the left." />
<Content bannerContent={{
title: "Blog",
banner: "robert.webp",
bannerAlt: "View at a tram bridge rising and then curving to the left.",
}}>
<!-- TODO descriptions on filter click -->
<div class="tag-filters-alt">

View File

@@ -1,7 +1,5 @@
<script>
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/components/table-of-contents.svelte";
import ContentSidebar from "$lib/viewport/content-sidebar.svelte";
export let data;
</script>
@@ -12,18 +10,16 @@
<meta name="DCTERMS.created" content="{data.date}T{data.time}">
</svelte:head>
<Content>
<Banner2
title="{data.title}"
subtitle="{data.subtitle}"
date="{data.date}"
dateUpdated="{data.dateUpdated}"
banner="{data.banner}"
bannerAlt="Banner for blog post '{data.title}'"
tags={data.tags} />
<TableOfContents />
<ContentSidebar bannerContent={{
title: data.title,
subtitle: data.subtitle,
date: data.date,
dateUpdated: data.dateUpdated,
banner: data.banner,
bannerAlt: `Banner for blog post '${data.title}'`,
tags: data.tags,
}}>
<svelte:component this={data.content} />
</Content>
</ContentSidebar>

View File

@@ -12,13 +12,12 @@
<title>Drawing Gallery | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Drawing Gallery"
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."
subtitle="???"
/>
<Content bannerContent={{
title: "Drawing Gallery",
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.",
subtitle: "sketches & stuff",
}}>
<div class="selected-container">
<a class="selected-img-link" href={drawingsRev[selectedIndex].src}>
@@ -62,20 +61,32 @@
}
.selected-img-link {
margin: 0;
width: fit-content;
height: 400px;
margin: 0 auto;
overflow: hidden;
}
.selected-img-link:hover .selected-img {
scale: 1.06;
}
.selected-img {
object-fit: contain;
width: 100%;
height: 400px;
height: 100%;
max-height: initial;
scale: 1.0;
transition: scale var(--duration-animation) var(--anim-curve);
}
.selected-text-container {
display: flex;
flex-direction: column;
gap: 8px;
overflow: scroll;
padding-right: 12px;
max-height: var(--media-height);
}
.selected-text-header p {
@@ -106,21 +117,18 @@
width: 100%;
overflow: hidden;
border-radius: var(--border-radius);
filter: brightness(70%) saturate(60%);
/* filter: brightness(70%) saturate(60%); */
outline: var(--border-style) var(--border-dash-size) transparent;
transition: filter var(--duration-animation) var(--anim-curve),
outline-color var(--duration-animation) var(--anim-curve);
}
.img-button:hover {
filter: brightness(100%) saturate(100%);
outline-color: var(--color-highlight);
transition: outline-color var(--duration-animation) var(--anim-curve);
}
.img-button img {
width: 100%;
height: 200px;
object-fit: cover;
transition: scale var(--duration-animation) var(--anim-curve);
filter: brightness(100%) saturate(80%);
transition: scale var(--duration-animation) var(--anim-curve),
filter var(--duration-animation) var(--anim-curve);
}
.img-button:hover img {
scale: 1.12;
@@ -128,4 +136,16 @@
.img-button:active img {
scale: 1.08;
}
.img-button-container:hover img {
filter: brightness(70%) saturate(60%);
}
.img-button:hover {
outline-color: var(--color-highlight);
}
.img-button:hover img {
filter: brightness(100%) saturate(100%);
}
</style>

View File

@@ -1,8 +1,6 @@
<script lang="ts">
import Content from "$lib/viewport/content.svelte";
import Banner2 from "$lib/banner2.svelte";
import TableOfContents from "$lib/components/table-of-contents.svelte";
import ImageRow from "$lib/media/image-row.svelte";
import ContentSidebar from "$lib/viewport/content-sidebar.svelte";
export let data;
</script>
@@ -31,20 +29,17 @@
</div>
{/snippet}
<Content>
<Banner2
title="Creative Feed"
banner="banner.webp"
bannerAlt="A blue screen with the text 'how do you do art ? 1. face your fears 2. become your heroes'. The 'art' looks to have been edited in. The music artist Porter Robinson is standing in the bottom right corner."
subtitle="minor things I have worked on"
/>
<ContentSidebar bannerContent={{
title: "Creative Feed",
banner: "banner.webp",
bannerAlt: "A blue screen with the text 'how do you do art ? 1. face your fears 2. become your heroes'. The 'art' looks to have been edited in. The music artist Porter Robinson is standing in the bottom right corner.",
subtitle: "minor things I have worked on",
}}>
<p>Welcome to my creative feed! It is heavily inspired by <a href="https://deathsurplus.com/">DeathSurplus' art blog</a> definitely go check out his website!</p>
<p>This page is intended to be a contrasting companion to the <a href="/projects"><code>projects</code> page</a>; I'll use this page for smaller things that don't fit the dedicated-page-format.</p>
<!-- <TableOfContents /> -->
{@render pageButtons(data.currentPage)}
{#each data.feedPosts as post}
@@ -62,7 +57,7 @@
{@render pageButtons(data.currentPage)}
</Content>
</ContentSidebar>
<style>
.page-button-container {

View File

@@ -1,8 +1,6 @@
<script lang="ts">
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/components/table-of-contents.svelte";
import LinkList, { type LinkEntry } from "$lib/lists/link-list.svelte";
import ContentSidebar from "$lib/viewport/content-sidebar.svelte";
let favouriteAlbums: LinkEntry[] = [
{
@@ -108,17 +106,15 @@
</svelte:head>
<Content>
<Banner2
title="About Me & natconf.dev"
banner="/me.webp"
bannerAlt="Mirror picture of me, pixelated beyond recognition"
subtitle="If you'd like to learn more about me and my website"
date="2025-08-10"
dateUpdated="2026-04-03"
pixelated />
<TableOfContents />
<ContentSidebar bannerContent={{
title: "About Me & natconf.dev",
banner: "/me.webp",
bannerAlt: "Mirror picture of me, pixelated beyond recognition",
subtitle: "If you'd like to learn more about me and my website",
date: "2025-08-10",
dateUpdated: "2026-04-03",
pixelated: true,
}}>
<p>Hi there! I'm Deniz (they/them). Welcome to my website!</p>
@@ -199,7 +195,7 @@
<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>
</Content>
</ContentSidebar>
<style>
.faq-question {

View File

@@ -19,10 +19,10 @@
<title>Feeds | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Feeds"
subtitle="XML feeds" />
<Content bannerContent={{
title: "Feeds",
subtitle: "XML feeds",
}}>
<p>This is a list of RSS feeds I maintain on this website. You can subscribe to them by adding the link of any feed to an RSS reader of your liking.</p>

View File

@@ -8,11 +8,10 @@
<title>Music Rotation | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Music Rotation"
dateUpdated="2026-04-14"
/>
<Content bannerContent={{
title: "Music Rotation",
dateUpdated: "2026-04-14",
}}>
<p>content coming soon.</p>

View File

@@ -7,11 +7,10 @@
<title>Now | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Now"
dateUpdated="2026-04-14"
/>
<Content bannerContent={{
title: "Now",
dateUpdated: "2026-04-14",
}}>
<p>content coming soon.</p>

View File

@@ -7,11 +7,10 @@
<title>Privacy & Cookies | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Information on Privacy & Cookies"
dateUpdated="2025-09-10"
/>
<Content bannerContent={{
title: "Information on Privacy & Cookies",
dateUpdated: "2025-09-10",
}}>
<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>

View File

@@ -31,16 +31,15 @@
<title>Projects | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="My Disordered Projects"
banner="/projects/banner.webp"
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" />
<Content bannerContent={{
title: "My Disordered Projects",
banner: "banner.webp",
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",
}}>
<p>Welcome to my 💫new💫 projects page! Here I show off all the things I have done. Projects are ordered reverse-chronologically and have some other neat information displayed. have fun browsing~!</p>
<!-- TODO it would be nice if these were green here to separate them from the red tags on the blog page -->
<div class="tag-filters">
<p class="tag-filter-header"># filter projects by category:</p>
<div class="tag-filter-container">
@@ -123,14 +122,14 @@
width: 100%;
height: 100%;
z-index: -1;
filter: brightness(40%) saturate(40%) blur(1px);
filter: brightness(40%) saturate(40%);
transition: filter var(--duration-animation) var(--anim-curve),
scale var(--duration-animation) var(--anim-curve);
scale: 1.05;
}
.project-wrapper:hover .project-banner {
filter: brightness(60%) saturate(100%) blur(0);
filter: brightness(60%) saturate(100%);
scale: 1.0;
}

View File

@@ -1,7 +1,5 @@
<script>
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
// import TableOfContents from "$lib/components/table-of-contents.svelte";
import ContentSidebar from "$lib/viewport/content-sidebar.svelte";
export let data;
</script>
@@ -12,17 +10,14 @@
<meta name="DCTERMS.created" content="{data.projectDetails.date}T12:00">
</svelte:head>
<Content>
<Banner2
title="{data.projectDetails.title}"
subtitle="{data.projectDetails.subtitle}"
dateIndeterminate="{data.projectDetails.date}"
dateUpdated="{data.projectDetails.dateUpdated}"
banner="{data.projectDetails.banner}"
bannerAlt="{data.projectDetails.bannerAlt}"
/>
<!-- <TableOfContents /> -->
<ContentSidebar bannerContent={{
title: data.projectDetails.title,
subtitle: data.projectDetails.subtitle,
dateIndeterminate: data.projectDetails.date,
dateUpdated: data.projectDetails.dateUpdated,
banner: data.projectDetails.banner,
bannerAlt: data.projectDetails.bannerAlt,
}}>
{#if data.projectDetails.links.length > 0}
<div class="link-button-container">
@@ -34,7 +29,7 @@
<svelte:component this={data.content} />
</Content>
</ContentSidebar>
<style>
.link-button-container {

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import TableOfContents from "$lib/components/table-of-contents.svelte";
import ImageRow from "$lib/media/image-row.svelte";
</script>
![Top view of the Daisy FM synth](fullview.webp)
@@ -35,24 +36,39 @@ I designed the PCB in [KiCad](https://www.kicad.org/). I had no prior experience
I split the PCB into four layers, separating power, ground, digital signals (switches and toggle), and analogue signals (potentiometers, audio out). I made some exceptions, such as for the waveform buttons, since they cross the playing key traces.
<div class="horizontally-centre-aligned">
<img src="pcb-sketch.webp" alt="Screenshot of KiCad schematic">
<img src="pcb-empty.webp" alt="The finished PCB produced from the KiCad schematic">
</div>
<ImageRow
images={[
{
src: "pcb-sketch.webp",
alt: "Screenshot of KiCad schematic",
},
{
src: "pcb-empty.webp",
alt: "The finished PCB produced from the KiCad schematic",
},
]}
/>
The PCB was manufactured by [JLCPCB](https://jlcpcb.com/).
#### USB-C
If using a USB-C breakout board, wire in two 5.1 kΩ pulldown resistors by soldering a resistor between the pin CC1 and ground. Do the same for pin CC2 with a second resistor.
Alternatively, if your USB-C breakout board does not have CC pins exposed, there's a chance you could still connect pulldown resistors to make it compatible. On [this breakout board](https://www.amazon.de/dp/B09FPZDDD9) I purchased on Amazon, I discovered that the third pin from the right exposes a CC connection. Wiring a resistor between this pin and ground enabled C-to-C functionality. If you want to test the functionality before soldering, you can hold a resistor between this pin and either the ground connector on the board or the USB port's outer shell, since that one's grounded as well.
<div class="horizontally-centre-aligned">
<img src="usbc-breakout-small.webp" alt="Close-up of the USB-C breakout board with the CC pin marked">
<img src="hand.webp" alt="The tiny USB-C breakout board compared to my hand">
</div>
<ImageRow
images={[
{
src: "usbc-breakout-small.webp",
alt: "Close-up of the USB-C breakout board with the CC pin marked",
},
{
src: "hand.webp",
alt: "The tiny USB-C breakout board compared to my hand",
},
]}
/>
Do keep in mind that this type of connector does not have mounting holes and requires either a more sophisticated mounting mechanism in the chassis, hot glue, or both. Also, soldering to this pin is insanely finicky, since it is VERY small, so I strongly recommend a breakout board such as [this one by Soldered](https://www.reichelt.de/entwicklerboards-usb-typ-c-adapterboard-buchse-debo-usb-c-f-p376522.html) that exposes the CC pins.

View File

@@ -32,11 +32,11 @@
<title>Homesick | denizk0461</title>
</svelte:head>
<Content>
<Banner2
title="Homesick"
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." />
<Content bannerContent={{
title: "Homesick",
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>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>

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import Video from "$lib/video.svelte";
import ImageRow from "$lib/media/image-row.svelte";
</script>
My progress in October 2023. Updates are shown in chronological order.
@@ -40,10 +41,18 @@ We now have health points! As it is currently set up, the health bar supports up
The health bar even aligns properly for 5 and 6 max health points, reducing the max points displayed per line from 4 to 3!
<div class="horizontally-centre-aligned">
<img src="2023-10-07_01.webp" alt="Five health points in the shape of plusses">
<img src="2023-10-07_02.webp" alt="Six health points in the shape of plusses">
</div>
<ImageRow
images={[
{
src: "2023-10-07_01.webp",
alt: "Five health points in the shape of plusses",
},
{
src: "2023-10-07_02.webp",
alt: "Six health points in the shape of plusses",
},
]}
/>
## What Are the Controls??
@@ -71,11 +80,22 @@ The Quick Select menu opens when the E key (keyboard) or the North face button (
In order to get started with the 3D models I'll need to create for the game, I attempted to begin the process of modelling the weapon of the protagonist! It's supposed to become a battle axe, though I have not yet finalised whether I'll keep with the idea.
<div class="horizontally-centre-aligned width-restricted">
<img src="2023-10-22_02.webp" alt="Top view of the battle axe with a flat blade">
<img src="2023-10-22_04.webp" alt="Top view of the battle axe with a thickened blade">
<img src="2023-10-22_05.webp" alt="Side view of the battle axe">
</div>
<ImageRow
images={[
{
src: "2023-10-22_02.webp",
alt: "Top view of the battle axe with a flat blade",
},
{
src: "2023-10-22_04.webp",
alt: "Top view of the battle axe with a thickened blade",
},
{
src: "2023-10-22_05.webp",
alt: "Side view of the battle axe",
},
]}
/>
## Hot, Fresh Quality

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import Video from "$lib/video.svelte";
import ImageRow from "$lib/media/image-row.svelte";
</script>
My progress in November 2023. Updates are shown in chronological order.
@@ -10,11 +11,22 @@ Lots of progress on the 3D models! I modelled the first weapon for the game, the
The earliest version was based on an 8-sided cylinder. After some feedback from friends, I remade the weapon, using a 16-sided cylinder, and also adding more details to the weapon overall. More attention went into the grip, which now resembled a weapon grip more so than a stick.
<div class="horizontally-centre-aligned">
<img src="2023-11-05_00.webp" alt="N5 Blaster v1 made from an 8-sided cylinder">
<img src="2023-11-03_01.webp" alt="N5 Blaster v2 made from a 16-sided blaster and with additional lights on the grip">
<img src="2023-11-05_03.webp" alt="N5 Blaster v3 with additional lights on the body">
</div>
<ImageRow
images={[
{
src: "2023-11-05_00.webp",
alt: "N5 Blaster v1 made from an 8-sided cylinder",
},
{
src: "2023-11-03_01.webp",
alt: "N5 Blaster v2 made from a 16-sided blaster and with additional lights on the grip",
},
{
src: "2023-11-05_03.webp",
alt: "N5 Blaster v3 with additional lights on the body",
},
]}
/>
Here's an overview of the first model.
@@ -32,11 +44,22 @@ In my first attempt at creating this icon, I took a picture of the wireframed ic
I also continued work on the battle axe, giving it more character. It's still not close to being finished, but it's now a bit less of a rough draft.
<div class="horizontally-centre-aligned">
<img src="2023-11-01_01.webp" alt="Battle axe with a hollowed-out blade">
<img src="2023-11-01_06.webp" alt="Battle axe with a stabilising pattern in the blade">
<img src="2023-11-01_09.webp" alt="Battle axe with two blades">
</div>
<ImageRow
images={[
{
src: "2023-11-01_01.webp",
alt: "Battle axe with a hollowed-out blade",
},
{
src: "2023-11-01_06.webp",
alt: "Battle axe with a stabilising pattern in the blade",
},
{
src: "2023-11-01_09.webp",
alt: "Battle axe with two blades",
},
]}
/>
I will admit though that I'm unsure whether I'll actually stick with the battle axe as the protagonist's main melee weapon.
@@ -46,10 +69,18 @@ Another idea, though more as an unlockable extra, is Derek the crowbar.
I also worked on the upgrade for the N5 Blaster, the N5 Cannon. Progress on that one has been a bit slow, since I have yet to figure out what kind of weapon I want the upgraded version to be.
<div class="horizontally-centre-aligned">
<img src="2023-11-12_04.webp" alt="N5 Cannon body">
<img src="2023-11-12_02.webp" alt="N5 Cannon Body next to the N5 Blaster">
</div>
<ImageRow
images={[
{
src: "2023-11-12_04.webp",
alt: "N5 Cannon body",
},
{
src: "2023-11-12_02.webp",
alt: "N5 Cannon Body next to the N5 Blaster",
},
]}
/>
And, as a bonus, here's the discarded, very-early-WIP draft I created for a rifle-type weapon. I don't think this type of weapon fits the type of game I'm making.
@@ -63,10 +94,18 @@ And a draft of a rocket launcher with 9 barrels! This is heavily inspired by the
I begun modelling my protagonist! I didn't progress far, as I currently lack a vision for where I really want my character to go in detail. I have slight ideas inspirations are, for example, [Merc & Green from Ratchet: Gladiator](https://hero.fandom.com/wiki/Merc_and_Green), and [Denholm Reynholm](denholm.webp). I quite liked the idea of having glowing tubes on the character's back; I got the inspiration from a Blender tutorial that was randomly recommended to me one morning.
<div class="horizontally-centre-aligned">
<img src="2023-11-11_05.webp" alt="Tubes for the back of the protagonist">
<img src="2023-11-12_01.webp" alt="Glowing tubes attached to a torso block">
</div>
<ImageRow
images={[
{
src: "2023-11-11_05.webp",
alt: "Tubes for the back of the protagonist",
},
{
src: "2023-11-12_01.webp",
alt: "Glowing tubes attached to a torso block",
},
]}
/>
i love

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import Video from "$lib/video.svelte";
import ImageRow from "$lib/media/image-row.svelte";
</script>
This is my final update before the next semester begins! I'm actually quite sad about this. For the past few days, I've been really motivated to work on my game. The free time that I had after I finished my last few submissions for university gave me enough room to spend significant time developing. But now that the next semester is about to begin, I fear that university will rob me of a significant amount of my time, and that I will not be able to spend the rest of my time productively.
@@ -65,10 +66,18 @@ Something visual to intersperse the dry code explanations:
This is an image for a weapon I've come up recently! It's supposed to be a slow-firing but strong blaster, contrasting the rapid-firing but weaker N5 Blaster (which recently changed to an automatic firing mode). The Venom originated from sketches like this, by the way:
<div class="horizontally-centre-aligned">
<img alt="A REALLY crude sketch of a blaster." src="dual_venom_sketch.webp">
<img alt="A crude sketch of a blaster resembling the 3D model shown above." src="venom_sketch.webp">
</div>
<ImageRow
images={[
{
src: "dual_venom_sketch.webp",
alt: "A REALLY crude sketch of a blaster.",
},
{
src: "venom_sketch.webp",
alt: "A crude sketch of a blaster resembling the 3D model shown above.",
},
]}
/>
The bolt visible in the first sketch actually makes me consider using [the model I showed off recently](/projects/projectn5/devlog/2024/0323/#a-new-weapon-is-in-the-works-) as the v2 for the Venom (which I would call Antidote by the way, in reference to [this song](https://youtu.be/fbafd6UV3w4)).

View File

@@ -1,3 +1,7 @@
<script lang="ts">
import ImageRow from "$lib/media/image-row.svelte";
</script>
I'M BACK!!!!
For real this time!! I've been busy with university, then I started working on other projects including 3D prints, electronics, a different game, then got busy with university again, and now I FINALLY started work on Project N5 again. And, as I promised in [my last update](/projects/projectn5/devlog/2024/0713), it would not take me another 3 months to get back to development in fact, I undercut that deadline by a whole 24 hours!
@@ -26,10 +30,18 @@ There's also a blue line shooting out of the gun in the picture above. That's a
The N5 Blaster received an overhauled icon. The soon-to-be-implemented N5 Bomb Launcher also received its own icon!
<div class="horizontally-centre-aligned">
<img src="n5-blaster-icon.webp" alt="N5 Blaster logo made from an icosphere and two handles">
<img src="n5-bomb-launcher-icon.webp" alt="N5 Bomb Launcher logo made from an icosphere and waves">
</div>
<ImageRow
images={[
{
src: "n5-blaster-icon.webp",
alt: "N5 Blaster logo made from an icosphere and two handles",
},
{
src: "n5-bomb-launcher-icon.webp",
alt: "N5 Bomb Launcher logo made from an icosphere and waves",
},
]}
/>
I changed the icosphere by tracing its 3D counterpart (the ball inside the N5 Blaster's glass tube) from a different point of view. It wasn't symmetrical before it is now.

View File

@@ -1,3 +1,7 @@
<script lang="ts">
import ImageRow from "$lib/media/image-row.svelte";
</script>
I have lots progress to share!!
First things first: Laura is, unlike I promised before, not yet finished. However, I have made *so much* progress in the past few weeks that I just wanted to get out already. Here's the current iteration of Laura:
@@ -36,17 +40,34 @@ Modelling hair has proven... challenging. What style to go with? What modelling
The first try (seen above) was using the technique from the SELS video selecting faces from the character's head, duplicating them, separating them into their own mesh, changing the scale, adding a solidify modifier, and then adding faces. This... worked, but I didn't like the results. And I tried quite a few styles.
<div class="horizontally-centre-aligned">
<img src="laura-hair-flat-1.webp" alt="White hair with middle split">
<img src="laura-hair-flat-2.webp" alt="White hair with spiky bangs">
<img src="laura-hair-flat-3.webp" alt="White hair with spiky ends">
</div>
<div class="horizontally-centre-aligned">
<img src="laura-hair-flat-4.webp" alt="Brown hair with middle split, flowing behind the character's ears">
<img src="laura-hair-flat-5.webp" alt="Brown hair with middle split and divided at the ears">
<img src="laura-hair-flat-6.webp" alt="Brown hair with big bangs">
</div>
<ImageRow
images={[
{
src: "laura-hair-flat-1.webp",
alt: "White hair with middle split",
},
{
src: "laura-hair-flat-2.webp",
alt: "White hair with spiky bangs",
},
{
src: "laura-hair-flat-3.webp",
alt: "White hair with spiky ends",
},
{
src: "laura-hair-flat-4.webp",
alt: "Brown hair with middle split, flowing behind the character's ears",
},
{
src: "laura-hair-flat-5.webp",
alt: "Brown hair with middle split and divided at the ears",
},
{
src: "laura-hair-flat-6.webp",
alt: "Brown hair with big bangs",
},
]}
/>
It always looked too flat, too shapeless, too boring, wrong cuts. It just didn't work.
@@ -54,19 +75,35 @@ Next up: a technique shown in these two videos: [Blender: How to Make HAIR, Full
Essentially, you create a curve and a circle, use the circle's shape as a profile for the curve, then change the circle's shape as well as the position and scale of the curve's vertices to create individual hair strands. Shown well in the two videos linked above, this can look pretty amazing! Only one issue: I'm creating a **game** character, and this technique is quite expensive, as it creates a lot of polygons for all the individual hair strands and the detail that goes into them. To mitigate this, I lowered the resolution of the profiling and used only a few curves to create an entire head's worth of hair. This looked a little like this:
<div class="horizontally-centre-aligned">
<img src="laura-hair-curves.webp" alt="Toon shaded view at the character with brown hair">
<img src="laura-hair-curves-2.webp" alt="Side view at the character without special shading">
</div>
<ImageRow
images={[
{
src: "laura-hair-curves.webp",
alt: "Toon shaded view at the character with brown hair",
},
{
src: "laura-hair-curves-2.webp",
alt: "Side view at the character without special shading",
},
]}
/>
This hair mesh originally (left picture) consisted of three parts: two curves at the front (left/right) and one in the back. This... was okay, but scaling the curves made the hair look weird. Thinner strands, especially when there's only a few of them, made them look more like dreads, and scaling up the vertices to large scales, as seen in the front near the top of the head, makes the hair look as if it's ballooning. Getting the shape right was a mess too: using only a single curve in the back meant that I had exactly one curve to cover quite literally half the head, and making sure that this singular strand of hair covered the head stretching from one ear to another was a pain. I tried using five curves (right picture), so that I have three in the back, but it didn't improve anything.
I then went *back* to the first method of scaling up faces from the head, with more knowledge and several tries behind me, and you know what? It actually kind of worked out.
<div class="horizontally-centre-aligned">
<img src="laura-hair-flat-new-2.webp" alt="Front view at the character with a green headband and bangs">
<img src="laura-hair-flat-new-3.webp" alt="Front view at the character with a green headband and middle-split hair">
</div>
<ImageRow
images={[
{
src: "laura-hair-flat-new-2.webp",
alt: "Front view at the character with a green headband and bangs",
},
{
src: "laura-hair-flat-new-3.webp",
alt: "Front view at the character with a green headband and middle-split hair",
},
]}
/>
The right picture is the current iteration of Laura's hair. I added a head band because I thought it looked nice, though that detail is not final.
@@ -98,10 +135,18 @@ Influenced while I was researching a tangential topic on a Blender forum, I read
To illustrate my point (get it?), here are some pictures. Left is in T-pose, right is in A-pose:
<div class="horizontally-centre-aligned">
<img src="deform-1.webp" alt="Diagram showing a t-posing character, with the text 'large angle, thus more deformation'">
<img src="deform-2.webp" alt="Diagram showing an a-posing character, with the text 'smaller angle, thus less deformation'">
</div>
<ImageRow
images={[
{
src: "deform-1.webp",
alt: "Diagram showing a t-posing character, with the text 'large angle, thus more deformation'",
},
{
src: "deform-2.webp",
alt: "Diagram showing an a-posing character, with the text 'smaller angle, thus less deformation'",
},
]}
/>
However, after watching [this video on bind poses](https://youtu.be/FXfc4Gyw6I0) by Doodley, it seems that... it doesn't really matter. Whether you use the T-pose, the A-pose, the lovingly-called hug-pose, or anything else really depends on what you plan to do with your character. Since Laura will mostly wield guns and keep her arms fairly low for most of the game, I decided to change Laura's modelling pose to an A-pose, with her arms pointed 30 degrees downward.

View File

@@ -1,13 +1,26 @@
<script lang="ts">
import ImageRow from "$lib/media/image-row.svelte";
</script>
While I've been busy working on another game with friends lately, I've managed to almost completely finish Laura. Here's what I've achieved!
## Visual Personality Adjustment
As promised before, I've worked on Laura's head a bit more. Her full face shield has been replaced with a face mask / respirator covering only the bottom half of her face. Also, I finally got the hair into a state I'm actually happy with. Here's a comparison:
<div class="horizontally-centre-aligned">
<img src="../../2024/1222/laura-hair-flat-new-3.webp" alt="The old protagonist's head with green clothing and full-face mask">
<img src="laura-head-new.webp" alt="The new protagonist Laura's head with red clothing, a half-face mask. The character now has a brown left eye, a mechanical right eye, and eyebrows, as well as bangs">
</div>
<ImageRow
images={[
{
src: "../../2024/1222/laura-hair-flat-new-3.webp",
alt: "The old protagonist's head with green clothing and full-face mask",
},
{
src: "laura-head-new.webp",
alt: "The new protagonist Laura's head with red clothing, a half-face mask. The character now has a brown left eye, a mechanical right eye, and eyebrows, as well as bangs",
},
]}
path="."
/>
The eyes took some work to get right, but I'm pretty happy with the current result. They're not proper eyeballs, but instead they're embedded into the head, which visually isn't significant because the flat shading would hide these details anyway. She has a brown left eye with a small sparkle, as well as a right eye replacement. This implies that Laura sustained further damage to the right side of her body, which necessitated replacement of her eye in addition to her right arm.
@@ -56,17 +69,34 @@ I've been thinking of adding an option (perhaps as a cheat code) to change her o
## Some Funny Pictures
<div class="horizontally-centre-aligned">
<img src="ok.webp" alt="An OK hand">
<img src="dance.webp" alt="Laura flailing her arms">
<img src="naruto.webp" alt="Laura naturo-running">
</div>
<div class="horizontally-centre-aligned">
<img src="shock.webp" alt="Laura's face looking shocked">
<img src="reprehension.webp" alt="Laura's face looking astonished">
<img src="disgust.webp" alt="Laura's face looking disgusted">
</div>
<ImageRow
images={[
{
src: "ok.webp",
alt: "An OK hand",
},
{
src: "dance.webp",
alt: "Laura flailing her arms",
},
{
src: "naruto.webp",
alt: "Laura naturo-running",
},
{
src: "shock.webp",
alt: "Laura's face looking shocked",
},
{
src: "reprehension.webp",
alt: "Laura's face looking astonished",
},
{
src: "disgust.webp",
alt: "Laura's face looking disgusted",
},
]}
/>
## The Future of this Devlog

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import Video from "$lib/video.svelte";
import ImageRow from "$lib/media/image-row.svelte";
</script>
I've been making a lot of progress in a lot of different areas, so I won't be able to elaborate on every little detail, but I'll focus on more major things. Excited to share what I've been working on!
@@ -84,12 +85,26 @@ I also fixed a long-running bug where the `DirectionalLight3D` of this preview w
### Please Appreciate These Wonderful Temporary Weapon Icons
<div class="horizontally-centre-aligned">
<img src="104-icon.webp" alt="An icon for a rocket launcher that looks like a sperm">
<img src="106-icon.webp" alt="A primitive flame as an icon for a flame thrower">
<img src="107-icon.webp" alt="A hand-drawn crosshair serving as an icon for a rifle">
<img src="108-icon.webp" alt="The words 'VENOM' as an icon for the weapon of that name">
</div>
<ImageRow
images={[
{
src: "104-icon.webp",
alt: "An icon for a rocket launcher that looks like a sperm",
},
{
src: "106-icon.webp",
alt: "A primitive flame as an icon for a flame thrower",
},
{
src: "107-icon.webp",
alt: "A hand-drawn crosshair serving as an icon for a rifle",
},
{
src: "108-icon.webp",
alt: "The words 'VENOM' as an icon for the weapon of that name",
},
]}
/>
## Grand Code Overhaul

View File

@@ -1,7 +1,5 @@
<script>
import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/components/table-of-contents.svelte";
import ContentSidebar from "$lib/viewport/content-sidebar.svelte";
export let data;
</script>
@@ -12,18 +10,14 @@
<meta name="DCTERMS.created" content="{data.date}">
</svelte:head>
<Content>
<Banner2
title="{data.title}"
subtitle="Homesick Devlog"
date="{data.date}"
banner="preview.webp"
bannerAlt="{data.bannerAlt}"
/>
<TableOfContents />
<ContentSidebar bannerContent={{
title: data.title,
subtitle: "Homesick Devlog",
date: data.date,
banner: "preview.webp",
bannerAlt: data.bannerAlt,
}}>
<svelte:component this={data.content} />
</Content>
</ContentSidebar>