Bio

Hihi! I'm Sophia. I like rust (the programming language). Links: https://github.com/pufferfish101007 https://pufferfish101007.edgecompute.app

Stats

2
Projects
26
Devlogs
6
Votes
0
Ships

Coding Time

All Time: 71h 40m
Today: 1h 10m

Member Since

June 21, 2025

Projects

2
Yak Stack
10 devlogs 3 months ago
HyperQuark
16 devlogs 3 months ago

Activity

Earned sticker
Sophia
Sophia worked on HyperQuark
2h 41m 2 days ago

Today I implemented yet more blocks: the operatormathop block (which does things like sqrt, abs, ceil, floor, (a)sin/cos/tan, ln, log, exp and pow), operatorrandom, and direction-related blocks. This means that my 'colourful smiley face simulator' test project (http://scratch.mit.edu/projects/951679565) now compiles (although it doesn't quite work properly yet). I suspect it's something to do with nested loops but i'm not totally sure.

Update attachment
Earned sticker
Sophia
Sophia worked on HyperQuark
1h 51m 3 days ago

Today I implemented the operator_mod block, which wasn't too difficult in of itself. However, at the same time, I tried to simplify some of the type analysis so that blocks themselves don't need to consider the cases where they might receive boxed inputs (because that never happens in practice because blocked inputs are sent off to monomorphised implementations). This led to some interesting code to find the actual output type for when there are boxed inputs, including the attached almost-triple-question-mark which thankfully didn't make it into the final commit.

Update attachment
Earned sticker
Sophia
Sophia worked on HyperQuark
1h 6m 4 days ago

Today I implemented the pen_setPenColorParamTo block (which allows setting the hue/saturation/brightness/transparency of the pen colour individually). Was slightly challenging as the parameter menu is an input rather than a field (so accepts arbitrary values) :(
Image: the same as before but even more colours

Update attachment
Earned sticker
Sophia
Sophia worked on HyperQuark
9h 36m 5 days ago

Ok so I'm not quite sure how I've managed to rack up so many hours recently but anyway here's the devlog.
Since I started the rewrite late last year, I've been using a reusable pattern/trait/type that I call the 'registry pattern', which is really just an insertion-ordered key-value map with some associated functions. There are some cases where the keys and values that are passed in are constant (known at compile time) and used in various places across the codebase. It would be convenient if these could be stored in importable constants, but the issue then arises that I've got to make sure that the correct key is used with the correct value. To resolve this issue I create a new registry type called a NamedRegistry, inspired by reading through the codebase of typst, which allows me to define a zero-sized struct with associated constants from which an arbitrary (but consistent) name is derived and the value reused. Now rather than writing something like func.registries().tables().register("exampleTable", /* a bunch of info */) many times, I can write func.registries(),tables().register::<ExampleTable>() which is much nicer. And the code is quite abstract which makes me feel clever ;)
Using this new registry pattern I added a new registry for static utility functions, which were required for hsv<->rgb colour conversions, so I've was then able to implement colours as a primitive value (RGB and ARGB colours require separate primitive values because they behave slightly differently) and the pen_setPenColourTo block.

Attached image: the same as before, but colourful.

Update attachment

Ok so since my last devlog I've added a bunch of blocks but I was coding on my phone using vim so my time wasn't recorded ._.
Here's a complete (maybe) list of blocks that I've added since then:
- set size to
- switch costume to
- show
- hide
- pen down
- pen up
- clear (pen)
- forever
- go to (x) (y)
- set pen size to

Still more left to do and then i want to think about either lists or broadcasts.

(image: scratch cat drawing with pen)

Update attachment

I discovered that the preview deployment on github pages doesn't work even though my local build does - it turns out that vite treats a certain dependency differently depending on if it's building for dev or prod. To simplify things, I just set it so that it works in prod, and I'm using prod mode locally as well. Also updated my nightly rust toolchain locally so it matches CI and all my checks pass, for the first time in quite a while. yay!
this is probably a good point for me to push all the changes in my branch to the main repo and deploy as a new version.

Update attachment

With all my recent changes, my unit tests had got out of sync with the main codebase. I fixed these up to match recent api changes, and also replaced a lot of code that was duplicated elsewhere in the codebase and doing quite a bad job of it. Now all tests pass! (Although I definitely need more unit tests elsewhere in the codebase that don't just test that the generated wasm compiles!)

Update attachment

I've now started implementing some more basic blocks. I decided to start with the switch costume to [] block as it's probably the simplest block that requires some rendering. Rather than hardcoding offsets for the in-memory positions of various sprite properties, I made a macro that takes the names of properties and their sizes, and keeps track of their offsets automagically. Noice. Implementing the block itself was very easy but I had an absolute nightmare trying to get the sprite to actually display properly - this is probably where most of the supposed coding time came from, but in reality it was a one-line fix - I had mistyped target.direction as target.rotation. This is one of the few times I wish I was using typescript rather than javascript (although that would be horrible to work with scratch's quite-complicated json schema).
I also came across an instance of a Weak reference being dropped before usage, so I created a small reference cycle as a workaround - although this will cause a memory leak, it shouldn't be a particularly significant one, and I plan to reduce my usage of reference-counted pointers in the future anyway, which should get rid of the root problem. Hopefully.

Attached image: scratch cat displaying it's second costume successfully. Yippee!

Update attachment

I discovered yet another bug in the variable type analysis system (after I'd claimed that I'd fixed them all) - yippee! Turns out that doing funky shennanigans with variables means that we sometimes get missing type casts that we need to reinsert. Fixing this was ostensibly very simple (just needed to run the insertcasts procedure after VTA), but I also decided to address a long-standing issue where I was using hacky workarounds to allow procedures to return multiple values, without allowing multi-valued returns in the type system. This wasn't a particularly large change but was spread across many files so took quite a while to do. This was important to fix because `insertcasts` was getting a bit confused because I never made it consider procedure calls as a special case, since prior to now it never encountered multi-valued-returning procedures (as these are only added during VTA). While I was there I also spotted a possible bug involving transforming variable access to procedure argument access, which failed to consider the presence of regular procedure arguments.
With these changes, I could now run the benchmark project that I was using prior to the mega rewrite earlier this year, so today's image is some meaningless out-of-context benchmark numbers. You're welcome!

Update attachment

Fixed a little bug to do with procedure parameters - boxed inputs [1] were not being automatically boxed, but now they are! Also linted. Sorry for the short devlog but there's really nothing more to say!

[1] a boxed value is one that doesn't have its type known at runtime, so it is stored along with a tag of its type

Update attachment

It's been a while since my last devlog; I've been working on other projects. For hyperquark, I've been fixing more small and subtle bugs in the VTA (variable type analysis) system. These are really annoying to debug but my favourite one (i.e. the most frustrating) was where I was getting errors about the type stack being larger than the number of variables it was being assigned to. In the execution logs, it appeared that one step (a collection of operations) was being visited twice by the VTA module, but with a different set of opcodes. This was really very confusing, until I realised that steps can be accessed through more than one route - for instance through the different branches of an if/else block - and so visited more than one time. However, visiting a step can also modify that step (e.g. to write to outer-scoped variables), so on the second visit, any additional instructions were duplicated and so we ended up with a type stack double the size than was expected. It was a simple fix once I identified that, but it took a very long time to get there!

I don't really have any fun images of things working to give you, so have a pic of my latest error instead.

Update attachment

I've now created a build script to make my life slightly easier. It means that:
- I don't need to remember the long command for building (cargo +nightly build -Zprofile-hint-mostly-unused)
- I don't need to remember to export SVGs as PNGs every time I create or edit them

This was originally a bash script but then I realised that bash doesn't work how I want it to on windows which is sad, so I redid it in python and discovered the argparse library which is cool! (Unfortunately I can't do this all in WSL because of bugs in how WSL handles input events)

I also linted the rust codebase which is nice.

Update attachment

Cleaned code up a bit and also made the transitioning from stack to conga mode a bit better. Now yaks stop crouching if they aren't supporting another yak (or if they're stuck), and the mode buttons are disabled until the transition has finished. I was also finding that yaks were sometimes getting a little bit stuck on the seams between other yaks and the ground, so if it is detected that a yak is stuck and isn't falling, it is given a little bit of vertical velocity to help it get clear of the seam. Hopefully.

I've now added buttons. Which was surprisingly hard. I wanted to be able to edit buttons' enabled/hover/clicked/disabled space altogether, so settled for a spritesheet-esque approach in inkscape. This worked great except for the fact that using an AtlasTexture didn't always seem to correctly crop to the correct portion of the atlas - this was an incredibly easy fix (just needed to set a minimum size for the button) but took ages to figure out. I also modularised things a bit more including texture loading - textures are now loaded from pngs where possible and fall back to svgs. I'll probably put png conversion in a build step in the future so i don't need to remember to do it manually and to help clean up source control.
The buttons are for switching yak configurations - at the moment these configurations are stacked and conga. To get from stack to conga I thought I'd just have the yaks crouch down so they slide off of each other - this works fairly well and I just need to get them to stop crouching and also stop sliding once they're on the ground and not under any more yaks. No idea how I'll re-stack them - possibly something to do with having some of them sit down and act as ramps? I think controlling jumping yaks will be very difficult!

Sophia
Sophia worked on Yak Stack
2h 24m 2 months ago

The last couple of hours of dev time have been spent cleaning up the file structure and also making some tweaks to the code & art. I was experiencing some really funky issues where textures weren't aligning with their collision boxes - I believe this is because i was scaling textures by non-integer scale factors. Don't know why that's a problem but it is what it is. So I jiggled things around a bit and now everything aligns nicely; yaks' collision boxes are also now perfect squares which is nice.

In terms of cleaning things up, I removed old test files, moved assets into their own folder that's a bit more organised, added a README.md and also added a license (I went for the MPL-2.0 which is roughly equivalent to MIT OR APACHE-2.0, the standard license in the rust ecosystem).

Have a yak (now with a square collision box [from bottom of taller legs to top and sides of body]) as the attachment.

Update attachment
Sophia
Sophia worked on Yak Stack
3h 51m 2 months ago

I have spent literally hours playing around with different things to try and get stacking and sliding working correctly (and I think I've done some other stuff that I wasn't able to devlog due to the SoM website being down). See the attached video for an example of yak stacking working properly!

The way it works is as follows:
- Each Chunk of terrain is a StaticBody2D rather than a TileMapLayer. This allows tiles to be grouped into rectangles rather than being lots of squares - this helps with ghost collisions. At some point I may go back to using TileMapLayer for rendering, but keep using custom colliders, but only if rendering becomes a performance issue. It should be noted that as of godot v4.5 (not yet released on stable channel), TileMap colliders are chunked into larger quadrants in order to reduce ghost collisions, but I didn't find this to work at all.
- Rather than the yaks moving and the ground staying still, the ground moves (backwards) with the yaks staying still and sliding along it. This greatly improves the stability of the physics. In order to make the ground move visually and also apply physics as if it were moving, I had to both set a constantlinearvelocity in each chunk and also change the position on each physics frame. This caused some issues with wrapping chunks around for infinite scrolling, since position updates in a signal handler seem to be overwritten by position updates in physics_process, so these position updates needed to be deferred.
- because the yaks don't need to be moved left/right, i replaced the CharacterBody2Ds with RigidBody2Ds (with rotation locked to avoid chaotic spinning) - this worked really well and makes things pretty stable
- because yaks don't move any more, they were sometimes set to 'sleep' by the godot physics engine, which caused them to hover in mid air if a yak underneath them was impeded by a block - this was fixed easily because you can tell the engine to not put bodies to sleep
- yaks that go offscreen are now removed to save on resources - this means I've got rid of camera zooming temporarily but I plan to bring it back at some point

now i just need to figure out how to move yaks into different configurations, which is going to be difficult now that they're rigid bodies :( fun times!

Sophia
Sophia worked on Yak Stack
1h 53m 2 months ago

Got smooth camera zooming and sort-of-stacking of yaks working. I'm quite pleased with the camera zooming as a first attempt, but overall I feel it could be a lot better - it should really zoom out until all active yaks are in view, but at the moment it just decreases the zoom by 8(?)% if the edge of a yak goes off screen, regardless of how far off it goes.

Yak stacking also only works up to four yaks for some reason, but I'm glad I managed to get it working at all. In order to get the yaks to stack, I had to inspect the most recent collisions of each yak, and only set the horizontal velocity to a positive value if one of those collisions was with a Chunk node (i.e. the floor) - I can't just use the native is_on_floor method because that detects other yaks as the floor too! Because yaks currently have friction of 1.0, if a yak is on top of another yak it will immediately slow down to stationary (relative to the other yak), so that all works out fine. I also briefly experimented with using a RigidBody2D rather than a CharacterBody2D for the yaks, to give me more fine-grained control, but I was totally out of my depth there.

Next I want to work on making stacking work better, then removing abandoned yaks (i.e. those which are no longer moving) from the scene (so we don't get infinite camera zoom)

Got infinite scrolling (+ infinite(?) yak spawning) working! Infinite scrolling was surprisingly easy - I just use a VisibleOnScreenNotifier2D to signal when a chunk of terrain goes offscreen, at which point it is transported to the right of the other chunks. I had to learn about godot's signals for this, but they're surprisingly simple, and using rust makes this so much easier, because the godot crate provides typed signals, which make it much much easier to reason about what's happening where. I still need to make it so that when the camera zooms out, more chunks are created if needed. Once I've done some camera zooming stuff, I'd like to start playing with making yaks actually stack on top of each other rather than just walking along and shmooshing into a line.

Sophia
Sophia worked on Yak Stack
2h 53m 3 months ago

Today I worked towards getting infinite scrolling + terrain generation - at the moment the 'terrain' is just flat, with an extra block on top 20% of the time. It's also not quite infinite yet - I still need to make chunks wrap round to the front when they're offscreen. Yaks are also now programmatically generated, so my node tree in the godot editor is looking quite empty. I suspect I am not really doing things in 'the godot way', especially as rather than using the built in ready hook, I'm doing my setup manually - that's just because I don't really know yet what order things are initialised in. Next up I also want the camera to be able to zoom out if the yack gets offscreen - this will be useful for when I start implementing stacking and the stacks get tall; at some point I'll also want to implement the wave coming so that yaks that lag behind are removed.

In the video attached I am jumping over hurdles à la Chrome Dino Game; this is just a temporary mechanic to test the scrolling and terrain generation!

Sophia
Sophia worked on Yak Stack
1h 51m 3 months ago

Used the godot tutorial on the jumpstart website (https://v1.jumpstart.hackclub.com/guide.html) to create a very basic platformer. This wasn't just blindly following a tutorial though, as I had to translate the scripting bit to rust, which worked out ok once I'd figured out where things are. Although yak stack won't be a platformer per se, it will need that sort of physics, and using a tilemap for the terrain should work fairly well (and it'll be a lot easier than anything else). Just need to figure out how to do scrolling (presumably just move the camera, but I'll need to figure out how to discard unneeded sections of the tilemap) and also procedurally generate said tilemap - hopefully that's possible. Then I'll need to figure out how to add new nodes at run time (for many yaks), and then I can start figuring out the actual game mechanics. Exciting times!

Sophia
Sophia worked on Yak Stack
1h 22m 3 months ago

I decided to try and learn to use godot for this (but using rust of course); this is my first time using a game engine so it'll be interesting. The attached video is what I've got working so far; I wanted to (as a test) use arrow key inputs to control the spinning speed of the yak but there seems to be some sort of input control issue with WSLg, so I'm now going to have to install rust (and godot) on my windows system :( Then I can get started actually creating this game hopefully!

Sophia
Sophia created a project
86d ago

Yak Stack

The Big Moo (supreme leader of all yakkind) was lounging on a hot, sunny beach when a tsunami warning came in. Thankfully, you're on duty, piloting the brand new Yak-O-Matic 3000, perfect for dropping yaks out of the sky. Your mission is to strategically stack those yaks to construct impromptu bridges, towers and sacrificial battering rams to save The Big Moo from the tsunami. Don't panic. Just Yak Stack.

Yak Stack
10 devlogs 0 followers

Today I fixed a bunch of little bugs around all sorts of things... so many I can't even remember what I've done. I think there are still some instances of variable graph node entries being in the wrong order (fun to debug 🙄) but hopefully those won't be too bad to fix - and once those are done I can move on to some slightly more interesting items on my todo list; then I can push the last few weeks of changes to the main branch and release v0.0.5. The image is a funky iterator adapter that I wrote today which I quite like. Apparently I've spent 2h26m since my last devlog, so this time must include some other time from the last few days that I haven't devlogged for - no idea what I was doing in that time tbh but was probably just more nitty gritty bug hunting.
Have a great Thursday :D

Update attachment

Just devlogging so I don't lose a little bit of time from yesterday - started refactoring how I handle string constants, using the js string imports extension rather than manually inserting them into a table. To do this I'm needing to add an additional lazy instruction for global indices, because we can't know what index a global will have until we've inserted all the necessary global imports, which can't happen until all steps are compiled.

Update attachment

Finally managed to iron out all the various bugs surrounding procedures in VTA. Turns out procedures need a lot of special casing because not only can they return multiple values, they also need any boxed inputs to remain unboxed - usually, boxed inputs are unboxed and passed into monomorphised blocks, which currently doesn't work with procedures - I would like to do procedure monomorphisation at some point but I need to figure out if it will be worth the trade off for code size. Not many lines changed for a long period of time but a lot of that was spent trying things out and then deleting them again.

Update attachment

Just adding a devlog so I don't lose my very important 8 minutes and 56 seconds of working today... I spent that time trying to debug an interesting issue in the VTA where a node is emitted which has more variable writes than there are elements on the stack. I know this must occur somewhere around the entry/exit to procedures, but I'm not sure where yet. Although I haven't yet fixed that bug, I did manage (i think) to preemptively fix another big which will occur on the exit to procedures. Maybe.

Update attachment

VTA (variable type analysis) now considers the flow of variables in and out of procedures; or rather, it will do once I've ironed out the bits that don't work. This required changing procedures to have return values (not yet implemented in WASM gen), along with considering procedures in the VTA graph generation - this included changing first-time global variable reads in procedures to argument access. Hopefully this'll allow for some nice optimisations once it's working. The commit is quite large but this includes changes before I started recording time for this hackclub event!

Update attachment
Sophia
Sophia created a project
97d ago

HyperQuark

Compile Scratch projects to WebAssembly to run them quite quickly. Hopefully.

HyperQuark
16 devlogs 0 followers
Sophia
Sophia joined Summer of Making
97d ago

This was widely regarded as a great move by everyone.