Shrooms: HDRP in URP

The Shrooms demo runs on Unity’s mobile-friendly Universal Render Pipeline (URP), which doesn’t support volumetric fog and lighting like the High Definition Rendering Pipeline (HDRP). An early design decision was to lock the camera to only about 20 degrees of rotation off the default view axis. This allows many computationally-inexpensive (oldschool) cheats and tricks to create rich atmosphere. My mantra was: “HDRP in URP.”


 In the Shrooms world, lightbulb is a job. Every light source is a glowing, bioluminescent mushroom person. The Copenhagen-inspired strings of street lamps that draw the viewer through the level each contain an animated Bulb Guy (created by Niek Meffert) sitting in a little wire gondola underneath a beat-up reflector. It’s a living.

He/she, and the remainder of the lamp, are set to not cast shadows, and contain a downward-facing  Spot Light. There are 37 in all, in addition to a wan Directional Light sun from the left—which is a problem, because Unity’s URP has a hard limit of 8 lights per mesh. The Unity Terrain tool splits the ground into a couple dozen smaller tiles, but the initial result was most of the light sources being simply ignored by the ground mesh, and glows often visibly sliced off where they crossed tile boundaries. Baked Lightmaps and realtime lighting in URP both share the lights-per-mesh limit.

Quick & dirty normal map in Photoshop: Filter > Other > High Pass, Filter > 3D > Generate Normal Map

The solution was to place pieces of flattened human-world junk along the ground, to disguise the boundaries and ensure that every light creates a visible effect. The junk shader uses a Texture stitched together in Photoshop from derelict building photographs, with a rough Normal Map.

Like the noise functions, the Texture is applied in World Space, allowing the same low-res crumpled square of debris to be recycled, stretched and resized ad-nauseum, with the Texture remaining undistorted and matching up perfectly at object boundaries. I’ve been a big fan of using world space shaders to create visual variety in instanced models since The House of Time–which, yes, will finally get some big updates this summer.

Simple exponential-squared Distance Fog ties the effects together, creating additional depth, and a Bloom post effect softens the edges of windows and other bright objects to match. A Depth of Field post effect further softens objects in the extreme foreground, adding to the murky intimacy, and the deep background is a hand-painted backdrop by Natasha Beck in an Unlit Shader.

HDRP in URP: A mix of simple, oldschool tricks and modern GPU-driven effects.

Faking Volumetrics

 It’s a not-so-dirty not-so-secret that even in high-end film compositing software volumetric lighting is faked by slicing the camera’s Z-axis into stacked, transparent planes at render time. This is what Shrooms does manually. Using the limited camera view and careful placement, patches of fog are created with a shader on a small stack of transparent planes. The shader multiplies a half-circle gradient alpha Texture with a procedural noise function. The noise slowly migrates up the Y-axis, as if mist were rising off the swamp. The noise is generated in World Space, so that scaling, squashing or stretching the fog planes creates no distortion to the noise pattern.

Light glows work the same way. Each light fixture model contains a set of three  planes: Two larger, colored, more transparent ones in front and back, and a smaller, more opaque, white plane in the center. The alpha Texture is a narrow cone gradient, aimed downward, and the World Space noise function slowly falls, like misty drizzle. The bright spotlights in the arena and cafe are just variants on this scheme, and a circular glow is used in a couple of additional spots.

Shrooms: Color & Forms

In Niek Meffert’s concept for Shrooms, giant mushroom people battle giant plant people in their swampy homeland, while grinding the remnants of humanity under their figurative boots. The dev team was Meffert, Lucas Oliveira, Sabrina Christiansen, Kaspar Dahl, Natasha Beck, and myself as Lighting Designer and Technical Artist. You can check out the demo (Mac & Windows) on here.

Frequently heard during environmental modeling: “It’s good, Sabby. Get rid of the straight lines.”

The objective was to create a bright, colorful, murky, fungal setting. Fungus suggests bright, “sickly-sweet” tertiary colors, and we wanted an organic, lively scene. However, with too much clashing color the scene would have become busy and unreadable. Just finding your way and knowing what to interact with would have meant a frustrating cognitive load.

For that reason, I worked with the team to enforced certain rules to control user attention. The main character is in complementary colors. The bad guy’s color palette is a high-saturation split complement. NPC characters each have a single, dominant color. Non-interactive parts of the scene favor muted, analogous colors.

