You are browsing as a guest. Sign up (or log in) to start making projects!

purpld

@purpld

Joined June 10th, 2026

  • 14Devlogs
  • 4Projects
  • 1Ships
  • 15Votes
NEEEERD!
Open comments for this post

6h 56m 28s logged

A REAL BOARD!

A trickier task than it sounds like, but I needed some clues finally! The default testing board was uh… not exactly “production ready” in my opinion (lol).

This was tricky particularly because, well, where am I going to get clues from? You kinda need a LOT of clues for a good Jeopardy game, and while UGC is something I want to make, I would like a default mode, too, and there is certainly no way that I was going to try to make a bunch of clues by myself.
(respectfully, I don’t think I am also smart enough to do that lol)

Jepp

I found a little project called jepp which exposes a LOT of existing Jeopardy clues through an API. I didn’t want to bother that API too much though, and there is an SQLite DB dump publicly available, so LARPARDY now uses that instead. With a little bit of SQL later (and, uh, remembering how to use SQL lol)… we have many, many clues!
The only thing is that the database does not store the value of clues, so it’ll be a bit random. A $1000 clue might end up being super easy lol, but I think that’s some jank I’m okay with.

Player list

Ooh also, I made a proper player list now! I did want literal podiums, which I may still do at some point, but I’m happy with this for the time being. This can now also react to changes in the game like points or who’s turn it is!

0
0
1
Open comments for this post

9h 50m 3s logged

BEEEG DEVLOG

Wowwee! I’ve gotta remember to make devlogs more often.
Seriously. Here’s a list of changes that I’ve made since my last devlog!

  • The basics of the board are implemented! You can’t interact with it yet, but the template to do so is there, and it now exists on the server-side too and the client reads from that state.
  • The board is also animated now. When someone selects a clue, it will highlight the category and the clue, you can hover clues, and, my favorite bit, the categories get revealed one by one when the game starts!
    • That last part actually kind of sucked to implement lol. I prepared for this when making the lobby’s ready up system and made the state that it uses to work a bit dynamic because I knew that I would need it! The state stores readyForNextState, which for some states (like when we’re in the lobby) allow unreadying, but for others, simply act as a marker of whether a specific client is ready to move on. This is probably actually really important because if we just ran a timer on the server, a NUMBER of things could go wrong, most importantly being that a laggy client could get desynced VERY quickly and have a bad time.
  • Alongside this, there is an intro now! I spent a good bit of time in Aseprite and messing with FL Studio to make some art and an intro track, both for the logo and so I finally have some artwork to add in the Discord Developer Portal, so there aren’t anymore blank assets. It’s not perfect (i am NOT an artist lol) See pictures below!
    • psst, I also made a “think” music track for if the final round is enabled! It’s not in the game yet, though.
  • I made a number of styling fixes. The board in particular looks much better on different screen sizes now, even on my phone. Reminder to use relative sizes when able, not px!
  • The server now registers the activity entry point command as having an APP_HANDLER handler, which means that the server must respond to interactions now, rather than Discord autolaunching the activity. The benefit of this is that we have control over whether a message gets sent to the channel it was started in (and when), or if we even launch the activity at all (disallow banned users? anything is possible…)!
  • The rich presence actually has meaningful details now lol, rather than placeholder text.

NOWWW what?

I am going to, FINALLY, FOR REAL THIS TIME, (lol) actually start making the game logic. (It’s about time!)
More updates sooooon!

0
0
9
Open comments for this post

1h 59m 30s logged

I prototyped the game board last night! This took a while to get the styling right as I want this to work well on all screen sizes, hopefully including mobile devices. It’s still a little rough on very small sizes (e.g., my phone), but one step at a time! I still want to add little “podiums” at the bottom for our players.

After that, I’m going to be working on getting the board working on the serverside, so that actually becomes part of the game state.

0
0
6
Open comments for this post

8h 39m 30s logged

socket.io is cool, BUT

So. 8 hour devlog, my bad, but I’m going to start by talking about the thing that I’ve been mostly fighting with today.

