I put together this halftone shader effect in Blender earlier today:

The key realization for me was that Blender's shader nodes allow you to use Diffuse BSDF or other shaders as inputs to your setup. This means we can take the lightness of our mesh and use that as an input to a color ramp with a step function in it. In more detail, here's the shader setup:

I'd wager a more skilled artist could replace the dot-pattern generator with something that gives more consistent result and doesn't have that semi-circular banding issue. Give it a try and let me know if it works out for you.

The Martian atmosphere is a curious pain in the ass. It's thick enough that it causes aerodynamic heating, but too thin to be practical for a parachute or breathing. It's a younger sibling that exactly dances the line of what's allowed.

The whistling at the edges of our ship turned to a full roar as it oriented itself in a precarious, almost upright position that maximized its exposure to the wind. Its skin started bleeding liquid methane to offset the increase in temperature from the compression. After our surface speed had dropped below Mach 4, the landing thrusters engaged and we began the vomit-inducing intermittent backwards fall. We'd all seen the landings in videos of yore. Two beautiful points of light transform into ivory towers that gently set themselves on the ground. It had come a long way since then, control systems growing ever more robust and formally validated, flow control and combustion systems becoming more powerful and lighter. Still, the turbulence of the Always-Toeing-The-Line-Fuck-You Martian Atmosphere made the landing computer work like mad and kept our eagle-eyed pilot, Thompson, glued to the terminal.

Slowly, quickly, slowly, gracefully, gently, eye-poppingly, we eventually landed with a delicate thud on the Red Planet. In an instant, the bitterness and irritation that came with a six month road trip fell away and I was reminded of the impossible wonder of what was about to happen. This was everything we'd spent our lives trying to do and, against all odds, we were the first to make it to Mars and survive.

There was a moment of quiet celebration between the three of us as the engines wound down.

"Mission Control, this is Thompson. The Eagle has landed. Current telemetry has us just shy of 3.1 km to the landing site. Fuel consumption was 2% below predictions. We're sitting pretty. Ready for EVA."

We were short of the target site, thank goodness. Perseverance Valley, the final resting place of Oppi and Xia Yibu (下一步), the Chinese Lander. Perseverance Valley is unfriendly, and overshooting our landing site would mean going sledding down the side of a mountain in a government-issue rental rocket. Mission Control would be very unhappy. We would be fine, if slightly dead or dying and on fire.

They nearly beat us. China had been hiding their heavy-thrust and high-payload rockets for nearly two decades, and they didn't announce their intended landing on Mars until someone forced their hand by leaking the story. I suppose they wanted to wait until they'd succeeded? No matter, because of all the space-faring nations, they were the only ones to make the last launch window. For a while, it seemed like China would be the first on Mars. As a scientist, as a terran, as a human, I was overjoyed that we were finally finding our footholds in the next worlds. As an American, I was envious and disappointed.

But we were handed a second chance. The Xia Yibu's ceramic buffer panels fractured and broke apart from the non-uniform heating. The entire vessel underwent what we call a, "Rapid Unplanned Disassembly." The general population refers to it as an explosion.

I remember hearing the news. In the span of a moment I felt nearly every emotion I believed I was capable of feeling. I thought about the families of the astronauts. I thought about what it meant that we, as humans, had failed. I thought about the poor workers who assembled the tiles and were, at that moment, likely awaiting execution for their mistakes. I thought about what it meant for us, that we can have the chance. I thought about my reaction, that glimmer of self-serving joy at other's misfortune. I thought about what it said about me and I felt sick. I needed to sit down. I took a breath -- these emotions can be processed later. There was work to be done.

Thompson, Brown, and I had not discussed who would be the first to set foot on the red planet. There was nothing to discuss. The decision was made by NASA and handed down in plain manila envelopes to us. The disparity between the gravity of the decision and the presentation invoked images of the holy grail as a plastic sippy-cup. Maybe with a crazy straw.

Someone tried very hard to select the most egotistical, arrogant, self-serving shitheel in the nation. They picked me. They succeeded.

