mrspeaker's head in a monitorYou find yourself at the entrance to the Hompage of Mr Speaker. In a darkened corner sits a trunk containing HTML5 games and some JavaScript tidbits. In a dark corner you spy a Twitter account. Exits are North, East, and .

?> _

Farm to Table: A postmortem

You have 48 hours of adventuring time in a country you've *never* been to, and *may never* return. By random chance, There is a 48 hour game jam happening simultaneously. A sacrifice must be made: the game or the experience? Choose wisely.

...

Trick question! You can do both, poorly! Welcome to my Ludum Dare 43 entry for the theme "Sacrifices must be made". My game - Farm To Table - has you training your workers, breeding them to improve, and possibly grinding them up to make the tastiest burgers in the business!

Farm to Table

The gameplay centers around selecting the lil' workers from the queue and assigning them to different tasks: farming, cooking, breeding, and, well, getting crushed into mince meat.

Through careful breeding you can create better cooks and farmers. But here's the rub: Thanks to their superior breeding, the best workers are also the tastiest! Naturally, the people in charge - the "steakholders" - require profit$ (and therefore burger quality) to be continually on the rise. Your business must maintain its status as a viable investment target.

("Here's the rub" is a thing people say, right? Sounds weird.) Anyway, that was supposed to be the idea. A difficult-but-enjoyable balance of inputs, transformations, and outputs.

In practice I ran out of time for the vital "balancing of the systems" part. So you are able to transform the inputs, but the outputs have exactly zero impact on the next round of inputs when they feedback. You can't actually make better burgers. In fact, your profits-from-sales aren't even tracked at all. Oops.

Still, I was pretty happy with the result. In Ludum Dare there are thousands of games for the players to rate. I figured that as long as it was fun-ish for players to try and figure out the controls (and the rules of the game) then it would still be ok. And really, most people won't play long enough to realise that there is no goal anyway!

48 hours earlier...

...It was late Friday afternoon when I learned that LD would be commencing shortly. That was tempting - but there was no way I could justify wasting the entire weekend holed-up in my hotel room, instead of exploring my new surroundings in a beautiful new country... Could I?

Then the theme was announced. It was a good one. Plus, it was dark and cold outside. Certainly not a night for exploring. I'd just tinker on something for the evening, then start my outside-adventuring in the morning.

By the time morning rolled around I had yet to go to sleep. It seemed wise to put off adventuring - at least until the afternoon.

My Ludum Dare plan was to build a simple "economy game" because it's something I'd never done before. The thematic inspirations emerged from one of my favourite movies (Soylent Green), and one of my favourite Commodore 64 games (Mad Doctor).

Soylent Green, and Mad Doctor

The economy

Economy games need "sources", "syncs", and a way to transform them. In my economy, the sources are people and the syncs are the conveyor belts that create the burgers. You can transform the statistics of the inputs by breeding the best "outputs" to make even better "inputs".

To stop an uncontrolled positive feedback loop, it's required you sacrifice your best workers in order to create the tastiest burgers.

napkin sketch

Although it wasn't all implemented, the final product turned out pretty close to my back-of-the-napkin sketch: so I'd say that was an achievement earned!

Building it

The build process began with a rough mock-up of the playfield in Aesprite. This was just a horribly rushed effort that would be replaced with real graphics later (spoiler: in Ludum Dare there is no "later". The graphics remained unchanged).

I liked the Mad Doctor style, and I also liked that it wouldn't be Yet Another Grid-based Game like nearly all my past Ludum Dare entries.

The game library? Phaser 3

To turn the image into something playable I decided to go with Phaser3. Normally I like to use my own engine, or even start from scratch - but I'd been wanting to see what's new in Phaser and this seemed like a good way to find out.

Phaser takes a PHP-style kitchen-sink approach to API design: just add every feature you could possibly think of. Before you bother building something be sure to search the docs and see if it isn't already included out of the box. It might seem a bit in-elegant at times, but at 4am in the middle of the jam I was glad I didn't have to roll my own Phaser.GameObjects.RetroFont routine again.

Using unfamiliar tech in a Ludum Dare is usually asking for trouble, but in this case I kind of knew Phaser2 - and my game wasn't doing anything too crazy - so it turned out fine (frequent grumbling about documentation and mystery-meat factory methods aside).

Look ma, no build tools!

I also wanted to make this game using plain ol' JavaScript. Well, plain new JavaScript at least. No build tools, no compile step, no traspilation, no npm, no dot files... just some HTML, a bit of CSS, and [a bunch of JavaScript files](https://github.com/mrspeaker/ld43/).

Farm To Table JavaScript

This isn't as stupid as it sounds anymore, now that JavaScript Native Modules are supported nearly everywhere (even iOS and Android browsers). My only issue was that I only had Phaser3 as an old-school script file that would normally be included via a script tag, and be available as window.Phaser. To make it a bit nicer in my project I exported the object from another file:

import "./phaser.min.js";
export default window.Phaser;

Which allowed me to use it in my project like a regular import:

import Phaser from "./lib/phaser.js";

There's something I really like about the simplicity of a "plain-old-project". I love knowing that I will be able to run (and tinker with) this project in 10, 20 years time (like my first ever browser game, Some Adventure Guy, from 14 1/2 years ago!) - without having to try and resurrect some long-dead build tools and dependencies.

Day/Night II

Thanks to an extended nap on Saturday (coupled with the crazy-early setting of a northern-hemisphere winter sun) I missed out on any real-life day-time adventuring. I did, however, get a system working for clicking and dragging my lil' peeps to the various sections of the world. I decided to write off Saturday as a no-tourist day - I'd get outside tomorrow. For sure.

In the mean time, I had a passable version of "conveyor belts" working... this was achieved by assigning a conveyor-belt-ish animation to a sprite after it was created. There's absolutely no logic - just an animation that moves it to its correct spot if nothing else is removed. So multiple items will often overlap and look bad. This bug was then placed on the "fix later" pile (spoiler: never fixed).

Hotel Foley Artistry!

After adding the meat-grinder mechanic (and successfully pushing out a few cooked burgers) I decided to take a break from coding and do 15 minutes of sound effects. This turned out to be my favourite part of my LD entry.

Normally I make the sound effects and music on my home studio setup: some midi gear, Ableton Live, and all of my plugins. Being on the road I had none of my usual sound-making arsenal, so some improvisation was necessary!

A hotel shower, an apple, and a good old-fashion mouth-pop resulted in the horrifically-perfect and unsettling sound effect. The rest of the audio: music and sound effects - were done under extreme time pressure, moments before I submitted - and were crap. But the bone-crushing grinder sound effect was perfect!

The final countdown

By Sunday I'd all but given up on sight-seeing and had gone all-in on Ludum Dare. But there was an issue: less than 6 hours remaining and the project was in a bad state. The controls were completely un-learnable, the burger-making progression system was overly complex and opaque, there were no instructions, and everything was absolutely confusing to anybody who wasn't me.

Sensing the train-wreck ahead, it was time for a sharp detour.

I would sacrifice the entire point of the game in order to have something that might possibly be "confusing-but-in-a-good-way" for new players. As long as it was kind of fun to figure out the controls - the player would feel a bit clever, and hopefully not notice there was no actual game. That was the new plan.

Ruthlessly I ripped out the mechanic that defined the game: being able to manually adjust a worker's stats using XP points you earned by cooking tastier burgers. By doing this, I could greatly simplify the control system. Now "hover" would display stats and single-left-click'n'drag would move workers. That was it.

I asked a stranger at the hotel cafe if they would kindly test a game where you mince up people into meat patties. They were surprisingly happy to help out, and they fairly quickly figured out they needed to drag and drop the little people around. The simplification had worked, and I had something passable!

And there was still two hours remaining in the competition. Plenty of time to re-balance the game by tweaking the breeding system, and reworking the burger-ranking system I tore out earlier. I could see exactly what I needed to do to make the game playable!

But sacrifices must be made.

Although it pained me to stop so close to the finish line, I made a tough executive decision. I would use the last two hours of weekend daylight - sacrificing the last two hours of Ludum Dare #43 - to traverse a breathtaking suspension bridge, that crossed a giant ravine, leading into the heart of a wonderland rain-forest. I'd be tourist.

I submitted the game, pushed my code to GitHub, and jumped in cab...

In conclusion

The final product was not really a game, it wasn't very polished, it didn't have good music, it wasn't particularly fun to play... but it was one of my favourite Ludum Dare entries so far.

I loved the weird graphical style, the hand-made sound effects, and the general "oddness" of it. I had an idea of what I wanted it to be, and it turned out pretty close to what was in my head. In the end it was the gamedev equivalent of jazz music: I had more fun creating it than others will have consuming it. I'm fine with that.

So, was my sacrifice (giving up a once-in-a-lifetime weekend of adventuring) worth the stress and panic of trying to make a bad game vaguely playable at the zero-hour? Who can say... but see you for Ludum Dare #44!

Oops, forgot about you

14,000 pending comments

I may have forgotten to maintain and update the ol' mrspeaker.net. Sorry about that - I'll get right on it!

These are my Emacs days

I've been using Atom as my primary editor for several years now. But recently there's been a tidal wave of support for VS Code. It swept through the tech industry and washed away Atom and Sublime and friends. I figured it was fruitless to fight the trend, so I switched to Emacs.

Emacs. Emacs

Now that I reflect on it, it's been a long time coming. From early on I suspected it would end this way. Somehow I intrinsically knew it would eventually happen.

It happened.

Me n’ Carl Sagan hand-rolling some WebGL2

Imagine, if you may, an apple sitting happily on your desk. One day, and in a manner causing much confusion to our apple friend - you wrote some weird WebGL2 thing from scratch. From the apple's perspective, it might look something like this.
Carl Sagan in a WebGL2 cosmos
However, from a source code's point of view it would look more like this.