The networking backend that I’m using for LARPARDY is Socket.IO, which works similarly to (and usually on top of) WebSockets, but with a lot more quality of life features and ease of use for specifically these kinds of situations.
I have been fighting for a few hours today trying to figure out why I could not, for the life of me, get socket.emit to work on the client.

It was, in fact, one setting, retries, in the client config, stopping it from working, for SOME reason. Oops.

Anyways…

PROGRESS! (GAME!)

Progress has been steady! Most of the changes that I’ve been making have been making the client more workable as I make new components, and actually more planning out the infrastructure. I’ve designed some new UI elements, moved where some state is stored, and so on. I have a bad habit of overplanning, or rather, being too worried about planning big projects like these, because I like to avoid having to do cleanup work later (like the cleanup that I’m doing on the client right now). It’s not strictly a bad habit, but sometimes it’s better to just write the code rather than spend hours deliberating about micro-optimizations with yourself.

I believe I am now ACTUALLY at the point where I can begin properly building the UI for the game board and the frontend & backend aspects around that.

This was more hidden work (and… fighting with the socket.io client, apparently) so I don’t have too much to show this time either, sadly. BUT, I did finally design and prototype the lobby! So you do get something fun to look at while I work on everything lol

0
0
1
Open comments for this post

8h 55m 14s logged

it’s REDISin’ time!

wait is that… not the line from the movie?
(also SORRY this should have been at least a couple devlogs lol, please forgive me)

I’ve finally been working on the state management for LARPARDY! This turns out to be a MUCH harder task than I originally thought it would be, particularly because I’m trying to make sure that this will be safe and work well in a real environment.

Redis

First of all, instead of keeping state in the server’s memory, I have added a Redis DB to the project. This is part of why I wanted Docker set up, as this is now just in the docker-compose.yml!

I have NEVER personally used Redis before, so some time of the time from this devlog was admittedly stumbling my way through figuring out how to use Redis correctly.
CORRECTLY is the key word, to be clear. I’m building basically a wrapper class around the Redis database, StateManager, which abstracts away the nasty database stuff so the main code doesn’t have to worry about actually interacting with Redis. It was, kind of a pain to write actually (lol?), because I was worried about race conditions basically the entire time, since this code needs to run async (i.e., something else might do something to a thing while we’re also trying to do something with that thing). I HOPE that the state management code is bug free for now, but we’ll see.
(please…)

Client

The client has now also been updated to listen for new game states. I also finally figured out how to set up Rich Presence, so it will show that you’re playing LARPARDY on your profile!
In addition, I made it so in-game avatars will highlight green when someone is speaking (like Discord), and I added waiting UI for when a player has joined but hasn’t fully connected yet, AND for when you are still connectin#.

so NOWW can we start to make the actual game?

yyyyyYES! I think so. I hope, anyway (lol). I believe my next step will be making a basic lobby/waiting UI that lets you start the game, and then finally start to implement the actual game. I AM EXCITEEEEDD
(there’s not a ton to look at since this was mostly backend work. sorry! i’ll have more next time :3)

0
0
2
Open comments for this post

1h 15m 24s logged

oops…

I wasted some time on accident, woops.
I thought Discord’s proxy verification meant that the discordsays.com proxy would send these headers to verify that an actual Discord client had connected with them, but uh, I checked the flowchart again and I got that wrong. Hm. Thankfully, I didn’t get too far into implementing that.

Regardless, trying to implement that still encouraged me to do a small bit of cleanup, which was properly declaring the environment variable. A certified :ts: moment.

(YES I am going to abuse the fact that I figured out that you can use custom emotes here. i am so sorry)

smol devlog

0
0
3
Open comments for this post

7h 18m 10s logged

I HATE DOCKER i love Docker!! :33:

So, I didn’t even write a devlog yesterday because I spent the entirety of the time that I did have setting up a Dockerfile and docker-compose.yml for LARPARDY.

…why did it take that long

Because I’ve never used Docker before! Well, I have, to run services on my PC and my homelab server, but I’ve never used it for my own projects before.

Specifically, I want to go ahead and set up Docker because I know that I’m going to need a database (or possibly two! SQL + Redis), and running everything together in a container will make both development AND deployment much easier for me.
I’ve never used it before, so this is, uh, a learning experience, to say the least.