Lighting rules were also held to. Unimportant parts of the level fall back into mist and shadow. The character path is comparatively well lit, always suggesting where the player can and can’t go. Interactive parts of the scene (usually just-for-fun destructibles) pop comparatively, while others harmonize.

Forms avoid straight lines, with blobby, asymmetrical and impractical shapes but—importantly—recognizable outlines. Classic Warcraft games, and the art of Chris Sanders (Lilo & Stitch) were strong references here.

And of course, what’s the point of a game without asshole physics?

Oh Steam…

Kubrick twist: Searching Steam aliases is notoriously broken! This seems to be a known issue that’s been causing consternation for half a decade. Specifically, aliases with trailing numbers (e.g. spacetoast123) are unfindable with the exact string, and usually with a partial string.

So, while I’ve been able to send a friend request to the Second Prize raffle winner ($25 USD), who has no trailing numbers, nothing I’ve tried has brought up profiles for the First and Third Prize winners ($75 and $25, respectively).

If you entered the raffle, and your Steam alias ends in numbers, please friend me via my public profile page: Over 300 hours of Civilization VI? Yes, it’s a problem. Regardless, you may have already won! I promised not to post handles publicly (and creating a duplicate with the same alias seems quite easy) so winners can’t be directly announced.

Bottom line: If you ever run a stunt like this yourself, even though it might make you look spammy, get an email too.

Raffle Code

As promised, I’ll be raffling off one $75USD Steam digital gift cards, and two $25 cards shortly. Just to be super transparent, here’s the raffle code.

And no, I’m sure mathematically this wouldn’t hold up in a real lottery–but for a raffle with fewer than 20 valid entrants, I think we can call it good.

