-
- NOTE: THIS POST WAS TRANSFERRED FROM MARKDOWN BY HAND SO I MIGHT HAVE MISSED SOME STUFF SORRY
-
-
today i wanted to take a bit of time to write about a shader i implemented for my in-progress game project (more
- on that soonβ’)
-
i wanted to create a "blacklight" effect, where specific lights could reveal part of the base texture. this
- shader works with spot lights only, but could be extended to work with point lights
-
-
- Example of shader running, showing hidden writing on a wall.
-
-
-
i wrote this shader in wgsl for a bevy engine project, but
- it should translate easily to other shading languages
-
-
the finished shader can be found as part of this repo
-
-
shader inputs
-
-
- for this shader, i wanted the following features:
-
-
- the number of lights should be dynamic
-
-
- the revealed portion of the object should match the area illuminated by each light
-
-
- the falloff of the light over distance should match the fading of the object
-
-
-
- for this to work i need the following information about each light:
-
-
- position (world space)
-
-
- direction (world space)
-
-
- range
-
-
- inner and outer angle
-
-
- these will control the falloff of the light at its edges
-
-
- outer angle should be less than pi/2 radians
-
-
- inner angle should be less than the outer angle
-
-
-
- i also need some info from the vertex shader:
-
-
- position (world space!)
-
-
- uv
-
-
-
-
bevy's default pbr vertex shader provides this information, but as long as you can get this info into your
- fragment
- shader you should be good to go
-
-
lastly i'll take a base color texture and a sampler
-
-
- with all of that, i can start off the shader by setting up the inputs and fragment entry point:
-
-
- next, we need to make sure the effect falls off properly over distance we can do this by getting the distance
- from the light to
- the fragment and normalizing it with the range of the light before plugging that into an inverse square falloff
- we'll use squared distance to avoid expensive and unnecessary square root operations:
-
- let light_distance_squared=distance_squared(in.world_position.xyz, light.position);
- let distance_factor=inverse_falloff_radius(saturate(light_distance_squared / (light.range * light.range)), 0.5);
-
- now we'll have a float multiplier between 0.0 and 1.0 for our angle and distance to the light we can get the
- resulting color by multiplying these with the base color texture:
-
- let base_color = textureSample(base_texture, base_sampler, in.uv);
- let final_color=base_color * angle_factor * distance_factor;
-
- this works for one light, but we need to refactor it to loop over all the provided blacklights:
-
-
- @fragment fn fragment( in: VertexOutput ) -> @location(0) vec4<f32> {
- let base_color = textureSample(base_texture, base_sampler, in.uv);
- var final_color = vec4f(0.0, 0.0, 0.0, 0.0);
- for (var i = u32(0); i < arrayLength(&lights); i = i+1) {
- let light=lights[i];
- let light_to_fragment_direction = normalize(in.world_position.xyz - light.position);
- let light_to_fragment_angle = acos(dot(light.direction, light_to_fragment_direction));
- let angle_inner_factor = light.inner_angle / light.outer_angle;
- let angle_factor = linear_falloff_radius(light_to_fragment_angle / light.outer_angle, angle_inner_factor);
- let light_distance_squared = distance_squared(in.world_position.xyz, light.position);
- let distance_factor = inverse_falloff_radius(saturate(light_distance_squared / (light.range * light.range)), 0.5);
- final_color = saturate(final_color + base_color * angle_factor * distance_factor);
- }
- return final_color;
- }
-
- and with that, the shader is pretty much complete you can view the full completed shader code here
-
-
In this post I talk about how I went about setting up a stat visualization page for my rockbox mp3 player.
+
+
+
+ A static site generation experiment
+
+
+
+
Preamble: Digital Sovereignity & Rockbox
+
+ I've been building up a pretty sizeable collection of digital music
+ over the last couple of years. I think there's a lot of value in owning
+ the music I pay for and being able to choose how I listen to it.
+ Purchasing music also allows me to support artists in a more direct
+ and substantial way than the fractions of cents for using streaming services,
+ but that's more of a happy consequence than some moral obligation I feel.
+
+
+ Over the years, I've enjoyed listening to my music in a variety of ways.
+ For years I kept all of my music files on all of my devices and used
+ various local music clients depending on the platform, most notably mpd
+ and ncmpcpp on linux. Eventually, as I charged headlong into the glorious
+ world of self-hosting, I began using a central Jellyfin media server that
+ I stream music and video from. It's super convenient, and works on all of
+ my devices (including my TV!).
+
+
+ My media server is great, and it's been the primary way I listen to music
+ for a while now. But it has limitations. For example, I don't expose my media
+ server to the internet, so I'm unable to stream from it while I'm out and
+ about. And even if I could, the bandwidth requirements would be pretty high.
+ I figured I would need a dedicated music player if I wanted to take my music
+ library on the go, and settled on the HIFI Walker H2 after reading some
+ online recommendations. The ability to install Rockbox, an open-source firmware,
+ was a big factor in my decision. I couldn't tell you how the device works
+ out of the box, since I flashed the firmware pretty much immediately once I got it,
+ but I've been super impressed with how the device works while running Rockbox.
+
+
+
+
+ I'm using a modified version of the InfoMatrix-v2 theme, which looks great.
+
+ Rockbox comes with many codecs for common audio formats including FLAC and MP3. The
+ device boots extremely quickly, and the interface is snappy. Virtually every aspect
+ of the user experience is tweakable and customizable to a crazy degree. I've even begun
+ listening to music on my player even at home, since a device specifically for the
+ purpose provides less distraction while I'm trying to be productive.
+
+
+ All this to say I'm pretty much sold on Rockbox. But there's certain things I
+ still miss from my days of being a user of popular services like Spotify with
+ fancy APIs and data tracking. Things like Spotify wrapped or third-party apps
+ for visualizing playback statistics are a fun way to see what my listening history
+ looks like and could potentially be used to help find more music that I'd enjoy.
+ This is why when I noticed that Rockbock has a playback logging feature, a little
+ lightbulb lit up over my head.
+
+
+
+
Generating and Parsing Logs
+
+
+
+ The logging feature can be accessed through the settings menu.
+
+ Rockbox has a feature that logs playback information to a text file. This feature can
+ be enabled by setting Playback Settings > Logging to "On". With this setting enabled, a
+ new line gets added to the end of the .rockbox/playback.log file every time you play a track,
+ containing info about what you played and when.
+
+
+ The logging feature is actually already used by the LastFM scrobbler plugin that comes preloaded with
+ Rockbox, which is probably the simplest way to get insights into your playback. However,
+ I personally want to avoid using third-party services as much as possible, because it's more fun.
+
+
+ If I take a look at a logfile generated after a bit of listening, I'll see that I've wound up with
+ a series of lines that each look something like this:
+
+
1758478258:336689:336718:/<microSD0>/Music/This Is The Glasshouse/This Is The Glasshouse - 867/This Is The Glasshouse - 867 - 01 Streetlight By Streetlight.flac
+ An example of a log entry for "Streetlight by Streetlight" by This is the Glasshouse.
+
+
+
+
+ I wasn't really able to find any information online about the format of these logs, but they appear
+ to be simple enough to figure out. From what I can tell, each event is broken up into 4 pieces:
+
+
Timestamp: The number of milliseconds since the UNIX epoch.
+
Playback Duration: The amount of the song that was played, in milliseconds.
+
Total Track Length: The length of the played track, in milliseconds.
+
File Path: An absolute path to the file containing the track on the filesystem.
+
+ All of this is enough to know what I was listening to and when. I can use the file path to check for
+ audio tags which can help glean even more information about my listening habits.
+
+
Now that I have this information and know how to interpret it, I'm ready to start processing it!
+
+
+
Analyzing Playback History
+
+ In order to get some useful information out of my playback history, I think it's a good idea to start by
+ building
+ a database. I created a sqlite database with the following tables:
+
+
+
+
songs
+
+
+
+
+
id
+
i64
+
PK
+
+
+
title
+
String
+
+
+
+
artists
+
JSON
+
+
+
+
album_id
+
i64?
+
+
+
+
genre
+
String?
+
+
+
+
+
+
+
+
albums
+
+
+
+
+
id
+
i64
+
PK
+
+
+
title
+
String
+
+
+
+
artist
+
String
+
+
+
+
cover_art
+
Blob?
+
+
+
+
+
+
+
+
history
+
+
+
+
+
id
+
i64
+
PK
+
+
+
timestamp
+
Datetime
+
+
+
+
duration
+
i64
+
+
+
+
song_id
+
i64
+
+
+
+
+
+ I can add more columns later, but this is a good place to start.
+
+
+ Now, as I read through the logfile line-by-line, I can check if each album exists before
+ inserting it into the database:
+
+
for line in log_file.lines().flatten() {
+ println!("{line}");
+ // Skip comments
+ if line.starts_with("#") {
+ continue;
+ }
+ let chunks = line.split(":").collect::>();
+
+ let timestamp = DateTime::from_timestamp_secs(
+ i64::from_str_radix(chunks[0], 10).context("Failed to parse timestamp")?,
+ )
+ .context("Failed to convert timestamp")?;
+
+ // Load tags from file on device
+ let file_path = chunks[chunks.len() - 1][1..]
+ .split_once("/")
+ .context("Missing file")?
+ .1;
+ let tags = Tag::new()
+ .read_from_path(args.mount_point.join(file_path))
+ .context("Failed to read audio tags")?;
+
+ //...
+}
if let Some(existing_album) =
+ sqlx::query("SELECT id FROM albums WHERE title=$1 AND artist=$2")
+ .bind(album_title)
+ .bind(album_artist)
+ .fetch_optional(&mut *db)
+ .await
+ .context("Failed to execute query to find existing album")?
+{
+ let album_id: i64 = existing_album.get("id");
+ info!("Album already exists, id {album_id}");
+ //...
+} else {
+ info!("Inserting new album: {album_title} by {album_artist}");
+ //...
+ let result = sqlx::query(
+ "INSERT INTO albums (title, artist, cover_art) VALUES ($1, $2, $3);",
+ )
+ .bind(album_title)
+ .bind(album_artist)
+ .bind(cover)
+ .execute(&mut *db)
+ .await
+ .context("Failed to execute query to insert album into database")?;
+
+ //...
+}
+ Checking for an album with matching artist and title before creating a new row in the
+ database.
+
+ I did something similar with the songs and history tables, basically building up a cache
+ of history information and skipping anything that's already in the database on repeat runs.
+
+
+ With this database constructed, it's pretty easy to get a bunch of different information
+ about my listening. For example (forgive me if my SQL skills are kind of ass lol):
+
+
SELECT
+ songs.title AS song_title,
+ songs.artists AS song_artists,
+ songs.genre AS song_genre,
+ albums.title AS album_title,
+ albums.artist AS album_artist,
+ history.timestamp AS timestamp,
+ history.duration AS duration
+FROM history
+CROSS JOIN songs ON songs.id = history.song_id
+CROSS JOIN albums ON albums.id = songs.album_id
+ORDER BY timestamp DESC;
+ Querying for a list of each history entry along with track metadata, sorted from most to
+ least recent.
+
+
+
SELECT
+ songs.genre,
+ SUM(history.duration) AS total_duration
+FROM history
+CROSS JOIN songs ON history.song_id = songs.id
+GROUP BY genre
+ORDER BY total_duration DESC
+LIMIT 10;
+ Querying for the top 10 most listened genres by playtime.
+
+
+
+ It's all well and good to be able to view this information using a database client,
+ but it would be really cool if I could visualize this data somehow.
+
+
+
+
Visualizing this Data Somehow
+
+ I wanted to make this data available on my website for people to view, and for a bunch of mostly trivial
+ reasons I won't get into here, I have a couple of requirements for pages on this site:
+
+
Pages need to be static.
+
Pages need to be JavaScript-free.
+
+ This means any chart rendering needs to be done automatically at build time before
+ deploying. I don't currently use a static site generator for my site (just for fun),
+ so I'm basically going to need to write one specifically to generate this page.
+
+
+ I won't get too deep into the specifics of how I queried the database and generated each visualization
+ on
+ the page, but I can explain the visualizations I created using the queries from the previous section.
+ For the
+ listening history I wanted to generate a table displaying the information. To accomplish this, I first
+ used a combination of sqlx's ability to convert a row to a struct and serde to serialize
+ the rows as JSON values.
+
+
+ Struct definition for a history entry, allowing conversion from a sqlx row and
+ de/serialization from/to JSON.
+
+
+
+ In order to keep the generation as painless as possible, I decided to use the Tera template
+ engine, which allows me to define a template HTML file and substitute in values from
+ a context which I can define before rendering. In the case of the table, I can just generate a <tr>
+ matching the data for each item:
+
+
+
+ A Tera macro for generating a table from a list of playback history items.
+ I used a macro so I can re-use this later if I want to add time range views.
+ (last month, year, etc.)
+
+
+
+
+ I wrote similar macros for each of the visualizations I wanted to create. Most are
+ easy, but for my top 10 genres I wanted to display a pie chart. I found a pretty decent
+ data visualization crate called charming that's able to render to html, however
+ the output contains javascript so it's a no-go for me. Luckily, it can also render to
+ an SVG which I can embed nicely within the page.
+
+
+ Here's one I generated just now.
+
+
+
+ And that's pretty much all there is to it! The finished thing can be found here.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/blog/rockbox_stats/log-setting.bmp b/blog/rockbox_stats/log-setting.bmp
new file mode 100644
index 0000000..29789fa
Binary files /dev/null and b/blog/rockbox_stats/log-setting.bmp differ
diff --git a/blog/rockbox_stats/playback-settings.bmp b/blog/rockbox_stats/playback-settings.bmp
new file mode 100644
index 0000000..cee3cfb
Binary files /dev/null and b/blog/rockbox_stats/playback-settings.bmp differ
diff --git a/blog/rockbox_stats/player.bmp b/blog/rockbox_stats/player.bmp
new file mode 100644
index 0000000..452a057
Binary files /dev/null and b/blog/rockbox_stats/player.bmp differ
diff --git a/index.css b/index.css
index 62d4571..9ae6d1e 100644
--- a/index.css
+++ b/index.css
@@ -9,15 +9,6 @@ html {
image-rendering: pixelated;
}
-/* Links */
-a {
- color: var(--blue);
-}
-
-a:visited {
- color: var(--purple);
-}
-
#weird-fucking-header-container {
display: inline-grid;
grid-template-columns: 1fr;
@@ -33,3 +24,4 @@ a:visited {
grid-template-columns: 1fr 1fr 1fr;
gap: 4px;
}
+
diff --git a/index.html b/index.html
index 2b49255..20341f8 100644
--- a/index.html
+++ b/index.html
@@ -33,18 +33,21 @@
This page shows a bunch of information about the music I've been listening to on my mp3 player. Think of it kind of like my own personal Spotify wrapped, minus the antichrist.
+
This page is updated wehenever I feel like regenerating it.
+
+
Playback History
+
Total playtime: 7:57:48, 117 tracks
+
+
+
+
+
Timestamp
+
Played Duration
+
Title
+
Artists
+
Album
+
Genre
+
+
+
+
+
2025-09-23 19:41:01
+
3:37
+
The Misty Veil of May
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:37:24
+
2:26
+
An Old Owl Calling
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:34:58
+
3:03
+
Night in a Mossy Hut
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:31:55
+
2:31
+
Crying Wind
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:29:23
+
3:05
+
Dawn
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:26:17
+
3:27
+
Hidden Valley
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:22:50
+
3:32
+
The Gathering of Deer
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:19:17
+
3:49
+
A Wild River to Take You Home
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 19:15:22
+
3:16
+
A Wild River to Take You Home
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-23 16:05:05
+
2:49
+
Twin Fantasy (Those Boys)
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:52:11
+
16:10
+
Famous Prophets (Stars)
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:36:01
+
7:39
+
High to Death
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:28:22
+
5:39
+
Cute Thing
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:22:42
+
6:46
+
Bodys
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:15:55
+
5:25
+
Nervous Young Inhumans
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:10:30
+
5:04
+
Sober to Death
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:05:25
+
1:29
+
Stop Smoking (We Love You)
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 15:03:56
+
13:18
+
Beach LifeβinβDeath
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 14:50:37
+
2:52
+
My Boy (Twin Fantasy)
+
[Car Seat Headrest]
+
Twin Fantasy
+
Alternative
+
+
+
2025-09-23 14:47:44
+
1:32
+
The Light & the Glass
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:46:12
+
3:54
+
A Favor House Atlantic
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:42:18
+
4:15
+
The Camper Velourium III: Al the Killer
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:38:02
+
5:22
+
The Camper Velourium II: Backend of Forever
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:32:40
+
5:21
+
The Camper Velourium I: Faint of Hearts
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:27:18
+
4:05
+
Blood Red Summer
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:23:13
+
6:35
+
The Crowing
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:16:37
+
5:08
+
Three Evils (Embodied in Love and Shadow)
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:11:29
+
5:00
+
Cuts Marked in the March of Men
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 14:06:28
+
8:12
+
In Keeping Secrets of Silent Earth: 3
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 13:49:39
+
2:07
+
The Ring in Return
+
[Coheed and Cambria]
+
In Keeping Secrets of Silent Earth: 3
+
Progressive Rock
+
+
+
2025-09-23 13:45:29
+
5:45
+
Life and Death
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:39:43
+
3:25
+
Father
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:36:17
+
2:16
+
Son
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:34:01
+
3:15
+
Go Get Your Gun
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:30:45
+
4:05
+
This Beautiful Life
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:26:40
+
3:39
+
He Said He Had a Story
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:23:01
+
4:41
+
Saved
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:18:19
+
4:13
+
Mustard Gas
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:14:06
+
5:01
+
The Thief
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:09:05
+
4:51
+
The Poison Woman
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 13:04:13
+
4:39
+
The Tank
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 12:59:34
+
4:49
+
What It Means to Be Alone
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 12:54:44
+
5:29
+
In Cauda Venenum
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 12:49:15
+
1:38
+
Writing on a Wall
+
[The Dear Hunter]
+
Act III: Life and Death
+
Progressive Rock
+
+
+
2025-09-23 12:47:36
+
7:09
+
Vital Vessels Vindicate
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:40:27
+
4:13
+
Black Sandy Beaches
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:36:13
+
4:28
+
Dear Ms. Leading
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:31:45
+
4:29
+
Where the Road Parts
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:27:15
+
6:07
+
Red Hands
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:22:05
+
1:13
+
Red Hands
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:15:59
+
3:48
+
Blood of the Rose
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:12:10
+
3:44
+
Evicted
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:08:26
+
4:45
+
Smiling Swine
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 12:03:40
+
7:46
+
The Bitter Suite III: Embrace
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:55:54
+
6:06
+
The Bitter Suite I & II: Meeting Ms. Leading / Through the Dime
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:49:47
+
4:57
+
The Church & the Dime
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:44:49
+
4:18
+
The Oracles on the Delphi Express
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:40:31
+
9:29
+
The Lake and the River
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:35:12
+
4:25
+
The Lake and the River
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:33:31
+
2:44
+
The Lake and the River
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:30:47
+
4:59
+
The Procession
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:25:57
+
0:38
+
The Death and the Berth
+
[The Dear Hunter]
+
Act II: The Meaning of, & All Things Regarding Ms. Leading
+
Progressive Rock
+
+
+
2025-09-23 11:24:06
+
4:03
+
The River North
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 11:20:03
+
6:00
+
His Hands Matched His Tongue
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 11:14:02
+
6:00
+
The Pimp and the Priest
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 11:08:02
+
7:02
+
1878
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 11:01:00
+
5:56
+
The Inquiry of Ms. Terri
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 10:55:03
+
5:56
+
City Escape
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 10:49:07
+
1:43
+
The Lake South
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 10:47:23
+
1:55
+
Battesimo del fuoco
+
[The Dear Hunter]
+
Act I: The Lake South, the River North
+
Progressive Rock
+
+
+
2025-09-23 10:44:36
+
4:24
+
Chapter X
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:40:12
+
3:32
+
Chapter IX
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:36:39
+
3:39
+
Chapter VIII
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:33:00
+
6:08
+
Chapter VII
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:26:51
+
3:45
+
Chapter VI
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:23:06
+
3:39
+
Chapter V
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:19:27
+
3:24
+
Chapter IV
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:16:02
+
4:24
+
Chapter III
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:11:37
+
2:28
+
Chapter II
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-23 10:09:09
+
1:23
+
Chapter I
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-21 19:50:53
+
12:26
+
Sleep
+
[Godspeed You Black Emperor!]
+
Lift Your Skinny Fists Like Antennas to Heaven
+
Post-Rock
+
+
+
2025-09-21 19:50:18
+
3:27
+
A Wild River to Take You Home
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-21 19:45:18
+
1:28
+
A Wild River to Take You Home
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-21 19:43:49
+
0:28
+
A Wild River to Take You Home
+
[Black Hill & Silent Island]
+
Tales of the Night Forest
+
Post-Rock
+
+
+
2025-09-21 19:40:11
+
0:48
+
Night Ela (Mystic Thing)
+
[Candy Claws]
+
Ceres & Calypso in the Deep Time
+
Shoegaze
+
+
+
2025-09-21 19:28:37
+
1:28
+
Night Ela (Mystic Thing)
+
[Candy Claws]
+
Ceres & Calypso in the Deep Time
+
Shoegaze
+
+
+
2025-09-21 19:26:40
+
0:42
+
The Tragedy
+
[The Pax Cecilia]
+
Blessed Are the Bonds
+
Post-Metal
+
+
+
2025-09-21 19:25:58
+
5:01
+
A Dance With Death
+
[We Lost the Sea]
+
A Single Flower
+
Post-Rock
+
+
+
2025-09-21 19:25:00
+
3:26
+
Homecoming: Denied!
+
[Harakiri for the Sky]
+
Aokigahara MMXXII
+
Post-Metal
+
+
+
2025-09-21 19:21:33
+
1:18
+
Keeping the Blade
+
[Coheed and Cambria]
+
Good Apollo Iβm Burning Star IV, Volume One: From Fear Through the Eyes of Madness
+
Progressive Rock
+
+
+
2025-09-21 19:20:14
+
1:47
+
I Existed
+
[Snooze]
+
I Know How You Will Die
+
Progressive Metal
+
+
+
2025-09-21 19:14:22
+
7:40
+
Robinson
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 19:06:42
+
3:35
+
October
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 19:03:07
+
10:21
+
Old George
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:52:45
+
9:34
+
867
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:43:11
+
3:38
+
Two-Headed Calf
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:39:33
+
6:25
+
7Bass / Lorne
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:33:07
+
9:51
+
January
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:23:15
+
3:39
+
Southpaw
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:19:36
+
8:37
+
Before Machinery
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:10:58
+
5:36
+
Streetlight by Streetlight
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 18:05:21
+
0:17
+
Streetlight by Streetlight
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 15:00:22
+
0:02
+
Before Machinery
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 15:00:12
+
5:36
+
Streetlight by Streetlight
+
[This Is The Glasshouse]
+
867
+
Progressive Rock
+
+
+
2025-09-21 02:29:43
+
0:24
+
The Diary of Jane
+
[Breaking Benjamin]
+
Phobia
+
Rock
+
+
+
2025-09-21 02:29:20
+
1:13
+
Intro
+
[Breaking Benjamin]
+
Phobia
+
Rock
+
+
+
2025-09-21 01:23:28
+
2:00
+
The Diary of Jane
+
[Breaking Benjamin]
+
Phobia
+
Rock
+
+
+
2025-09-20 19:51:54
+
0:05
+
Chapter X
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:41
+
0:01
+
Chapter IX
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:39
+
0:01
+
Chapter VIII
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:38
+
0:01
+
Chapter VII
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:36
+
0:01
+
Chapter VI
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:35
+
0:01
+
Chapter V
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:33
+
0:01
+
Chapter IV
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:32
+
0:01
+
Chapter III
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:30
+
0:01
+
Chapter II
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
2025-09-20 19:51:29
+
0:02
+
Chapter I
+
[Sufferer]
+
Sufferer
+
Post-Hardcore
+
+
+
+
+
+
+
+
Top Genres
+
+
+
+
+
+
+
Progressive Rock: 5:09:49 (64.8%)
+
+
Alternative: 1:07:16 (14.1%)
+
+
Post-Rock: 51:41 (10.8%)
+
+
Post-Hardcore: 37:09 (7.8%)
+
+
Post-Metal: 4:09 (0.9%)
+
+
Rock: 3:39 (0.8%)
+
+
Shoegaze: 2:17 (0.5%)
+
+
Progressive Metal: 1:47 (0.4%)
+
+
+
+
+
+
Top Albums
+
+
+
+
+ πΈ Act II: The Meaning of, & All Things Regarding Ms. Leading
+ π€ The Dear Hunter
+ β± 1:25:26
+
+
+
+
+
+
+ πΈ 867
+ π« This Is The Glasshouse
+ β± 1:14:56
+
+
+
+
+
+
+ πΈ Twin Fantasy
+ π€ Car Seat Headrest
+ β± 1:07:16
+
+
+
+
+
+
+ πΈ Act III: Life and Death
+ π€ The Dear Hunter
+ β± 57:51
+
+
+
+
+
+
+ πΈ In Keeping Secrets of Silent Earth: 3
+ π€ Coheed and Cambria
+ β± 51:36
+
+
+
+
+
+
+ πΈ Act I: The Lake South, the River North
+ π€ The Dear Hunter
+ β± 38:38
+
+
+
+
+
+
+ πΈ Sufferer
+ π€ Sufferer
+ β± 37:09
+
+
+
+
+
+
+ πΈ Tales of the Night Forest
+ π€ Black Hill & Silent Island
+ β± 34:13
+
+
+
+
+
+
+ πΈ Lift Your Skinny Fists Like Antennas to Heaven
+ π€ Godspeed You! Black Emperor
+ β± 12:26
+
+
+
+
+
+
+ πΈ A Single Flower
+ π€ We Lost the Sea
+ β± 5:01
+
+
+
+
+
+
+
Top Artists
+
+
+ The Dear Hunter: 3:01:57
+
+
+
+ This Is The Glasshouse: 1:14:56
+
+
+
+ Car Seat Headrest: 1:07:16
+
+
+
+ Coheed and Cambria: 52:55
+
+
+
+ Sufferer: 37:09
+
+
+
+ Black Hill & Silent Island: 34:13
+
+
+
+ Godspeed You Black Emperor!: 12:26
+
+
+
+ We Lost the Sea: 5:01
+
+
+
+ Breaking Benjamin: 3:39
+
+
+
+ Harakiri for the Sky: 3:26
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/style.css b/style.css
index 03f81d9..c45a247 100644
--- a/style.css
+++ b/style.css
@@ -44,6 +44,14 @@ body {
perspective-origin: top left
}
+pre, code, samp {
+ font-family: unifont;
+}
+
+samp {
+ color: var(--gray2)
+}
+
.section {
margin: 1rem;
padding: 1rem;
@@ -188,3 +196,12 @@ a.evil:hover {
flex-direction: column;
align-items: center;
}
+
+/* Links */
+a {
+ color: var(--blue);
+}
+
+a:visited {
+ color: var(--purple);
+}
\ No newline at end of file
--
cgit v1.2.3