Brown and I suited ourselves up, in some sense. We put on what was basically aeronautics-grade hazmat gear -- orange and white plastic-y laminated undergarments. The actual suits were attached to the ship. Mars, in addition to not having a very helpful atmosphere, is covered in a dust that's highly poisonous to humans. Rather than worry about venting atmosphere or flooding the ship with calcium perchlorate, it was easier to just leave the suits outside all the time and sneak into and out of them.

We entered into the backs of our suits, did ran the systems through Power On Self Test, and sealed the ports. Thompson opened the outer shielding and lowered the ramp. "Moss," he said, "Don't fuck up."

"I'll do my best." It was all I could do. And I stepped down the ladder. One rung. Two. Three. Just move. Just breathe. My suit probably weighed 300kg. Keep moving. That's only 100kg in Mars gravity, but enough to crush the average person. Almost there. Fortunately, there was a high-efficiency exoskeleton woven into the fabric itself. Two more steps. It felt like a hefty backpack. One more step. Just a backpack. Nothing more.

Contact.

A weightless step.

A deep breath.

Mic on.

"And so it was again as it was once before. That human kind stood on the shoulders of giants and walked among the stars."

Mic off.

Thompson clicked over my intercom. "Well done, Moss. I bet you're crying." I was. Mic on: "I'm not crying you're crying." Brown clicked in, "Thompson probably is crying." Thompson clicked back, "We all are. This is the greatest day of my life. We've got work to do, though, so are you just going to stand there bawling or are you going to get your shit together and move out?" I had to laugh. "First of all, I'mma do both." Brown was on the last second to last step, misjudged the position, and stepped off into thin-air. I heard a muffled thud. "Brown?" I said, "You okay? Status."

Brown came back, "Ego has suffered considerable damage. Suit integrity still at full. When you retell this story, say I did it on purpose."

"Let me help you..." I trailed off. There was a gouge in the landscape at the edge of the spillway. Brown noticed my distraction.

"Xia Yibu made it to the ground," stammered Brown. "Almost intact. Why didn't any of our satellites pick that up?"

"Budget cuts?" I offered. "Thompson, can you open a channel to Mission Control and send them an update?"

"Already done."

"You're frustratingly competent. Brown, what's LRF read for distance?"

"3.2km, but some pretty basic trig would suggest it's less than that. My head says about 2.1 km. The face part of my head. The mouth part of my face."

"Thompson, how's our landing change the time to sunset?"

"Effectively? Not at all, and you've got enough air to make it there and back, if that's what you're proposing."

"It was not. Not explicitly, at least. I really want to." I drew a breath, still reeling from everything that had happened in the past... two minutes? We had a plan. We had a mission. We had orders. Wing it on your own time. "Okay, let's set up camp."

The habitats were basically bouncy castles made of carbon and kevlar reinforced plastic. It wouldn't protect us from radiation, but it would withstand the weight of Martian soil. We were going to bury it -- diffuse the brunt of the sun's death rays. Brown got to surveying while I unpacked the lander. Thompson ran diagnostics and played 90's punk on the secondary channel. Adrenaline and enthusiasm carried us through the day and we finished with time to spare. We had a site with loose soil that we could blast away and fill with our hab. We had the ship unloaded and the storage area reconfigured for fuel. We had confirmation that our resupply unit, one that had shipped well ahead of us and started transforming the surface into fuel, was locked on our position and migrating to us. It was good to be alive.

NASA returned our messages. The light latency was 30 minutes at this point in orbit. We had enough time for a few back and forth exchanges during the work day, status updates, plan changes, fun things. The channel was too low-bandwidth for video or audio, but they offered some very poetic descriptions of the world's reactions. Not that it mattered. We wanted to get to the Xia Yibu.

I slept -- more deeply than I had in perhaps my entire life. Despite the anticipation of the day to come, I was at peace with myself and with the world. Both worlds. Victories were very ephemeral in my life. Even the greatest successes morphed into fortunate accidents through the malice of hindsight. This would be different. I had done something worth remembering. I had done something, finally, to justify my existence.

Life's a funny balance of narcissism and self-loathing.

Dawn on the Red Planet is stunning. If you've ever lived near a lighthouse, you may recognize the single ball of luminescence against a background of rock and haze. That's the Martian sunrise.