oh also, pnpm

Oh. Also. pnpm has a bug. Apparently.
I’m using pnpm as the package manager for both the server and the client (since they’re both TypeScript projects). Both projects are stored in a monorepo (literally meaning just a repo with multiple projects, basically), which makes it easy to manage for me and keeps my commits together.

Nicely, pnpm recommends a Dockerfile for this exact scenario! I reconfigured the project to use pnpm‘s workspaces feature (which… is seperate from package.json’s workspaces, for some reason) so that this would work.
pnpm deploy is supposed to copy the project with it’s own node_modules since workspaces use a shared one. The problem is that, when it rewrites workspace dependencies (because I have a shared package for both the server & client), it links it to the wrong source, which no longer exists after it’s copied!
I tried to debug and get this working for ACTUAL AGES before I gave up and just wrote commands that manually copy the files instead.
I figured that there HAS to be a way to get this working, considering the documentation itself recommends this build file. But noooope. It doesn’t seem so (cite: this GitHub issue which has been open since… 2023???).
:bleh:

so what did you actually do

The Docker config works now, and that’s the important thing! I currently have the client build into an nginx image, but I’m either going to drop this entirely or have the server serve the client files itself. This will allow me to implement Discord proxy header verification too, if I decide to.

0
0
1
Open comments for this post

1h 43m 59s logged

Socket.IO!

As for perhaps one of the most important bits… this is Socket.IO! I had to figure out how to get this working with Fastify first (thank you random GitHub commenter) since that’s my web framework of choice for the backend (for anything not going through Socket.IO), but here’s a basic implementation of it working!

what it do?

Socket.IO works similarly to (and if it’s available, on top of) WebSockets, where there’s a persistent connection with bi-directional communication between the client and the server. Socket.IO adds some extra fancy things on top of that, such as fallbacks when WebSockets aren’t available and rooms, and in general will make my life easier (lol).

This part is, of course, very important for getting a game handled by the backend to work! This will also allow us to do multiplayer. Discord gives you an instance ID for each activity that players are playing together, so I’ll use this to make the rooms, that way players in the same voice channel will end up in the same game!

0
0
4
Open comments for this post

5h 48m 34s logged

ho boy…

I’ve wanted to make a Discord Activity basically since the feature began being teased… so, no better time than the present, right? I saw some guys playing Jeopardy the other night and I realized that I feel like the online ways of playing Jeopardy are kinda… uh, bad? I thought I should fix that.

I’ve been getting a lot more comfortable with frontend development recently (I’m normally more comfy with backend stuff!), so now this is really going to test my ability to handle FULL STACK development.
With that said, I’ve been playing around since last night and I have a working setup with (stable) communication with the Discord client via the SDK. (hooray!) Currently, it just shows the name and avatar of connected players.

don’t you love React?

Me too! Unfortunately, I am lying.
I’m trying Vue.js for the first time for this project. There is a LOT that I’m planning that is very new to me for this project. I expect to need Redis, Socket.IO, and (of course) the Discord activities SDK, none of which I’ve ever used. So, here we go?

the name. dude. what. why

I didn’t originally have a name for this (the README still remains “Untitled Jeopardy Clone” for now), so I was using the name “Leopardy” as a placeholder. Someone recommened me to switch to LARPARDY.
I couldn’t say no. I wish I did.

…anyways, next up is actually making some sort of game state work. I’m going to start working on the backend!

0
0
4
Ship

