Springbound Devlog 1: Shaping a mountain
A deep dive into speeding up level design iteration as a solo dev using custom tools in Unreal Engine
Hey! I'm Bryce, a solo game developer and creator of Springbound. This is part of a series of deep dives exploring interesting aspects of the game and sharing lessons learned along the way.
Here’s the whole series if you’d like to read more: Springbound Devlogs
Springbound has a relatively compact map with 5 distinct areas: forest clearing, meadow, upper mountain, lower slope, and lower mountain. Most of the game involves flowy movement down a mountain, so little level details like slope and elevation affect the game’s feel. Each area has different elevations and routes to slide along that are designed around the game’s locomotion mechanics.
I had little prior experience in level design for this game, so creating tools and workflows that allowed me to prototype, test, and quickly iterate on layout ideas was a big win!
This post covers the experimentation process and the tools I created for shaping terrain and slopes in Unreal Engine. Hopefully, it’ll be useful for you too! I’m working on cleaning up and releasing some of these tools… stay tuned.
Flowy movement and level design: a perfect match!
From early on in development, I knew that the game would take place on the side of a mountain. This nicely tied together both the emotional notes I wanted to explore around life’s ups and downs with the flowy movement mechanics that felt good in early prototypes (more on this later).
Because the game progresses downhill at the beginning and character movement is also faster (and more exciting) going downhill, I realized that I could regulate the game progression and pacing using flat, uphill, and downhill areas.
Different movement modes complement different slope types to create pacing as the player moves between interesting parts of the map to meet objectives:
This matrix shows how the pacing and level geometry are directly coupled together: movement modes are regulated by the slope of the landscape and map layout, and the points of interest need to be spaced apart based on the amount of time it takes to move between each. I wanted to evoke feelings of awe and joyful discovery when encountering and exploring large spaces for the first time—but lasting just long enough to feel like a meaningful journey without making the walks between points of interest tedious.
Skating movement facilitates quicker player movement along important routes that the player crosses multiple times. I added an ice slope through the meadow because the player crosses this area several times in the game:
Since they’re closely coupled, I needed to prototype and iterate the level design and feel of the main locomotion mechanics together!
Starting the prototyping process
When I first started prototyping out the mountain slope, each revision took hours!
I started by just hand-painting the landscape height using Unreal’s built-in tools. But small bumps and slope changes were noticeable (even after smoothing) because the player movement code samples landscape data and angle to figure out how fast the player slides.
Also, I quickly learned that when the map is on a slope, adjustments to the scale of regions and the distance between locations cause huge changes in the vertical Z position of everything on the map! In one experiment, I added a few extra switchbacks to a steep ski slope so the run would be 30 seconds longer. This change moved the ending area ~10,000 scene units lower! Every small adjustment meant a lot of manual work sculpting terrain and moving actors around.
So, I tried out a couple of workflow changes:
Using multiple additive maps for each area that could be moved around in the editor
However, aligning separate landscapes without seams becomes tedious with this method and any level-loading transitions are difficult to disguise since this is an outdoor, open-world map.Using Gaea (a 3rd party terrain tool) to take slope maps and automatically fill and erode terrain around them
I wanted realistic mountain terrain surrounding the main areas anyway so this workflow could save time, but it wasn’t as precise as I needed. Gaea is great for detail on a macro scale but micro tweaks especially to precise elevations are super difficult. I tried exporting precise heightmaps for slopes and important areas and layering this on but subsequent passes always remove this precision, even after adding bulk to counteract erosion.Creating custom editor tools in Unreal to shape slopes and areas non-destructively, and place objects procedurally (cough cough PCG)
There’s nothing better than being able to make tweaks and see the final result in real time. This gave me the most flexibility and I used it from prototyping to the final version!
Slow iteration + difficult workflow means…time to make some tools!
If you Google “unreal nondestructive landscape tool” you’ll quickly find Landmass, a fantastic plugin that lets you set up nondestructive terrain brushes using Blueprint! You can use splines to define peaks, valleys, and rivers plus layer on different types of noise for a more organic feel. It’s super fun to play around with.
But after digging deeper, I found that the Landmass brushes were designed to be more artistic and directional than precise. If I created a spline at a specific height, the resulting landscape would move up or down when I tweaked the properties in the brush (caveat: this was in UE 5.3, things might have changed since). And everything was additive which wasn’t quite what I was looking for.
The next stop was the Landscape Patch plugin. It doesn’t have much official documentation but YouTube has many videos about it. It only has two built-in patches, a circle height patch (that brings a circle of landscape to a specific height) and a texture patch (which does the same thing using a heightmap, and with a blend mode - alpha blended, additive, min, max). This is much closer to what I was looking for!
But… that’s it. No other fancy terrain tools like Landmass. So, time to make my own!
I used the Landscape Texture Patch component as a base and built a blueprint tool LandscapePatch_Mesh
around it that takes a user-defined mesh and renders a heightmap texture from it that is passed into the patch. The patch then moves the landscape covered by the mesh up or down to match the exact height of the mesh.
I chose this mesh-based approach because it offers the most flexibility for defining surfaces over the landscape. Unreal has plenty of tools for generating meshes like the Spline Mesh Component and UE5’s relatively new Geometry Scripting plugin which generate meshes programmatically.
This is the hierarchy of mesh patch tools I created. These tools have everything I needed to shape the map—clearings, rivers, slopes, lakes, and ravines! All use splines (open splines for paths/slopes and closed splines to define areas like clearings):
I added extra functionality to some of the specialized patches:
The clearing patch also tags its spline for use in PCG, so that trees and plants aren’t generated in the clearing
The river patch creates spline meshes with an ice material following the river path
The ski slope patch uses a custom-built spline mesh component which adds visualizers and custom detail controls using
FComponentVisualizer
andIDetailCustomization
in C++ to allow fine-tuned control over the angle and speed of the slope:

Adventures in heightmap land
All of this sounds great in theory, but how do you actually render a heightmap texture from a mesh? This seemingly small piece turned out to be much more complex than I expected.
Let’s look at one interesting slope on the map, the cliffside path up to Pip’s burrow:
We’ll start by capturing the slope spline mesh from below using a Scene Capture component.
The “from below” part is important because if the mesh is convex, the landscape should only touch the bottom of the mesh, not clip up through to the top
Capture at the resolution that Landscape Texture Patch needs (one pixel per landscape quad)
This gives us a heightmap texture like this (here the depth is encoded in the red & green channels):
We want the landscape to gradually blend from the slope area to match the surrounding terrain, because hard edges look bad. Luckily, Landscape Texture Patch has a “Use Texture Alpha for Height” property, so if we turn this on we can insert this blend value in the alpha channel of the heightmap texture.
But looking at the texture above… there’s no depth data outside the slope shape for blending. We need a depth value to extend beyond the slope shape to blend with the lower layers of the landscape.
Intuitively, we’d want to extend the height value of the slope’s closest edge outward. But how do we do this? Good news: there’s an ✨algorithm✨ for that! Enter: jump flooding and signed distance fields (SDFs)!
(Interestingly, Landmass uses these too and I referenced their implementation for mine!)
In our case, the jump flood algorithm does this: it finds the edges of the shape and sets each pixel there to its (X, Y) texture coordinate. Then, until the entire texture is filled, it iteratively finds pixels adjacent to any set pixel and sets their value to the set pixel’s value.
It produces a texture where every pixel contains the coordinate of the closest edge of the shape that it starts with. Here’s the visual output (red = X and green = Y):
So what can we do with this jump flood texture? We can generate a signed distance field!
SDFs look crazy when you visualize them but they just represent the distance to the edge of a shape (in our case the slope squiggle above), with a negative sign if it’s outside the shape or a positive sign if it’s inside. Since the value of each pixel in the jump flood texture above stores the coordinate of the closest point on the squiggle shape, if we read the distance from the value of each pixel to the coordinate of each pixel, we have our distance field! Here’s the SDF for the slope above (again, distance is encoded in the red & green channels):
What can we do with this? Well, we now have the distance from anywhere on the landscape patch to the nearest point on the slope. And then we can use this distance to figure out the blend value for anywhere on the landscape patch to create that nice gradual blend discussed earlier. The resulting blend looks like this:
Woohoo! We have the blend value for the landscape anywhere on the patch. Now, we need the height value for the landscape. Luckily, we already have that jump flood texture above so we can use that to fill the entire texture with the height of the closest edge of the slope (red & green encoded):
We’re almost there!! We can now combine the patch height texture and the patch alpha texture to produce a final texture to give to the Landscape Texture Patch:
Phew, we made it! 🥳 All that just to produce a landscape patch that nicely blends into the surrounding terrain. Now we can adjust slopes and see the results in real-time, which makes this whole ordeal so worth it:
Using these tools I was able to build out the main forest clearing area from sketch to a playable level to slide around in 4 days!
Thanks for making it to the end of this post! I hope this deep dive into creating custom landscape tools for Springbound was insightful! We covered how movement mechanics and level design work together, experiments with landscape editor tools in Unreal, and creating blended heightmaps from a mesh.
As a solo developer, any tool that helps transform ideas into playable prototypes as quickly and accurately as possible is a huge win.
Read the next post for a deep dive into a different part of the game:
PS: I didn’t touch much on using Unreal’s Procedural Content Generation (PCG) to lay out the trees, bushes, and fences that make up the forest in tandem with the landscape tools in this post. But there’s so much PCG content out there already that honestly, I don’t have much to add! Aziel Arts on YouTube is a great resource if you’re looking to learn more about PCG.
Amazing! This is the Death Stranding of cozy critter games.