We ate together. Mission Control approved the change of itinerary. We had the go-ahead to proceed to the site of the Xia Yibu. Another happy accident in my life -- Oppi, our main objective, was on the way to the Xia Yibu.

Our crawler was like Opportunity's grown-up sibling. The nickle-titanium shape-metal-alloy tires had proven to be a nice upgrade, but the basic construction of the frame was unchanged. Advances in DC motors and battery technology also left more space for cargo, passengers, or, in our case, speed while unloaded.

The journey ended up being 2.2 km. Goddamn you're good, Brown. A 2 km journey is something the average person can make in about 25 minutes. Our exoskeletons and the 1/3rd gravity would mean we could probably have sprinted in about 5 minutes, but we had a job that required some hauling: retrieve Oppi.

Thompson saw it when we were 100 meters out. Oppi was not alone. Draped at the side was the body of a CNSA astronaut who, as suggested by the control unit attached to Oppi's serial interface, was trying to send a message back home. Failing that, the astronaut, the first human on Mars, inscribed a message.

好好休息, 我的老朋友. Rest well, my old friend.

Cameras are hard. If you've ever found yourself fighting against a camera that would really like to pivot in a direction you don't want it to, you've been on the receiving side of this technical difficulty. The reason behind your struggle is simple: spiteful developers.

Not really. Or at least probably not. The fact of the matter is that making a camera which balances the atmosphere of a game, moves quickly enough to keep up with the player, moves slowly enough to not move around with the player's jitters, and accounts for the corner cases like a player getting teleported -- it's not a simple thing.

I'd like to talk about the different methods I've been experimenting with in Clearing Skies. This is as much a journal entry for me to see what I've tried and why it works or doesn't work as anything else. I hope that someone may find some insight in it.

Approach 0: Strap the camera to the player.

This is the simplest and most straightforward approach to moving the camera. Wherever the player moves, the camera follows.

  • Simple! Easy to implement and understand.
  • Basically no corner cases where movement will be odd.

There are some drawbacks, and they're not too hard to see. When the player shakes or moves about drastically (like if she shakes after a shock or hit), the camera is liable to jitter along with her. Shaking the camera is a good way to induce nausea or eye strain in the player. Additionally, you lose the sense of level depth. The entire space is continuous. This is fine, generally, but for the first dungeon in particular, this felt to me like it shrank the space considerably.

  • Can cause eyestrain for sudden movements.
  • No way to add 'cinematic' elements on transitions between rooms.

Maybe there's an easy solution to the rapid movement problem? Indeed, we can try...

Approach 1: Smoothed Camera Movement.

The camera smoothly transitions between where it is and where the player is located. This solves a lot of the issues with the player shaking rapidly. It's like attaching a spring to a camera gimbal.

  • Still easy to implement.
  • Reduces eye strain from rapid motion.

The downsides are visible in the gif above. The biggest issue we run in to is the rapid movement of the player between rooms. The camera has to spend a few frames catching up to the player location on transport to a distant location. This can be solved by snapping the camera (disabling smooth on transition), on setting a max threshold before the camera teleports, or a few other tricks. No matter what, it's a bit more involved than simply assigning a location, and it still doesn't give us the cinematic room sweeping we want.

  • Camera has to catch up on long moves.
  • No cinematic controls.

Approach 2: Camera Zones

When the player character enters an area, the camera's bounds are set to match the region. This means the camera moves smoothly inside the zone, sliding to follow the player and 'transitioning' when the player moves between regions. I like the way this looks -- it divides the map in such a way that it makes things appear larger than they are.

  • Looks good. Cinematic.
  • High degree of control over where the camera moves. Can cut off areas outside of the map to avoid wasting screen real estate.

It's not perfect, though. Transitions are very abrupt and might cause issues with visual tracking of the player. It's also very cumbersome to implement, as the zones need to be defined manually:

Furthermore, troubles come in the way of overlapping rectangles. Not the region on the bottom where it may be necessary for two zones to overlap. Plus, when we finally leave the map, the bounds for the camera will need to change. Lastly, when we change the camera bounds, we lose the ability to smoothly transition between states.

  • Possibility of weird edge cases when moving between zones.
  • Time consuming to put together regions.
  • Not clear how to restore full camera zone when leaving dungeon.
  • No smooth transitions.
  • Visual tracking is hard on screen switches.