I made an easily configurable microphone hot swapping tool! Inspired by the lovingly horrible microphone of the Logitech C922 webcam. My project allows you to configure a microphone (for example, your webcam's mic) and record a hotkey, and then swap whenever and wherever (and quickly!) by holding down your hotkey. Your system's default microphone will be set to your chosen device when held, and return to whatever it was previously when you let go. And it works on both Windows and Linux!

This seems quite simple on paper, and it probably SHOULD be, but a couple of things made this actually quite challenging:
1. I wanted FUNNY MIC to be cross-platform! Nobody should be stopped from having horrible mic quality. Audio APIs on different OS's, however, are VERY different! I learned how to use conditional compilation in Rust, and most importantly, how to use it wisely, to make an internal API that works and changes depending on your platform. This also meant I had to learn how these platform-specific APIs work and how to use them!
2. Most importantly, this was my first time using Tauri as the backend framework for a Rust project! That in and of itself was quite challenging, but I've found that Tauri is nice to work with! I also chose React as my frontend UI framework, which I have used before, but it has been quite some time.

I'm proud of this silly little over-engineered thing I managed to make with the tools that I've been given! I think this is a program that I'll actually be continuing to use too (to mess with my friends, of course), which is nice.

To test this project, you will need to download and run an installer for your platform. If you're on NixOS, please see the README for more instructions; I've included a package for you too!

  • 4 devlogs
  • 25h
  • 18.35x multiplier
  • 437 Stardust
Try project → See source code →
Open comments for this post

7h 43m 10s logged

V1! (last devlog before ship?)

Wew, I should have probably made a devlog in between my last one!

Windows support

I have added Windows support! Fun fact, I hate working with the Windows API, and I’ve just learned that!
In fairness, it’s a littleee bit awkward working with an API that is very obviously native to C, even if the Rust library gives it some Rustiness, but still, I dislike it. Greatly. Anyways, the important part is it works! And I had to use an undocumented Windows API to do a basic task (setting the default audio device). Nice. Cool! Awesome.
(i’ve been trying to switch to Linux for a reason)
Thankfully, someone already implemented that in the com-policy-config crate so I don’t have to find and try to convert a header file myself.

Saving the config!

After Windows support was done, the rest was relatively easy! Tauri has another plugin that makes it a little bit easier to manage a JSON store file and make it accessible to anything that has an AppHandle. config.json now stores the selected swap device and keybind, and these get automatically reloaded on startup. Lovely!

oh hey uh, how are we building this thing, exactly?

I use NixOS as my main operating system, so I already made a default.nix and shell.nix for running here. However, it doesn’t seem I can properly compile the regular bundles for .deb., .rpm, and AppImages (easily, anyway), and it would be tedious for every release anyways! Thankfully, tauri-action already exists, too! I made a GitHub Actions workflow that will compile and publish installers for both Windows and Linux when I make a new release. It’s pretty neat stuff, actually!

README, After All

This also means I finally took the time to make a nice README. It was nice to take a small step back to kind of overview this project.
A fun little over-engineered thing this is, something that could have stayed a CLI app with only Linux support and nobody would have blinked, but here we are!
It’s definitely been good practice for both my backend (Rust!) and frontend skills. I will definitely be using Tauri again in the future!

Hello, from v1.0.0! (and Windows!)

0
0
1
Open comments for this post

11h 13m 26s logged

“It’ll be easy!”

NO IT WON’T BE ASDSFSDGDG
ahem. What I mean to say is that the UI is done and ready! I think it looks relatively nice, simple, and most importantly, is functional.
I, somehow, managed to log 11 HOURS, of which a significiant part of was not doing the UI, actually! It was literally just trying to get the global shortcut functionality to work again!

Wayland doesn’t like you doing that, actually

I use KDE Plasma as my desktop environment, which uses Wayland by default as of Plasma 6. I want to support all systems, and that obviously includes my own, but the Global Shortcut plugin for Tauri, as it turns out, only natively supports X11. Ah.
At first, I tried using this pull request by patching it into my dependencies, so the Tauri plugin would use that instead of the normal crate. This worked actually! Until I tried using unregister_all(), at which point it crashes the xdg-desktop-portal with a SIGABRT, somehow, for some reason.
I have no idea if that’s an issue with my system (I tried updating!) but I couldn’t find a way around it, so I ended up scrapping that plan (using an unreviewed, unmerged PR probably isn’t a great idea anyway…).

What now?

After what I said about rdev in the last devlog, I ended up writing a key handler module that would fallback to rdev when detecting Wayland (inspired by how murmur ended up doing this as well).
Except… I wrote all this, spent a couple of hours getting everything working, and then somehow, by having moved the callback function for shortcuts into the Rust code (where I previously was trying it from the frontend in TypeScript), it… WORKS?! With the default Tauri plugin, which is only supposed to work on X11.
This requires some more testing (is this a KDE Plasma specific thing?! or Xwayland??), so I’m keeping the keys module I made around for now just in case.

Good news!

The good news is that this means it works! The really only last two bits I need are Windows support and saving the config.
Should this have taken this long? Probably not. I attribute that to still wandering my way through Rust and literally never having used Tauri before (lol). A good amount of time was spent getting the UI working in a way that I was happy with, too!
With that said, here’s a quick recording of everything working!

0
0
2
Open comments for this post

4h 11m 29s logged

UI TIME!

This is my first time using Tauri! As I’ve learned with a previous project, UI and Rust are still a bit iffy, sadly.
Tauri effectively parallels Electron while offering much better performance, especially as you still use Rust for the backend while allowing the ease of use of HTML + CSS + JS/TS for the frontend! It uses native WebViews instead of Chromium, which gets rid of one of my biggest frustrations with Electron, that being including and running a whole browser for what’s often a single page.

Of course, this is, uh, maybe is not the best project to showcase how great those features are considering there is effectively one (1) main feature here (lol), but this is a learning experience and an excuse to continue more Rust!

I’m adding UI because running from the terminal is not the best UX, and this will make it easier to change the config (which you couldn’t do before after starting!) and handle everything more gracefully.

I will say that, so far, the developer experience with Tauri has felt great. Automatic hot reloading is enabled by default on both the TypeScript frontend AND the Rust backend (which will auto-rebuild), super neat! Getting everything set up with Nix was… less great, but not Tauri’s fault.
I also chose to use React for this project, as it’s been quite some time since I’ve really worked with it.

Oh, yeah, also I made a logo in Aseprite! I mainly needed this for a tray icon. Modeled after the one and only Logitech C920 PRO HD Webcam, with its glorious (read as: bad (read as: loud = funny)) microphone.


Now that the project has been refactored for Tauri, I need to port the old code to the new “backend”. I’ll build the config UI around this once that’s done!

Also, Tauri actually has a global shortcut plugin, so I can replace rdev with this for a (hopefully) less janky handling system.
(it’s awfully hard to find info about global key handling, probably because that’s misused for malware more often than not…)

0
0
1
Open comments for this post

1h 55m 27s logged

INITIAL PROTOTYPE

I almost forgot I was going to make this! I made an initial prototype for funnymic, which (for now, at least) is a CLI tool to hot swap to a microphone only when holding down a key (like a very, very bad and comically loud C922 webcam mic, perhaps lol).

This initial prototype only works on Linux. My TODO is to

  • Make this faster if possible (maybe some async jank happening right now)
  • Add Windows support
  • Make it actually configurable

This also is an excuse for me to learn more Rust! I’m likely going to work on most projects in Rust to continue learning (when it makes sense).

0
0
3
Open comments for this post

1h 33m 38s logged

NEOCITIES LOG 1

hihi! i’ve been on Neocities for a while, but, y’know, i haven’t had a good place to log my development process before! so this seems fitting.

i finally finished and published my Bluey page! it is LITERALLY a children’s show but despite that i became obsessed with it last year, and i think it’s actually really neat and really is worth the recognition. i started working on this shrine page mannyyy months ago and i’ve finally recently had the time to finish it to my liking!

one of my favorite parts of my shrine pages is matching the styling! i “borrowed” some CSS (mainly colors) from the actual bluey.tv website to help, but learning CSS while making this website has definitely been interesting lol

the voice clip buttons also use a convenient nunjucks macro to save me some time (and it keeps consistency)!

{% macro audio(url) %}
<a
  href="#"
  onclick="new Audio('{{ url | escape }}').play(); return false;"
  aria-label="Play voice clip"
  ><i class="nf nf-fa-play"></i
></a>
{% endmacro %}

this would probably be better with a dedicated script, but that seemed like a bit much for this task IMO so i did NOT do that lol

in general i learned actually quite a lot about CSS from this, i cannot lie lol

i’m quite happy with how this turned out in the end. whether or not you care about the show, i hope it’s worth a read!

(psst, also, the time logged for this devlog is quite small because most of this page had been done before Stardance! i just finished some touchups today and merged it.)

0
0
3

Followers

Loading…