function rankRaffleEntrants(){
        var entrants = "Prima Secunda Tertia Quarta Quinta Sexta Septima Octavia Nina Decima"; //Steam handles
        entrants = entrants.split(" ");
        ol = document.getElementById("orderedList");
        //print function
        function addToList(entrant){
          var li = document.createElement('li');
          var nextInList = document.createTextNode(entrant);
        while (entrants.length>1){
          var pick = Math.round(Math.random()*(entrants.length-1));
          var entrant = entrants.splice(pick,1);

Basilicum on Reddit – Raffle Extended!

Within the hour, I’ll be posting a Unity WebGL game to Reddit, in hopes of collecting a statistically meaningful sample of responses to a questionnaire. In addition, through Tuesday, June 8 at 22:00 CET I’m conducting a raffle to encourage participation. This could go wrong in so many ways, and only right in one.

The characters’ anxious hand-wringing is my own.

Edit: The raffle is open! Click here to play the test app.

Performs best in Firefox and Chrome. Feel free to play the game as much as you’d like, but please only submit one survey form.

Terms and Conditions:

Persons over 18 who submit the survey between Friday, June 4 at 22:00 CET and 22:00 CET Tuesday, June 8, and enter a valid Steam profile name will be eligible for a raffle, to be conducted by June 20th, 2021.

-One first-place winner will receive a $75 USD digital gift card, sent through Steam.
-Two runners up will receive $25 USD digital gift cards, also sent through Steam.

The winners will receive a friend request from my Steam account, “rhinocrate” and receive their digital gift cards as a friend-to-friend gift.

I wish it weren’t necessary to say, but I must reserve the right to disqualify participants based on evidence of ballot-stuffing or other forms of inauthentic or abusive behavior. There is a limit of one entry per person. Steam accounts must have at least one purchased game to be eligible for the raffle. If fewer than 20 valid responses are received, the raffle will be cancelled. No data collected will be used by me or anyone else for any purpose beyond tabulating results and completing the one-time raffle, nor will personally-identifying information (including IP addresses and Steam account handles) be distributed.

Hacking Twine: The Multiplane Effect

For Chronovoros, I created a Twine hack using custom macros inserted via Chapel’s Custom Macro Framework. These interact with the game’s custom CSS styling by adding foreground and background image elements. The image files,  indexed-color PNGs with a 1-bit alpha channel, are crushed down to surprisingly small file sizes for their resolution. (GIF would be just as useable, with interesting implications for animation.)

A layout for the different planes of one “scene” in the game, color-coded

Each set of images has its own macro, which when called passes a list of the desired image filenames and styling to a function which displays them. The images are scaled to fit the width of the window, and positioned to align either their top edge to the top of the viewport (the entire scrollable content of the page) or their bottom edge to the bottom of the window. An additional function is called every time the window paints (started by a call to its own macro on the first page of the game) which adjusts the vertical positions of the planes based on user scrolling; the vertical positions are calculated so that whatever the height of each individual image, scrolling completely from the top to the bottom of the window displays the entire image.

In practice, the multiplane hack breaks when the window is too tall. An aspect ratio should really be enforced with some kind of letterboxing scheme in the CSS. Having to write and call an entirely new macro for each set of image planes, while not complicated, is a little inelegant for a production-ready tool. Additionally, HTML5 special effects like contrast, color adjustment and blurring are implemented, but didn’t end up used on Chronovoros. Knocking the multiplane hack into something easier to use would be a good weekend project, for a later date.

Click here to download demo files and code for the Twine Multiplane Hack.

Chronovoros: A Multiplane Graphic Novel

The Nordic Game Jam 2021 is over and–as far as I know–everyone survived. My team set out to make a “cinematic text adventure” you can play in your browser. Which wasn’t totally a thing, so we had to invent some stuff.

The theme, announced at 6:30PM Friday, was “Pending.” (Yes, you can imagine the initial confusion!) We had the story, setting and characters in rough form by mid-morning Saturday. All five characters were designed, the outline was running in Twine, my basic multiplane hack was running, and I had some of the layouts sketched out by the end of that day. (Around 1AM, for all of us.) Sunday was a sprint to get the temporary artwork replaced, layers assembled and compressed, story finished, and the bugs squashed. We got it submitted at 4:50PM Sunday–10 minutes to spare!

The story and interactive logic were written by Sejr Thompson. The character design and other hand-illustrated art were by Alexander Pechlivanidis. My own role was twofold: Designing the layouts–in an animation sense–of the independently scrolling background and foreground art layers, and hacking the Twine text engine to display them.

It’s a jam game, so there are a few rough edges, but not half as many as you’d expect. Reviews so far have been very good. Check it out:

Play Chronovoros on

The High Arctic: A Story World Pitch

View as PDF

A story world pitch deck for Alex McDowell’s “Planet JUNK” collaboration. 500 years after the collapse of our civilization, an admixed tribe live an Inuit lifestyle in northern Greenland.

Destroying the world in 30 years is depressing, but this isn’t my first time down this philosophical road. God kings and abject despotism have held civilizations together for thousands of years–many times longer than democracy. Tribal-scale survival for hundreds of thousands of years.

The horror writer must look where they don’t want to. I feel that we understand, on some level, how fragile our current civilization is. With rare exceptions, we dress up collapse stories to make them more palatable–as Romero zombies, as alien invasions, as fantasy-science-gone-amok.

As dark as it was at times, I wanted to look at a downscaling of human life, and find some beauty and hope in our own survival.

14th Century Funeral Monument

Illustration commissioned by History Live! North East for an intriguing history project: To 3D print a life-sized sculpted knight’s tomb.

English funerary effigies like these began to be produced in the 14th Century in immitation of the Continental style, with locally-sourced alabaster in place of imported marble. According to Rachel Dressler, the waxy translucency of the stone was prized for its immitation of flesh, and “spiritual aura” in the light. History Live! North East is working with the University of Maine to create a modern reproduction of such a monument as an educational outreach tool. Sponsors (and I must recommend becoming one) can see their own coat of arms added to the base of the sarcophagus.

The Lighthouse Keeper

Among any number of negative habits is my tendancy to come up with an idea out of desperation at the last minute, play with it for a little while, and then fall in love and want to dump six months into it. Class workshops on different aspects of game design usually trigger this problem. This one is no different. (See also a simple RPG I’m trying to get working in Tabletop Simulator.)

As boring as it sounds, being a lighthouse keeper was as much about lifesaving as shipwreck prevention. A certain solitary type seems to have been attracted to the United States Treasury’s Lighthouse Establishment/Board/Service between 1791 and 1939 (which I think we can agree encompasses the “Golden Age” of lighthouses). Hoisting a dory into four-meter swells from a flooded gear room at the base of the tower in a pitch-black howling gale was a job requirement, and having a sturdy dog with sharp senses and no fear of the water along wasn’t all about companionship. (“Saved,” from the Louis Prang Collection commemorates a real lighthouse dog’s rescue of a child.) Denis Noble’s Lighthouses & Keepers is a good intro to this world.

I’m attracted to the character of an Indian man serving as a keeper sometime around the turn of the last century–someone like WWI US Army Sergeant Bhagat Singh Thind, who under the racial ideas of the time tried and failed to gain US citizenship when the Supreme Court ruled that, while “Aryan” he was not “white.”

I envision an adventure game made up of episodes (equipment failures, hurricanes, shipwrecks) with free exploration segments before the crisis portion triggers, in which you wander the lighthouse with your dog, read water-damaged books (real ones) about “race science” and other odd but consequential ideas for your character’s situation, and maintain the equipment. The offshore lighthouse serves as a metaphor for your own situation, literally defending a shore you can never reach. In these quiet moments, most of your default push/pull interactions are small acts of cleaning and maintenance (and scritching your dog). I want to make you complicit in the feeling that you’re constantly–even lovingly–maintaining this life-preserving tower.

In truth, an offshore lighthouse was manned by a crew of 3-4. Many keepers were married, and raised families at the facilities. The “solitary” aspect would be a departure from strict historicism–though sickness, injury or just plain poor manpower planning could easily leave a single hand to run a light. It was a quiet and hardworking life, though vastly superior to the sailing trade most keepers left.

I’ll leave you with this cutaway of Britain’s Eddystone Lighthouse, and an 1892 magazine article describing a visit there. It’s a fun topic to get lost in for a few hours. But for now, I think it’s best I leave it at that.

Tiny Convoy: Scaling Back

It was always an ambitious project, and not everything made it over the finish line.

What Got Cut

Glowing=on made it into the game, but no useful HUD feedback

UI Feedback: There’s a lot happening behind the scenes that the game doesn’t explain well. Every “CPU” (the brains of the robot, but also a physical robot part in the game) has randomized stats: Processing, Memory, Inputs and Outputs. These special stats aren’t altered by Upgrades, but they can be boosted by being close to (“meshing with”) nearby robots with higher stats. Processing governs how often an AI-controlled bot can reevaluate its choices. Memory is how much you can’t see but can “remember”–the fog of war. Inputs allow you a certain number of sensors you can equip. Outputs allow a set number of moving parts you can control. Likewise, damage isn’t well described, although your damaged parts do noticeably work less well.

Multiple “Car” Robots: Everything the bots do is designed around being able to take up more than one tile, dragging parts behind like train cars. Sadly, none of this made it into the final game, making even the word “convoy” seem slightly out of place. Bots sitting on top of other bots, and being carried along is–as best I can tell–entirely possible even in the demo build, but without trailers there’s not much point to it. So, no, we don’t get to play Tiny Convoy: Fury Road.

The Conversation Grid: The idea was to coordinate with your convoy without using words. You’d click on a friend and their internal map (from the Pathfinder) would come up as a grid of little icons. You could click on things to give them “ideas,” or to dissuade them from doing something dumb. It would have fed into their AI, not as a command, but as one of the AI’s competing ideas, with a boosted weight–sort of like the forgotten but brilliant “Galapagos.”

That Said…

Tutorial subs came very late in the design process, when it was clear playtesters couldn’t understand much of what they could do in the game–breaking design pillar #1

There is the start of a fun little game here. The many interacting systems largely work as intended, and cross-talk in interesting ways. The whole visual and audio presentation is inviting and detailed. With more content, fine-tuning and iterative playtesting, this could easily become a very good game.

But, on to second semester!

Tiny Convoy: Systems Programming

Since I was mostly the programmer, I’d like to look at some of the systems that make the game engine work. But first…


For me, what made this game possible was an email exchange with Michael Schmidt at Unity, in which he cleared up something critical. Since Unity regards every script as a different C# type, how can you subclass a script into different variations? More specifically, how can one script interact with another when it doesn’t know if it’s the class, one of the subclasses, or one of the subclass’s subclasses?

Crunchy McCrunch-Crunch

The key is that Unity will treat a subclass script as if it were any class up its chain of inheritance. When I subclass ActualThing into Upgrade, and Upgrade into Sensor, other scripts can reference a Sensor script as if it were an Upgrade script or an ActualThing script. So these lines are equivalent:

float currentMass = someGameObject.GetComponent<ActualThing>().mass;
float currentMass = someGameObject.GetComponent<Upgrade>().mass;
float currentMass = someGameObject.GetComponent<Sensor>().mass;

A Sensor script can then override, for instance, ActualThing’s takeDamage() function, and respond to it differently than, say, a rock would:

//in ActualThing:
public virtual void takeDamage(float damageAmount){
     //reduce hp
//in Sensor:
public override void takeDamage(float damageAmount){
     //reduce hp
     //reduce sight distance

This is how basic object inheritence patterns can be implemented in Unity.


The Grid: The first programming challenge was an infinite, non-repeating grid. Based on my previous thinking on large pseudorandom world generation, I worked out a system that places BigTiles (containing a 10×10 grid of normal game Tiles and other content on top of them) from a list of available BigTiles. A given x and y will always generate the same BigTile, allowing the game to dispose of BigTiles it no longer needs, but generate them again if needed. Each game picks a random x and y offset to the starting position–a pair of C# ints of value -2 billion to 2 billion. The x and y offsets are summed and used as another pseudorandom seed to further shuffle things around atop the BigTile. The list of available BigTiles changes based on the distance from the game’s starting point, allowing the game to gate more powerful and challenging content. Specific BigTiles can also be forced to appear, like the starting location.

Lots of stuff, not-quite-randomly generated

Pathfinding: The bots use an A* pathfinding system. Niek worked out the initial code, and I adapted it to allow planning without executing the route (for AI reasoning) and to talk to the existing grid-based systems. This required a deep dive into Amit Patel’s A* Pages, a deep summation of pathfinding systems, which I highly recommend.

AI: The bots not being driven by the player have competing desires, to which they assign weights based on need and availability of a solution. The highest weight wins. They may reevaluate their options several times on the way to their goal, but the current “plan” has a sunk-cost-fallacy bonus attached, to reduce indecisiveness. The AI can query the Pathfinder (a separate script) for the “cost” of a path; it will also store the steps needed for pathfinding, to avoid a processing-heavy path recalculation for the action it ultimately decides to take.

I grew up calling them that; turns out they’re “Touch-Me-Nots”

Mystery Boxes: Remember how every BigTile has its own pseudorandom seed number? MysteryBoxes are a system that uses these to “randomly” shuffle things around on BigTiles when they’re generated–plants, upgrades, whatever you’d like. The plant growing on top of a toppled monument? That’s not scripted. One limitation is that if something on a BigTile gets destroyed, it’ll reappear if the player ever goes far enough away and comes back. A special subclass, the CPUBox, will generate a new CPU (the base of a new bot) if your party is smaller than the allowed size, or a random Upgrade if not. Like other gated content, the maximum number of party members increases with distance from your starting point.

Class flowchart. Always out of date.

Tiny Convoy: Plan

“Tiny Convoy” is as a demo-length convoy simulator–a moving base builder–developed in Unity 2019 by Niek Meffert, Lucas Oliveira and myself. Playable betas for Mac and Windows can be downloaded here. The goal is to survive as a group of tiny robots in a big dangerous world: find power, upgrade your bots, and avoid dangers.

Remember the annoying escort missions in “Warcraft III,” where your soldiers kept hauling off to attack anything that moved, instead of protecting the things they were supposed to? It’s like that. Except your bots can’t attack anything. You are essentially robot herbivores. Looked at another way, “Tiny Convoy” is a herd simulator.


As a small team in our first year Masters, the work was loosly siloed. Oliveira took the lead on modelling and texturing, Meffert was point on UI and the first version of the A* pathfinder, and the C# code base is about 90% mine. (I also designed the Touch-Me-Not exploding plant.)

1. Emergent visual storytelling–no dialogue, no scripted beats
2. Keep moving & exploring
3. No weapons
4. Cooperation is essential to survive & thrive

Design Pilars

Our goal was to marry emergence and progression in an interesting and satisfying way. We wanted to build a game in which the player could create in their own mind an emergent storyline around an algorithmically-generated world. If the content one encountered became too boring and undifferentiated, there would be no sense of progression, and little incentive to keep exploring. On the other hand, if too many things were deliberately laid in the player’s path at defined points, it would take on the feeling of an “on rails” story game, to the detriment of replayability.

Concept sketch

Every “Civilization” player remembers when the Mongols took their capital, and they rallied back to win. What happened was only the randomized game content interacting with the rules and the player’s choices, but it took on the quality of a narrative moment because it was different and valued by the player. Likewise, we wished to create moments like “When Little Blue got stepped on,” and  “When we found the field of Touch-Me-Nots on the other side of the desert”—moments created entirely by the game systems interacting with the player’s choices, but which would feel personally meaningful.

The game loop for Upgrade Mode

 To do this, we needed to construct a series of game loops, with systems of player feedback. We would gradually challenge the player by introducing limits on stock (not enough power available) and new sinks (dangers that damage parts). The game engine would introduce new content and changes to the starting conditions in a measured manner as the player moved farther and farther across the game world.