In a more perfect world, I'd love to be able to define small pins which act as boundary keepers for the camera, then, if a distance is exceeded, have the camera quickly tween to the player location and return to tracking. I don't have a solution for that worked out yet, however. Time will tell if I get it solved.

Bucky Isotope recently made mention of building the US-Mexico border wall entirely out of LEGO, following it with an inquiry on how much such a wall would cost.  Twitter, even with the newly increased comment size, still did not provide ample room for the calculation with sources.  This short piece will serve that purpose.

We will assume that the wall will be comprised of 2x4 LEGO brand building blocks for the sake of simplicity.  It is possible that a more cost effective wall be made if a different piece is chosen as the basis, but it will suffice for our purposes.  

9.6 1.8 1.0 31.8 32.0 4.9 2×0.1 8.0 8.0 8.0 8.0 31.8 15.8 4.9 2.6 6.41 0.8 0.6 0.3 Credit: Cailliau.org


A 2x4 LEGO brand building block has dimensions 16mm by 32mm by 9.6mm. 

If we simplify the surrounding border (heh) and remove the cap insets, shifting the volume instead to the perimeter by increasing the thickness to 1mm from 0.8mm, we can sum the four walls and 'ceiling' thusly:

Left: 15.8mm * 9.6mm * 1mm = 151.68mm^3
Right: Matches left.
Front: (31.8mm - 2mm) * 9.6mm * 1mm = 286.08mm^3 // We subtract 2mm for the thickness of the left and right walls.
Back: Matches front.
Top: (31.8mm - 2mm) * (15.8mm - 2mm) * 1mm. = 411.24mm^3 // Subtracting for the front, back, and side walls.

Total volume: 849mm^3 = 0.849cm^3.

At the time of writing, LEGO blocks are manufactured from acrylonitrile butadiene styrene (ABS), having a density of 1.05g/cc.  A 2x4 LEGO brand building block then weighs approximately 0.89145g, giving us 1121 blocks per kg.

We can convert an average eBay cost of approximately $50/lb to $110.23/kg, or approximately $0.0893 per block.

The US-Mexico border is 3,145km long from the Gulf of Mexico to the Pacific ocean.  Assuming blocks were stacked using the long side, it would take approximately 98,900,000 blocks for a grand total of $8,831,770.

The wall would stretch an impressive 9.6mm into the air and would weigh 88.16 metric tons.

If a taller or wider wall is required for some reason, one can calculate this by multiplying for every additional ~10mm of height desired and again for every 16mm of width desired.  For example, doubling our wall from 9.6mm to 19.2mm would double the cost to $17,663,540.  Doubling the width to 31.6mm would double the cost again to $35,327,080.

The average adult male from Mexico is 172 cm.  To construct a wall with this height at a thickness of 15.8mm would cost approximately $1,582,358,791.  It would require a human to be moving at least several centimeters per hour to breach.  

As a recent convert to Google Fi, I found myself in a position to find a memory tool for my new phone number.  In the interest of speed and laziness, I threw together a script which would produce all the combinations of letters that could be made from my number and dump them to a text file.  It seemed in good taste to share that script.

import itertools
digits = ['0', '1', '2ABC', '3DEF', '4GHI', '5JKL', '6MNO', '7PQRS', '8TUV', '9WXYZ']
digit_map = {k:v for k,v in zip("0123456789", digits)}
phone = "8005551234" # Your number here.
options = [digit_map[n] for n in phone]
with open("words.txt", 'wt') as fout:
  for p in itertools.product(*options):
    fout.write("".join(p) + "\n")

This will yield a text file with a list of entries like (for the above number):

T00K5L1B3H
T00K5L1B3I
T00K5L1BD4
T00K5L1BDG
T00K5L1BDH

It's worth noting that we could do away with the digit_map by just indexing directly into the digits, followed by a reverse before the output, but this solution provides greater clarity at a meager cost in efficiency.