• Cyberpunk 2077 is quite an achievement. Is it absolutely perfect? No. But the ways it’s not perfect can (and likely will) be fixed with patches. Will it ever live up the absurd levels of marketing hype? Probably not, but that’s okay. The hype was ridiculous, and the ways it has fallen short of it are fairly unimportant to the gameplay in my opinion.

    The main thing about Cyberpunk 2077 is how immaculately set-dressed the world is. Nearly every accessible part of the world is just a huge mess of garbage and grime, but also things of technological beauty. The amount of detail and design work put into the drivable vehicles alone is mind-boggling. Cyberpunk’s rendering of a large capitalist dystopia is akin to Red Dead Redemption 2’s rendering of the American west. It’s basically the perfect idea of these places. Is it 100% realistic? No, it’s the theme park version, but isn’t that better?

    The nicest graphics in the world wouldn’t save the game if the gameplay wasn’t fun, and Cyberpunk delivers there as well. The gunplay feels great, very punchy and visceral. The RPG progression eventually turns you into an overpowered unstoppable murder machine, but isn’t that how it should be? You start off having to hit people 5 times in the head to kill them, and by the end you’re doing somersaults and slicing people’s heads off with retractable mantis blades. Sounds about right to me.

    The main story and the sub-stories that compose the bulk of your first 40 hours in Night City are the glue that holds the whole thing together. The main storyline is fairly interesting, and some of the other storylines definitely go interesting places, but it’s mainly the characters that actually make you feel things here and there. Sometimes that might be annoyance when the characters make mistakes despite your best efforts, or admiration when you see another side of a character you didn’t expect.

    Cyberpunk is unfortunately a buggy game, with some rough edges here and there. I don’t think the bugs I’ve encountered are anything worse than you usually get with a game of this scale, but we’re in an age of the internet where every minor complaint must be amplified until it becomes a scandal that must be brought up every time the game is mentioned. That’s too bad, because it almost prevented me from getting the game. That said, maybe all the negative hype on release helped me adjust my expectations, so that I’ve been able to enjoy what is a monumental achievement, instead of sitting around nitpicking it to death.

    As a bonus, here’s some pictures I took with photo mode while I played the game. There shouldn’t be any spoilers.


  • When I started developing for PICO-8 a couple weeks ago, I quickly realized that it wasn’t really built in a way to be very portable. I like to develop on a couple different computers, so it’s important to me that I can quickly transfer files around and maintain a consistent development environment between machines. So, I quickly hacked out an easy way to do that, and along the way made my life a lot easier. I figured I would share my tips for PICO-8 development in case it helps out other people.

    First up, fair warning, I develop on macOS, so this post will be macOS-centric. I’m sure many of these tips extend to Windows, but it’s an exercise to the Windows-using reader to figure out how. I also admit that I’m an established developer who is already very familiar with most development concepts, so I may gloss over things that seem simple to me, but are impossibly difficult for a newbie. I hope not, but it might happen!

    One Folder to Rule Them All

    By default, PICO-8 stores all your carts in a folder tucked away in your ~/Library. Sure, you can type folder in the CLI to open it up, but that’s not really my style. I keep all of my programming projects in ~/Coding, and I wanted to keep my PICO-8 projects in there as well. On top of that, I didn’t want to have to put PICO-8 in my Applications directory on each machine I develop on, because I’m super lazy.

    I created a pico-8 folder in my ~/Coding folder and put my PICO-8.app in there. I also created a carts directory to store all the carts I make or download. In the end, my folder structure looks something like this:

    pico-8/
    ┣ PICO-8.app
    ┣ carts/
    ┃ ┣ bob/
    ┃ ┃ ┣ bob.p8
    ┃ ┃ ┣ comms.lua
    ┃ ┃ ┣ jrpg.lua
    ┃ ┃ ┣ overworld.lua
    ┃ ┃ ┣ shmup.lua
    ┃ ┃ ┗ transitions.lua
    ┃ ┣ demos/
    ┃ ┣ utils/
    ┃ ┣ zines/
    ┃ ┣ life.p8
    ┃ ┗ template.p8
    ┣ .gitignore
    ┣ PICO-8_CheatSheet.png
    ┣ README.md
    ┣ license.txt
    ┣ pico-8.code-workspace
    ┗ pico-8.txt

    In order to make PICO-8 realize you’ve changed your carts directory, you’ll need to venture into the main place it stores your config.txt on each computer you develop on. If you want to be fancy about it, open up your Terminal and type in nano "~/Library/Application Support/pico-8/config.txt"

    Pro-tip: If you do not see a config.txt, you need to close PICO-8. It’s only generated the first time you close PICO-8.

    Scroll down and find the header root_path and change that path to the new location of your carts folder. For me, that looks like this:

    // Location of pico-8's root folder
    root_path /Users/amiantos/Coding/pico-8/carts/

    Save the config file by hitting Ctrl+X, Shift+Y, and then Enter (if you’re editing with nano).

    Note: this config.txt file does not support the tilde shortcut, so you can not put in root_path ~/Coding/pico-8/carts/ for example.

    Re-open PICO-8 and type ls to confirm your new carts folder is there. If you got nothing in it, put something in it by typing save tempfile then type ls to see the file in the PICO-8 CLI and then confirm it appeared in your proper carts file. Did it? Great!

    Easier Debugging

    Every developer worth their salt knows that the best way to debug anything is to simply print or console.log stuff. Sure, in some environments you’ve got breakpoints and all that, but with PICO-8 we’re kicking it old school. Unfortunately the print command in PICO-8 draws to the screen, which isn’t really ideal because the screen probably has other stuff being drawn to it that we’d like to see instead.

    Luckily, PICO-8 has a printh command, which will print logs out to the command line. But you need to launch PICO-8 from the command line to benefit from this behavior, which isn’t totally straight forward. Let’s go from 0 to 60 and make it real easy, real quick. We’re going to create an CLI alias to launch PICO-8 from the Terminal whenever we want.

    Step one: Open Terminal

    Step two: Type in nano ~/.zshrc

    Step three: In this file, add this line somewhere, replacing the folder name with the path to your PICO-8.app.

    alias -g pico8="~/Coding/pico-8/PICO-8.app/Contents/MacOS/pico8"

    As above, hit Ctrl+X, then Shift+Y, then Enter to save your changes. Close your Terminal and open a new window. Type in pico8, and pico-8 will launch! Let’s test it out to make sure it’s working. His ESC to bring up the PICO-8 editor and type in printh("hello world"), then hit Cmd+R to run the file. In your Terminal window, you should see the text hello world.

    Now when you’re building your game, if you’re curious about what is happening as you play, you can put printh statements all over the place. This is an invaluable tool for all pico-8 developers, and makes it really easy to debug issues with your game loops and so on.

    Step Up Your Editor Game

    PICO-8 comes with a code editor built in, and while it’s fun to use when you’re learning or building small projects, it becomes kind of hard to stay organized. It’s a lot nicer to use a code editor like VS Code to program, but you can run into conflicts if you edit your .p8 files in VS Code while you’re also drawing sprites or making music within PICO-8. On top of that, editing .p8 files directly in VS Code is just kind of cumbersome and while there are PICO-8 extensions for VS Code, they’re not absolutely ideal.

    Luckily, you can use #import statements to make life a little easier. Look back up at that directory structure posted above. Do you see that bob/ folder? That’s one of my projects. The bob.p8 file is the core project file, but all the code for the project is actually stored in .lua files. This lets you split your code up into multiple files, so you can separate your files by game mode or more. When you run or export your project, set up correctly, PICO-8 knows to automatically import all the code from those files. It’s seamless!

    It’s also very easy. Just create a .lua file in the same directory as your .p8 file, let’s call it test.lua. Put some code in it, maybe printh("hello world") from above? Now, go into the code editor in PICO-8 and type in #include test.lua and run your project. If everything went according to plan, you should see hello world in your Terminal. Congrats!

    You can #include as many .lua files as you need for your project. The sky is the limit! So far I like to keep each of my ‘game modes’ split up into separate files, just to stay organized. Now you can safely edit your code in VS Code, while editing sprites and music in PICO-8, and never worry about losing code or graphics. Just be sure to keep your code all in these Lua files!

    Gotta Git Up to Get Down

    If you’re a newbie developer, you probably have no idea what Git is. That’s okay. But you should know, and you will know if you’re going to make a career out of development.

    I’m not going to go deep into how git works or how to use it. There’s plenty of tutorials out there, like this one, for beginners. The main thing you should know is this: Git makes it very easy for you to backup your code, and when you start collaborating with other people, it makes it extremely easy to collaborate in a safe way where you’re never in danger of losing precious code. If you’ve ever made changes to a program that you regret and cannot recover from, smart usage of Git could have saved you; if you’ve ever accidentally deleted a file or had storage die on you, git would have saved you.

    How does this apply to this guide? Well, my entire pico-8 folder I showed you above is also stored within a private GitHub repo. This means whenever I want to develop on a new computer, I just have to pull down the git repository from GitHub, and all of my files as well as my PICO-8 executable are there waiting for me. If I make changes to one of my projects, I push it to the repo, and then I can pull those changes down to my other computers. No need to worry about file transfers, or syncing folders to the cloud, or any of that nonsense. I am always in control.

    Note: Notice that I said my repo is private. If you don’t want other people looking at your code, keep it private! On top of that, do not ever store your PICO-8.app in a public repo, by doing so you’d be giving PICO-8 away for free to everyone, and that’s unethical!

    If you want to make other developers look at you funny, use a GUI client for git. I really like GitUp for macOS. As with all things related to software development, there are people who think using a GUI for git is lame and weird. But, you do you! I like how it looks.

    If you don’t intend on ever collaborating with other people, or you don’t care about backing up your code files, then don’t bother with any of this!


    That’s about it! The combination of “one folder” and “importing lua files” makes PICO-8 development a lot easier to manage.


  • A couple of years ago, at another job, I hired this guy for a data entry position. He seemed like a decently smart guy who could type fairly quickly, even if maybe he was a bit of a bro. He was at the company for well over a year, I’m pretty sure, but my memory is pretty shoddy. He’d earned “Employee of the Month” twice in one year, which was something we debated about and wasn’t just a random pick!

    Then one morning, he didn’t show up to work. No call, no email, nothing. The next day, he still wasn’t there. I’m pretty sure it was this day, or the next, I called his emergency contact: his girlfriend; just to make sure he was okay! I wasn’t trying to be a nosey up-your-ass manager or anything, it was unusual for him to just no show… plus we needed to know if we needed to hire someone else…

    His girlfriend answered the phone. I told her who I was, her boyfriend’s manager, and that we hadn’t heard from him in two or three days and we’re just checking in to make sure he’s okay? She said, “Uhh, hold on a second,” and hung up the phone. When I called her back (maybe we’d gotten disconnected?) it went to voicemail.

    At this point it seemed pretty clear that he wasn’t going to come back to work, so we set about looking for his replacement. Pretty lame that he did that, but who knows why people do the things they do? A week or two later, the company got the paperwork from the unemployment office for him. He’s trying to get money from the EDD!

    The company explains to EDD: No, he no-called, no-showed, he probably shouldn’t get unemployment. And then the guy tells EDD: I was actually secretly fired by my manager on the morning of *insert date here*. But *I* was his manager! And I didn’t do that. I don’t know if he elected for it or if it just automatically happened, but a hearing in front of a judge was scheduled for a week later. Normally the company wouldn’t have gone to such great lengths to deny someone unemployment, but he just flaked out. Very uncool.

    The first absurd thing about the story is that he was a *good* employee. I had been a manager long enough to know that it’s a pain in the ass to hire people, and it sucks when they’re not good employees because it’s such a waste of time and energy. The last thing I’d want to do is willingly get rid of a good employee. And we had proof he was a good employee: emails I’d sent to others about him; emails I’d sent *to* him directly, praising him; and the aforementioned two time Employee of the Month receipts.

    I also had a bit of an ace up my sleeve: we had security cameras everywhere. He knew this, because he used them sometimes as part of his training. So, trying to be well prepared for the ‘hearing’ or whatever it would be, I sat down and I exhaustively recorded my whereabouts on the day in question. I noted down every time I left my desk, where I went, how long I was gone, and who was in the rooms with me where I was. I was almost never alone, and always on camera. I’m pretty sure I also prepared a statement, in addition to the email ‘evidence packet’, just to be thorough.

    Unfortunately, the truth about this guy is that while he was a good employee, he wasn’t a happy one. He had bigger aspirations. When getting to know him, I’d asked him what he most wanted to do, for work, with his life, or whatever. He said he wanted to be an entrepreneur. An entrepreneur of what? I asked. He didn’t have an answer, it didn’t matter, he just wanted to be *an entrepreneur*.

    He wasn’t happy that he was a ‘lowly’ data entry person. We’d tried to get him involved in the inventory security program we had, but looking at camera footage bored him. He asked at one point if the company would pay him while he learned how to grow marijuana, so he could become a sales person and make more money. The company said no, we won’t pay you to learn to grow, but we’ll give you access to our training program documents so you can learn on your own. Disappointed, he declined the offer. Unfortunately for him, there just weren’t any open positions in the company he’d be a good fit for, so he was stuck doing data entry.

    This is mostly just making fun of him, but I’ll allow it: one day a nearby company put out a pallet of 3M foam earplugs, boxes within boxes, a couple hundred earplugs a piece. We all took a couple boxes. He came to work the next day saying he was going to sell the earplugs online, with photos of Hilary Clinton and Donald Trump glued to them, as a novelty gift, with statements like, “the holidays might get loud this year!” or something. This idea never actually got off the ground.

    The day of the hearing, I arrived with the HR assistant and we sat at a long table. My former data-entry clerk was sitting directly across the table from us. Some judge sat down at the end of the table taking notes. I honestly don’t remember who spoke first, but the story was pretty simple: He alleged that, sometime on the morning in question, I walked upstairs to where he was working, walked him down through the building, through the back offices, out to the back of building by the street, and told him we’d no longer be needing his services, and he immediately walked down to the bus stop and left.

    So I asked him, what time did this happen? And I don’t remember what time he said, but it didn’t matter, I responded: Well, I have this chart here I made of where I was, and who I was with, for every moment of the day, and at no point was he anywhere to be seen. I submitted that shit into evidence, which wasn’t as dramatic as it sounds when you say it that way, all I did was hand it to the judge. The judge asked him if he had any objection to it, and he said of course, and explained that I was in charge of security cameras–true–so I could fake the whole thing or just make up a list. The judge didn’t find that very convincing.

    I also shared the fact that we knew he wasn’t happy, but that otherwise he was a good employee as evidenced by the internal emails, emails to him, and the Employee of the Month awards. He said that we gave out Employee of the Month awards just to quiet down unhappy employees, which is only true sometimes, and may have been why he received it twice in one year without us noticing…

    I also asked him some of the more obvious questions: who else witnessed me walk through the building with you? Why didn’t you go back upstairs to grab your huge bag of pistachios and other snacks, or to say bye to any of your co-workers? And when I called two days later, and your girlfriend answered, why didn’t you talk to me or call me back?

    The judge really jumped on that last one, saying: yeah, if this guy fired you, and then called your girlfriend ‘pretending’ you no-showed, wouldn’t you wanna cuss him out or something? Give him a piece of your mind? He didn’t have great answers to any of these questions, beyond that he was upset and confused about what happened, so he didn’t want to talk to me or anyone.

    At the end of the hearing the judge said, I’m pretty sure this is verbatim, “This is a peculiar situation. Two people who have entirely, completely different stories. But you both seem credible. He seems credible, and he seems credible. Very interesting.”

    Obviously, we received word the judge ruled in our favor a short time later, and rejected his claim for unemployment. He then appealed, this time with a new story. If I remember correctly, he suggested that one of his former managers (before me) didn’t like him, and that they were using me to fire him because of it. None of that came up in the hearing, though, and after review of the case by another judge his appeal was rejected.

    I don’t manage people anymore, and I’m kind of very glad that I don’t. I might have had a worse than average experience, because the company wanted to pay people the bare minimum amount needed to hire someone, *anyone*, and I ended up with employees who were often lazy, dishonest, and manipulative. You’d think being dishonest would take so much effort it’d be better to just do the job you’re meant to do, but no.

    Prior to this guy, I was used to employees telling bald-faced lies directly to my face, usually ones I couldn’t quite prove. But this was the first time that those lies directly involved me, saying I went and did things that I definitely didn’t. Luckily, I was sitting in front of an impartial judge, and at absolutely no personal risk whatsoever, so if I failed to prove that fact it wasn’t that big of a deal.

    But, in different circumstances (like if I worked for a larger company), he could have written a Medium post, or talked to a reporter, and voiced his fabricated mistreatment to the world at large. I could just imagine how the article would account, in detail, his alleged mistreatment (“they wouldn’t pay me to learn…”) and the day I led him outside and fired him, maliciously, leaving him destitute and dependent on his girlfriend.

    And then there’d be a single sentence at the end of the article: “The company denies these allegations.” That’d be all the defense I’d get, that the company would be legally allowed to give itself. I mean, I probably wouldn’t be named, but I and anyone else working there would know he was talking about me, which could hurt me. Luckily, I’m awesome, and that wouldn’t hurt my feelings too much. But there’s other people out there, less awesome, and more susceptible to hurt feelings.

    The point is: when it comes down to it, sometimes people can be dishonest about work. That can be work they did in the past for other people, or work they’re doing right now, for you. People who seem to have a relatively normal level of dysfunctional habits can suddenly, one day, just do something completely unexpected when there’s money on the line. It’s important to be aware of this, and not just blindly trust everyone who cries mistreatment at the hands of a company. *Sometimes*, not always, they’re just a grifter, looking for sympathy and a handout.


  • Last week I bought a Raspberry Pi Zero W so that I could set up a Pi-hole on my home network. If you don’t know what Pi-hole is: it’s a network-level ad and tracking script blocker. It’s different from using something like AdBlock or the Brave browser, because it works across all devices on your network automatically. Scripts and ads are blocked before the request can even be made, so in some cases it can really speed up your web browsing.

    After getting it going and seeing the nifty admin panel that shows you query stats, I realized I would really like to see those query stats very easily on my Mac. Long story short, I ended up building the app I envisioned, and even added some extra features I hadn’t planned on originally, like multiple Pi-hole support and the ability to toggle your Pi-hole(s) on and off as you please.

    PiBar is free open source software (FOSS) like everything else I’ve built, so you can grab it over on the PiBar GitHub repo. It’s also available on the App Store, if you want to show your support (and get automatic updates): Purchase PiBar on the App Store.

    I’ll be writing a WIUT post tomorrow about my development process for PiBar over the past week, so you can look forward to that, if you need something to look forward to. (If my post tomorrow is all you have to look forward to, reach out to me and we can get you the help you need. You’re not alone, we can get through this together.)


  • Recently we decided over at Lingo that we want to allow our customers to download multiple asset files at once. We store all assets in AWS S3, which doesn’t offer a method of retrieving multiple files at the same time in a single zip file. (Why not!?)

    I did some Googling around and found a Python solution that purported to work in the most ideal way: no memory usage, and no disk usage. How can this be? It sounds like magic. Basically the idea is that you *stream* the files from S3, directly into a zip file which is streaming to S3 as you add the files to it. (Still sounds like black magic.)

    Long story short, this did *not* work in Python. I don’t know why, as I followed a couple examples from the internet. Whoever suggested that it did work must not have tested it thoroughly, or was delusional, because it definitely used memory as it was building the zip file. With sufficiently large files, or a large quantity of small files, the whole thing crashed.

    Distraught that my precious Python was failing me, I found several sources on the internet that suggested this idea *did* work when using Node, and worked especially well as an AWS Lambda function. This sounded like a good idea to me, because a Lambda function will definitely not allow you to use too much memory, disk space, or time. Only problem was that I knew little to nothing about Node/JavaScript development. I guess it was time to learn!

    So… I learned. Long story short (again), it took a little bit of research, but I came up with this Lambda function which successfully zips up hundreds of files directly into a zip file on S3, without any real memory usage and definitely no disk usage. It took some research, because none of the examples people had posted online actually worked flawlessly from beginning to end. For all I know, this script has some issues, but I haven’t run into them yet, and when I do, I will update it to avoid them.

    Compared to Python, Javascript syntax is a horrific mess that makes my eyes bleed. But I can’t argue with results, this worked out while the Python solution did not.

    If you need an explanation of what this code does, just give yourself a year or two as a professional developer and you’ll realize understanding what it does isn’t particularly important, but by that time you’ll be able to figure it out.

    Good luck!