Second Ludum Dare in the books! I'm absolutely overwhelmed by the response. Thank you so much to everyone who played Splines 'n Shapes! For me, finishing a game in 48 hours counts as a huge success. I didn't even consider these results to be a possibility going into this jam:

I'll try to go over the process of making Splines 'n Shapes, as well as learnings, thoughts and next steps. It might get a bit long and ramble-y so feel free to skim this or just skip it entirely.
Game Description
https://ldjam.com/events/ludum-dare/47/splines-n-shapes
Splines 'n Shapes is an abstract puzzle game where you adjust loops and collect shapes. Loops are adjusted by repositioning control points and shapes must be collected in order (tri -> square -> pentagon -> etc) as well as in a single loop cycle. (Also... you must make a full revolution and collect the first triangle again :sweat_smile:)
https://www.youtube.com/watch?v=ieoemXV6vnc
Development Timeline
Initial Ideation
Whenever the theme of a jam is announced, I spend the first couple hours brainstorming ideas. I usually do this by taking a walk, away from my phone, my computer, or any distractions of that sort. I've heard that being in a calm, diffuse mode of thinking is better for creativity than a focused, active mode of thought. I find that walking and removing distractions helps put me into that diffuse state.
Having said all that, I didn't really brainstorm anything too interesting :sweatsmile: :sweatsmile: :sweat_smile:. Initial ideas included:
1. trying to escape a recursive function / for/while loop
2. nascar game w/ left turns?
3. something something hyperloop elon musk
4. some sort of paper plane game where you control how the plane loops
5. a game where you repeatedly throw and catch a boomerang in place.
Ending up going with option 5. I envisioned some sort of topdown view of a seated guy throwing a boomerang where the player could adjust the trajectory of the throw. The idea was still hazy, but it was time to start implementing.
Initial Implementation and Salvaging the Design
My initial implementation was for the boomerang throw to follow a Bezier curve where the two endpoints of the curve are at a single static position (explanation of Bezier curves). The two inner control points are adjusted with WASD and arrow keys or gamepad sticks:

I found this control scheme to be pretty bad for a couple reasons:
1. Reorienting the curve into a new direction (e.g. north to south, east to west) took an unacceptably long time. This wouldn't work for any sort of semi-realtime game.
2. It's pretty easy to get the control points mixed up. For example, if WASD control the initial left point and arrow keys control the initial right point, things could get mixed up if the initial left point was moved to the right of the initial right point.
It became pretty clear to me that if I was going to continue in this curve route, I'd need to switch to a click and drag interface. And I'd need to spice things up a bit.
Enter Splines
I recalled the term "Spline" and that it was related somehow to Bezier curves. Google led me to this document explaining them. Here's my shitty layman's summary of it (images taken/modified from the doc itself):
Splines are essentially a bunch of polynomial curves glued together. However, if you simply match the end values of these curves, there can be irregularities and kinks in the spline:
(C0 is a cubic bezier curve defined by control point sequence <P0, P1, P2, S>. C1 is defined by <S, Q1, Q2, Q3>)
There's a special set of splines called relaxed uniformed cubic B-splines. These splines are made up of Bezier curves glued together such that the spline remains smooth when moving from curve to curve. We can do this by setting anchor points, and then determining control points of each Bezier curve such that the slope and curvature at each matching end point is equal. The following image and algorithm might help explain:

- First we must place our anchor points (denoted by the points
B_i above).
- We then trisect each line segment between
B_i and B_(i+1) in order to obtain the inner control points P_i,0 and P_i,1 for Bezier curve C_i
- We then find matching endpoint
S_i as the midpoints between P_(i-1),1 and P_i,0. S_i is the endpoint of curve C_(i-1) and the start point of curve C_i.
- also note that the start point of
C_0 is S_0 which equals B_0. the end point of C_(n-1) is S_n which equals B_n. (n is the number of anchor points in the spline)
Hooray we have now have a relaxed uniformed cubic B-spline (I'm gunna call these B-splines from now on):

(The reasoning for why this algorithm works is in the paper linked above.)
In order to make this B-spline a loop, we add an additional curve between B_n and B_0. Like in the above steps, we must trisect the line segment to get our inner control points, and then update S_0 and S_n based on these inner control points:

ayyy! check out our B-Spline loop! The small gray points are our anchor points (our B points). The calculated S and P points are hidden. Looks pretty ugly though, so I resized/rethickened the shapes and loop, and used a 3 color gradient that I cycled to turn it into this:

The shapes and loop are all rendered with Freya Holmér's Shapes Library. This asset is a godsend in jams, especially for the artistically challenged like myself.
At this point, I had a pretty fun toy to play around with. Now I just needed to turn it into a game. I had some thoughts spinning in my mind. The main idea I had was for the revolving orb to hit a sequence of targets on the screen. The targets would need to be hit in a particular order, and these ordered targets would be represented by regular polygons (triangle, square, pentagon, etc). But by now I was about 13 hours into the jam, it was super late at night, and I fell asleep.
However, I woke up after only like 3 hours of sleep. Wasn't intentional. I think I was a bit anxious and excited about all the things I needed to implement, so I had trouble falling back asleep. In my groggy haze, I started to implement sounds.
Sounds
Decided to go with synth sound effects for this game, mostly because it's within my current skillset (I'm about 3/4 of the way through Syntorial...that's about it :sweat_smile:) and because I felt some influence from Mini Metro.
The sound effects I knew I needed were:
- orb properly hitting a target
- orb incorrectly hitting a target
- selecting/deselecting an anchor point
I played around with Synth1 in Reaper and came up with a basic patch that sounded pretty soothing. Main properties include:
- sine and triangle waveforms for osc1 and 2.
- Low Pass filter at about half cutoff.
- High amp release
- Chorus
- a bunch of reverb from stock plugins
(also had some minor variances between the orb hit patch and the anchor selected patch. 'Orb hit' has some FM w/ osc2 pitched at 28 semitones (FM amount is modulated with an envelope). This gives it a bit of a bell-like quality. 'Anchor selected' has zero amp sustain and osc2 pitched at 31 semis above)
The Synth1 patches are available to download on my itch page: https://sharkwithlasers.itch.io/splines-n-shapes
After getting a general sense of how the synth patches would sound, I noodled around on the keyboard to figure out note sequences that sounded nice. (for when an orb properly hits a sequence of targets)
I arbitrarily decided to play notes in the key of Bflat major (because C major is basic AF). And came up with ascending note sequences based on the number of targets that would need to be hit for a particular level:
number of notes | Note sequence (in scale degrees!) | Actual notes
--------------- | --------------------------------- | ---
2 | 1, 3 | Bb, D
3 | 1, 2, 5 | Bb, C, F
4 | 1, 3, 5, 6 | Bb, D, F, G
5 | 1, 2, 3, 5, 7 | Bb, C, D, F, A
6 | 1, 2, 3, 5, 7, 9 | Bb, C, D, F, A, C
7 | 1, 2, 3, 5, 7, 8, 10 | Bb, C, D, F, A, Bb, D
There wasn't too much rhyme or reason to how I came up with these. I kinda just followed my ear. I think I reduced the potential cheesiness by:
- avoiding long runs of the major scale (nothing longer than 3 notes here)
- avoiding outlining the I chord (I do this in the 4 note sequence though :slight_frown: )
- ending the longer note sequences on chord extensions of the I chord. (gives it a little bit of spice?)
- (and perhaps ending on the 3 and 5 in the first sequences helps establish the key? maybe?)
For the "Anchor point selected" notes, I would randomly choose a note in the scale degrees {1, 2, 3, 4} (and ensure no repeates). The "anchor point deselected" note would be a perfect fifth below the "selected" note. This pairing of notes felt pretty smooth and consonant.
For the "Target improperly hit" note, I landed on using Eb (perfect fourth above Bb). I experimented with using dissonances like the tritone, but these sounds clashed with the chill mood that my game was headed in. The perfect fourth seemed like the perfect balance of consonance and dissonance for this sound.
In order to get these sounds into Unity, I rendered the notes at Bb, then modified the pitches at runtime with Unity's AudioSource. These didn't sound as nice as when I was playing in Reaper, though. Going forward, I'll probably render each note separately in Reaper and dynamically play the correct audio clip in Unity.
Design and Game Feel Iteration
If I remember correctly, I spent the next portion of the jam working on polish and finalizing the small details of the gameplay loop.
Design Decisions
One thing I find pretty neat about game jams is that I start with a hazy initial idea, and through the process of iterating through many micro design decisions, end up with a totally different, but concrete result. These micro decisions sculpt and shape the game into a product I would have never thought of during the initial brainstorm. I think that's pretty cool.
Some of the many decisions I had to make included:
- deciding that the shapes must be collected in order
- capping the number of shapes in a level to 6 (it's hard to distinguish shapes once you go beyond 8 sides)
- deciding that all shapes must be collected within a single revolution
- deciding that this single revolution starts when you hit the first shape (triangle)
- deciding that you could still adjust the loop while the shapes are being hit / validated
- deciding that the orb must finish it's cycle and hit the triangle again.
- increasing the speed of the orb when it hits the first shape (to discourage loop adjustments during validation)
I'm not sure if all of these decisions were correct, but overall, I think it led to interesting puzzles where the player is not punished for experimenting.
Polish / Game Feel
For game feel / polish, I basically follow some lessons from the great Juice it or Lose it talk. Primarily, for any object/player interaction, there should be visual and/or audio feedback.
Some interactions (and feedback) in the game included:
- shape getting hit (shape flashes and enlarges, orb gets larger, loop thickens, audio)
- hovering over, selecting, and deselecting anchor points (enlarging the points on hover and select, shrinking on deselect, aura radiates from point, audio)
- revolution passes that is invalid (all shapes darken and then reset, audio)
- anchor point added/removed (during level transitions)
- shape added/removed
- ...
I mainly used DOTween to handle the visual feedback. Tweening is dope.

After this, I had to work on structing my code to have a level sequence, and properly transition between levels. This took a while and was pretty messy, so I'm just going to leave it at that. At the time of completion of all of this, I had about 3 or 4 hours left to design levels. (I think I snuck in a 3 hour nap in there somewhere. Unintentional once again, I think the anxiety of the jam made it hard for me to fall back asleep).
Level Design
For some reason, I always leave the designing of levels/puzzles until the end of the jam. I think a reason for this is because level design is such an open ended subject. In any case, I didn't have much time, so I followed these general principles:
- Convey the mechanics of the game through the sequence of puzzles (I'm not a fan of tutorialization)
- Show interesting, unique properties of B-Splines through these puzzles
The way I found interesting mechanics of B-Splines was by toying around with them in a sandbox, noticing an interesting loop/property, and then sprinkling shapes along the loop to turn it into a puzzle. It was a bit of a rushed process, but by the end of the jam, I had about 20 levels! Hooray!
Made a build, made a page, submitted. slept.
After the Jam
Over the past weeks, I've been playtesting the game with friends and streamers. The feedback I've gotten has been incredibly helpful and supportive! And it's been great getting to know people in the LD community!
(There are a ton of improvements that I could add to this game. Some low-hanging fruit, as well as design decisions that don't have a clear answer. (maybe I'll list some here later))
Because of the external support, as well as the fact that the aesthetic fits my limited art and audio skills, I plan on expanding this into my first full project. There's so much to do / think about!
- What should the scope of the game be?
- Should I limit the curves to just B-Spline loops?
- What kind of gameplay do I want players to experience (casual and chill, or stimulating puzzles)?
- What mechanics/extensions should I add to this game to keep it interesting?
- Can I jam a narrative into this?
- What should the game teach the player? (interesting shapes? interesting abstract properties of curves?)
- ...
It's pretty exciting, yet daunting to think about. It seems like these questions can only be answered by doing the work and iterating.
So, it's time to get to work! I might post updates on my twitter if you are interested.
Thank you for the wonderful jam experience!