Space.

Popcorn kernel bread ™

It is, with no doubt, the greatest idea I have ever had: bake bread with a bunch of popcorn kernels in it.

This idea... it's just... it's by far better than any other idea on this blog. It's better than my Kentucky Fried Chicken Feen from 2005. It's better than my BASIC revelation from 2015. As far as ideas go, it's just about the best there is. The best I could hope for.

It doesn't work though. The kernels don't want to pop. I'm not sure why, but here's how it went:

1. Bake bread

Since taking up the challenge of catching wild yeast in my house, trapping it in a container, feeding it after midnight, then harnessing it's power to convert boring old flour into delicious leavened sourdough - I've began wondering how I could push the limits of this ancient art form.

Adding popcorn kernels was the answer I came up with.

2. With popcorn kernels in it

popcorn kernel bread dough

I mixed in a handful (a bit more I guess) of kernels in to my active-starter-powered dough, and mixed them in thoroughly.

risen popcorn kernel bread dough

Once the dough had risen (~7 hours), I baked it in a cast-iron dutch oven, inside my extremely hot oven set to as-high-as-it-can-go... Then I waited for the fireworks...

3. Wait for the fireworks

baked popcorn kernel bread

Some time later, beautifully-browned, delicious-smelling, sourdough bread. Perfect in every way bar one: it was filled with un-popped popcorn kernels. Not even those on the outside of the dough went out with a bang.

A second great idea arose from the ashes: how about toasting the bread with the still-intact kernels? Could it maybe, possible, maybe give us some kind of interesting result?!

3. Wait for the fireworks

toasted popcorn kernel bread

No, it couldn't. The kernels were inert. Why they refused to pop in the oven, I can not say. In fact, I have not tried to analyse possible reasons, or develop alternative ideas for overcoming these reasons - because of my deep deep disappointment. Also my laziness.

Still... such a great idea.

[UPDATE! I received this great suggestion from Snaptastic (but have since temporarily removed comments, so I'll just post it here!)]: This would be so great!! Try wrapping a kernel in foil next time. And be careful not to eat it. If it pops,then you know it’s a sogginess issue. If not, then might be a temperature issue. I read somewhere that kernels shouldn’t be completely dry since they rely on steam to pop. If it’s a sogginess problem maybe you could coat the kernels in oil first? We need to get to the bottom of this!

ES6 (ES2017+) module support

It's been a long time coming, and we're still on shaky ground - but native module support is close. Not "burn your build tools!" close, but "burn your build tools for personal projects!" close... like arrow function syntax in 2013. If you have Firefox Nightly, or Safari Tech Preview (or Edge, I believe!) - you can give Babel a nice kick in the guts, and get back to some plain ol' JavaScript + HTML + CSS.

At the moment there's a couple of differences from the import syntax you know and love: first, your entry point needs to be a script tag from your HTML file:

<script type="module" src="main.js"></script>

Additionally, you need to add the file extension as part of the import path:

import test from "./test.js";

Notice the ".js" on the end there? Required. This means we lose the "default to 'index.js'" for importing just a folder path:

import test from "./test/index.js";

(Rather than the nicer import test from "./test") Still, I'll take it! Module support is enabled by default in Safari Technology Preview and can be switched on in Firefox Nightly in about:config under the key dom.moduleScripts.enabled - which default to false.

Building geometry with fraggles

My last experiment got out of hand and now the cubes have become self aware. See for yourself!



The earlier "lil cube" example worked by creating individual box meshes and adding them to the scene. This is not a very scalable approach if we want a lot of boxes! Creating a single chunk of 16 x 16 x 32 blocks would take about 20ms to create: More than a single frame at 60 fps, and way too long to do anything dynamic.

Then next thing I tried was to merge the boxes into a parent geometry, rather than adding each mesh individually. This did indeed give a performance boost, with each chunk only taking 5 to 10ms to create. Good, but still pretty slow.

Finally, I went all in for building the geometry myself. Using Three.js's BoxBufferedGeometry as a base, I wrote a function that would create the entire geometry for a single chunk. Each plane is added to a BufferGeometry - excluding any planes that would be obscured by a neigbouring box.

To work with Multi Materials (so you can have a different texture for each side of a cube) I had to split the creation into faces: rendering all the "top" faces first, then all the "front" faces and so on.

The result is a ~1ms render for most chunks on my machine: getting up higher with very complex and hole-y chunks.

Lil’ cube-y thing

Just adding something before the new year. Gotta get those posting stats up.
Lil' cube-t thing!

lil cube-y thing

Made with three.js, quick-sticks. Source of course.

Horizontal Rulez! for your terminal

Horizontal Rulez!

A handy script for your image-enabled (I'm looking at you, iTerm 3) shell. hr will spit out a random horizontal rule, straight from the depths of a GeoCities page. Good times.