00: Introduction
The first Procedural Note - describes the Procedure (video game development with generated + hand-crafted content) being Noted.
This is the first Procedural Note.
" Procedural Note " is " note on procedure " - in this case, video game development by way of procedural content generation techniques.
My interest in software development was and is rooted in a desire to produce complete and enjoyable video games. It's been stimulated by the many forms of procedural generation - the dynamic generation of content.
I've been thinking about just how (much) the second can be used to create the first.
These Notes'll be those thoughts expressed in terms of games I'll be developing and selling.
The first such game'll be..
Rampant on the Tracks.
Rampant on the Tracks currently only has a demo rooted in the concept of the random walk: https://jpshankar.github.io/rampant-on-the-tracks-random-walk-demo/
A random walk is a walk over a space of points such that a walker at point A, choosing its next step from the set of adjacent points S, could pick any point P in that set with equal probability.
It's a mathematical modeling concept best used when the thing you want to model can be understood as moving from state to state without being influenced at all by previous states.
The demo implements a semi-random variation, restricting next steps in terms of cardinal directions (North, East, West, South) + whether or not the prospective next step had already been visited by the walker:
const possibleNextSteps = possibleSteps.filter(
({nextStep: { widthIntervalIndex, heightIntervalIndex }}) => {
const wouldBePreviousStep =
gridStepsTakenSoFar.returnFirstOccurrenceIfFound(
({stepFrom: {widthIntervalIndex: fromWidthIntervalIndex, heightIntervalIndex: fromHeightIntervalIndex}, lineColor }) =>
widthIntervalIndex === fromWidthIntervalIndex && heightIntervalIndex === fromHeightIntervalIndex && lineColor === stepperColor
);
return !wouldBePreviousStep &&
widthIntervalIndex >= zeroBigNumber &&
widthIntervalIndex.valueOf() < numVerticalLines.valueOf() &&
heightIntervalIndex >= zeroBigNumber &&
heightIntervalIndex.valueOf() < numHorizontalLines.valueOf();
}
);
(See the GitHub repo for the full implementation.)
This behavior determination's procedural generation - it's not a decision tree, which would look more like " What's the distance from the starting point? If it's <= configuredStartingPointDistance, move in the appropriate direction facing away from the starting point - else, move towards. "
The latter is an accepted approach that produces behavior players can easily anticipate and react to. This procedurally generated approach does the same, with organic-seeming variations in behavior.
To illustrate this, here's one run of the walk demo with the walkers set up..

.. and with all walkers having come to a stop:

Each walker has traveled many steps from its initial state before reaching a P where all points in S have already been visited - an end state it can't progress from.
Let's look at how the red one got to its end state to illustrate the variation of this walk:
We'll start several steps in:

We can see Red having gone away from its starting point to the bottom of the space in an organic, inefficient way (steps 2-5 accomplishing what step 2 -> step 5 would've more efficiently).
We then see it go W..

.. go W a couple more times..

.. and go N.
The walker then goes E a couple steps..

.. then N, then W, then N again:

It finishes up going E, to its end state - a point from which it can't move any further.

We have seen the red walker progress from start to finish with novel variation in its progression - its taking the long way and nearly doubling back.
Looking at the states of the other walkers in the shots taken of the red one's progress, the player can talk about their progress towards their final states in terms of what they've learned from the red one:
- " Green's locking itself out of the lower-left corner.. "
- " Blue's locking itself into the upper-right.. "
- " Pink's going to have to head left and up to get anywhere.. "
.. but their talk is general. They're not confident enough to say " Green's close enough to its starting point that it'll move away " or " Blue's far enough from its starting point that it'll head back ".
That ambiguity there additionally engages the player - if the generated content works well with the hand-crafted parts of the game, the engagement will be positive. If it works poorly, the engagement will be negative.
How will Rampant on the Tracks demonstrate combining hand-crafted and generated content?
Well, Rampant on the Tracks will be a game about " walkers " being out of control (rampant) on their tracks.
The player's job will to get those walkers to their intended destinations by understanding the rules of their walks and then manipulating them accordingly.
There'll be both hand-crafted content - a narrative built around that - and generated content - the walkers and the strategies to manipulate their walks.
What'll the timeline for all this be?
Roughly within the following date ranges..
- 11/14-11/21: A more detailed explanation of Rampant on the Tracks' gameplay mechanics
- 11/21-11/31: Python tools for generating walkers and walks to solve (a generator and a solver that evaluates the generated output)
- 12/01-12/15: Web/mobile gameplay demos for playtesting/preview purposes
- 01/01/2026-01/31/2026: The process of releasing this game.
Subscribe to this newsletter if you'd like to keep to up to date with this and future projects developed with the same " procedural generation + hand-crafted " ethos!
(Or if you're just curious about the ethos. Or if you're just curious.)