All posts by Eevee

I am thirty-eight years old

Post Syndicated from Eevee original https://eev.ee/blog/2025/07/21/i-am-thirty-eight-years-old/

There are several old, personal events that I’ve been rotating in my head for a very long time. I’m finally writing about them because I’ve just had the staggering realization that they all form one singular story. In some cases I’d never made the connection; in other cases I just plain forgot that things which happened within hours of each other were related.

This isn’t pleasant to write, and it won’t be pleasant to read. But I need it out of me.

I might have some of the details wrong, since I’m piecing together fragments from decades ago. This is a story, not a documentary. It’s about me, no one else.

content warning: underage sex; the active pursuit thereof by adults; bestiality mention.

I am five years old

My family moves from the UK (where my mother is from) to an American military base elsewhere (as my father is in the US military). In the switch from the UK to US school system, my parents push to have me put in second grade, on the grounds that I’ve been absorbing basically anything I’ve been exposed to since I was old enough to walk, and I’d be bored to tears in kindergarten.

This puts me two grades ahead for my age, which makes me two years younger than everyone around me, which will remain the case until I graduate from high school. I’m still quicker on the uptake than most everyone in my grade, and later get shifted a third year ahead in math. I never have school-age peers. This is normal.

I am eleven years old

I’m a picky eater. A lot of foods actively repulse me. My mother keeps making them for dinner anyway. I do my best to eat around them. Once she makes a quiche, and the taste of the cheddar makes me instantly want to vomit, so I can’t eat any of it. My father insists I sit at the table until I’m finished. I try a few bites but can’t bear it at all. I sit there for an hour, alone, before he gives up and lets me slink away.


I like computers. I don’t know much I can do with them besides toodle around in QBasic, but being able to write out instructions and have a thing happen feels like magic to me. I’m enamored. I’ll stay enamored for the rest of my life. I’m dimly aware that Windows and Office are also software, but they seem too incomprehensibly vast and complex to have been made, let alone made by fundamentally the same process I’m engaging in when I draw circles on the screen. I don’t consciously think about this, merely take for granted that they emerged fully-formed from a Company, which is somehow a different sort of entity from a person.

I think the Internet sounds cool but I don’t really know what there is to do on it besides download utilities I don’t need or read about The Microsoft Windows 95 Product Team! easter egg, which I only ever get to work once. I also find out that you can trick MS Paint into taking a screenshot of its own help window, which is cool because I don’t know how to take actual screenshots. That means I can make fake UIs, which is cool because I don’t know how to make real UIs, and I don’t know how to draw, either. Art, too, seems like some kind of foreign magic.

I’m really into Animorphs. I want to turn into a red-tailed hawk like Tobias and just fly away. I’m starting to do less well in school, and feel a budding hostility coming from my parents over it. I don’t have a lot of friends, don’t really have a sense of how to make them, and don’t think about it much. I feel a little out of place everywhere, but I always have, so it’s normal to me.

I hear about book 16, The Warning. It’s the one with Jake morphing into a rhino on the cover. I haven’t read it yet, but as I understand it, the plot centers around one of the protagonists typing “yeerk” or something into a search engine and finding exactly one result, which they then go investigate.

I think about this. I know about the Internet and search engines. But obviously, I think, entering “Yeerk” wouldn’t find anything, because Yeerks aren’t real. I try it anyway, just to see. I’m stunned to discover the world of fansites.

One of them has a forum and even a chat room attached. I join both and am stunned once more to discover that the Internet has other people on it, just hanging out. The other people are all teenagers, a little older than me, but I’m used to that. Half of them also have overbearing parents, and we bond over bitching about them. I can be kind of weird and awkward here and it’s fine. I’m really happy about having found this little sanctuary, and I start spending a lot more time online.

I am twelve or thirteen years old

I’m in ninth grade. My parents have put me in a private school, and it is fucking miserable. Homework is so tedious it feels akin to torture, so I just don’t do it, so my grades drop, so I get endlessly scolded and told I’m a disappointment. Chores, too, are agonizingly boring, and my mother regularly screams at me for not doing the dishes. None of the adults in my life — not parents, not teachers, not other school staff — suspect I have ADHD, perhaps because I’m smart and quiet, and I will eventually work it out myself some years later. Everyone else seems to believe their lecture will be the one to finally inspire me. My parents, who had once fought to save me from boredom, don’t recognize it happening in front of them.

I’m miserable at home from all the screaming, which makes me even more reclusive and less interested in school, which makes my grades all the more mediocre, which makes my parents yell more, which makes me more miserable.

Perhaps luckily, I don’t draw any conscious conclusions from any of this. I have no sense of how other people experience the world, and I haven’t really thought about, say, whether homework is easy for other people. I don’t even understand that I’m struggling, because I have nothing to compare it to. I don’t remember being a little kid very clearly, so as far as I can tell, it’s just always been like this. This is normal.

I have a little breakdown once and yell back at my mother, trying to convey… why I’m unhappy, without fully understanding it myself. She stands there, stunned. My father storms into the room, grabs me by my shirt collar, drags me upstairs to my bedroom, and throws me into it. He gets a utility knife and cuts through several random cables on my computer, then leaves without a word.

One of the cut cables is my keyboard, so to use my computer, I have to steal the keyboard from his computer and be sure to return it before he gets home and notices. Otherwise I would be completely isolated.

I learn a valuable lesson. Adults will hurt me, and this is normal. I hurt quite often, but I can’t do anything about it, and if I try, adults will hurt me more, so I just sit with it.

Sometimes I used to cry, but then my mother would hear and come tell me (in a caring voice) not to, because I’d give myself a headache. I took that to mean I just shouldn’t, so I’ve stopped.

My parents will later try to send me to a therapist a couple times — the problem is of course with me, not them, never them. I confide the encounter with my father, which makes it through some unseen grapevine, and I end up having to talk to some sort of military-HR person about it. Fearing that I might get put into the foster system and things will somehow end up worse, I lie that I had it coming. I hate lying, but I’ve learned that I have to lie to adults sometimes, so they won’t hurt me as much.

It isn’t mentioned again. My parents never say a word to me about it… until over a decade later, when my mother will tell me that I was physically imposing and physically threatened her. I will have no idea what she’s talking about — until that moment, the thought of attacking her in some way never crosses my mind. I’ll also be a late bloomer, insofar as I’ll bloom at all, and one of the few strong images I’ll remember from that day will be my mother looking down at me. But she will remain absolutely convinced that I was a threat, and that is why my father took the therefore-fully-justified actions he did, and I will be unable to disabuse her of this notion up through the end of her life. One day, many years later, she will die of cancer, having never believed me about my own motivations.

She will also, in the same conversation, chide me for not doing the dishes. I will be almost thirty years old.

I am fourteen years old

I’m in tenth grade, taking AP calculus. I’m good at it, but the homework is still mindnumbing.

I try to coast through my own life, attracting as little attention as possible from the adults around me who have the power to hurt me. I’m not fully successful. But when I’m hurt, it’s normal.


I’m still online a lot. I’ve gotten into doing, well, “web stuff”. It started out with posting little JavaScript snippets onto a small forum that doesn’t strip it out, or using a lot of <font> tags to make rainbow text. I’ve also gotten into Pokémon, and I feel a strong affection for tables and lists, so I start to make a Pokédex website. I don’t really know what I’m doing, and much of the effort comes from painstakingly retyping information from strategy guides or just other people’s websites, a process my future self will find comically rudimentary in hindsight. But it still feels like magic, and now I can share it with other people, too. I don’t know if anyone uses my website, but I’m delighted to have made it.

I’ve also hit puberty — several grades after everyone else, which has been a little awkward — and am starting to hear about this “sex” thing. It sounds pretty interesting. I end up combining my interests and joining an IRC channel dedicated to Pokémon porn. I’m probably the youngest person here, but no one cares, and I have no sense that there’s any reason anyone would care. There are some older teenagers here, as well as some adults, ranging all the way up to one 40-year-old — but he’s a completely regular cheerful guy who just genuinely enjoys writing fics about Sabrina having sex with an Alakazam or whatever.

But there’s also a guy who makes the occasional comment about “little girls”. There are at least one or two people who casually mention they have regular sex with their dogs. No one bats an eye at this, so I don’t, either. I have no basis for comparison, because I am fourteen years old. Maybe this is normal. Everyone else acts like it’s normal. It must be normal.

Sometimes people try to have cybersex with me. I’m not very good at it. I don’t really know anything about sex, but I start to pick it up from how other people describe it. It’s fun to write about this thing I’ve never done, this activity so mysterious that it almost feels like it must itself be fictional. It feels like it only exists in a bubble, completely detached from normal life.


Offline, I still barely know anyone. I’ve sort of gravitated to a couple other nerds at school, but outside of the fact that we are all vaguely aware how to make a website, we don’t have a lot in common. One of them is just kind of mean, even. This is normal. I’m two years into high school and just barely hitting the age when most people are starting it. I live in Hawai‘i at the moment, and almost everyone else has lived here their whole lives, but I’ve never even been to the same school for more than two years.

I find out about a little old-school website where furries can enter their location and find other furries nearby. I put in my zip code. Nobody else, it seems, lives in Hawai‘i.

I am still fourteen years old

We move, for the fourth time in my life, this time to the US mainland.

I update my zip code on the furry location website. Still nothing.

But then, out of nowhere, I get a message from someone I don’t know, who I’ll call 🐨. He’s eighteen, four years older than me, but that’s normal. He says he used to live in my town and he’s passing through for just a day or two, and would I like to meet up? I’m fucking ecstatic and say yes.

My mother drives me to where he’s staying. It has that 1970s wood panelling everywhere, which I might be seeing for the first time. It ultimately leaves me with a strange, otherworldly impression.

We talk a bit, and then he clearly wants to have sex. This hadn’t come up in our brief conversations beforehand. He seems surprised, but unswayed, that I haven’t had sex before. I don’t see any reason to turn him down — sex is supposed to be The Best Thing, after all.

We fool around some. It’s… fine. I don’t really like how he touches me. But hurting is normal, and this barely hurts at all, so I don’t say anything. I don’t even know how to say anything. People don’t show much interest in what I want. If anything, what I want seems to be an inconvenience to everyone else.

So I don’t say anything. It’s fine. This is normal.

Things peter out. I go home.

I’m no longer a virgin. It seems like something should be different. But nothing is. I don’t really think about it.

I try to keep in touch with 🐨, but he isn’t around much. He’s part of a little group of furries who all live in the same town and know each other, though, and they start to reach out, and I talk to some of them.

I am sixteen years old

[Hello, future Eevee here. Just letting you know, this is your last chance to back out. –ev]

I’ve just graduated high school. I’m so close to being away from my parents, to living on a college campus in a distant state. It’s exhilarating, but also terrifying, because I don’t really know how to live on my own. I’ve never done laundry or bought my own food. I don’t have a car or much money. I don’t really know how to do anything, other than make websites that look like they were made by a sixteen-year-old.

Over the past couple years, a number of guys have shown sexual interest in me. Almost all of them have been eighteen or older. I’ve met some of them at furry conventions and had sex with them. I didn’t really like any of it. But I’m desperately starved for affection and still assume the problem is with me, so I keep taking any opportunity I’m given. Maybe the next time will be better? I don’t know what else to do, so I keep doing what I’m doing.

I’m sufficiently self-aware of this inner turmoil to post about it. The only relevant comment I get is from someone I do not know and never otherwise speak to.

There is absolutely nothing wrong with giving it up for whoever wants it, especially at your age!

I am sixteen years old. This is normal. It can only be normal. No one else thinks anything of it, so I don’t either.

I attend another furry convention not long before I’m to move into a college dorm. My family’s situation is a little complicated at the moment — the house has been sold, my mother is in an apartment in our old town, my father is in an apartment in the new town, I’m off to a convention, and somehow this is all intended to coalesce later.

I have two sexual encounters that have… ramifications.


One is with 🐯, who I met somehow-or-other through 🐨’s group, despite not being local to them. [I have no memory whatsoever of how we met, why we started talking, or what we talked about. –ev]

He is twenty-six years old, a full decade my elder. He is openly interested in me because I’m underage. This is normal. After all, I am underage, and most of the people capable of travel are adults, so anyone who would have sex with me would at the very least have to find it acceptable that I’m underage.

We meet up at this con. He has sex with me. As usual, I don’t really know why I’m participating.

It’s the worst sex I will ever have in my life, deeply unpleasant and uncomfortable. I spend every single moment of it desperately wishing for it to be over, but I don’t know how to ask him to stop. I expect people to hurt me if I push back against what they want from me, but I’m not even cognizant of this — I see myself as just wanting to make people happy. Eventually I can’t take it any more and, in a flash of inspiration, offer to fellate him instead. I don’t really care for that, either, but it’s much less bad.

He gets me to promise I won’t tell anyone. I’m vaguely aware that this is the sort of thing he shouldn’t be doing, and I don’t want anyone in trouble on my behalf, so I agree.


There’s also 🐸, who I’m at least acquainted with, though we’re not exactly close. We hang out in a couple of the same IRC channels and have friends in common. Also, we’re the same age, almost exactly — we were born in the same month.

We also meet up and have sex. This time, at least, it seems like sort of maybe a good idea. At least it’s someone I know. It’s not great, but it’s not nightmarish, either.

He leaves his phone in my hotel room. I happen to catch a glance of him a little later, and so I run up to him to return his phone.

His father is with him, and is furious. He’s absolutely convinced I’m some kind of sex predator, despite that we’re exactly the same age and I look younger than 🐸. I go for my wallet but he sense my intentions and angrily insists he doesn’t care what kind of ID I have. He declares he’s placing me under citizen’s arrest, a thing I’ve never even heard of. But of course, I believe I have to go along with adults, or they’ll make things even worse.

He actually calls the police, who spend about two seconds checking my ID and say “yeah this is fine”. But then they want me to Make A Statement Down At The Station, so I go there, and I awkwardly describe a bland teenaged sexual encounter to someone who is a remarkably slow typist considering it seems to be their whole job.

And now I’m at a police station, and the police only want to release me into my parents’ custody, because I am sixteen years old. So they call my father, who is thankfully only a few hours’ drive away. And they put me in a chair and tell me that if I get up they’ll lock me in a cell. And I sit there, for two hours, while cops twenty feet away crack jokes with each other about the fact that two teenagers fucked. It may have been more or less than two hours, but I have undiagnosed ADHD, which has a way of stretching out activies like sitting in a chair doing nothing.

My father arrives, so silently furious that he accidentally drives into the wrong state on the way back to his apartment. He demands I log into my laptop, and he changes my password. Once I’m alone, because he’s off at his job as some sort of network administrator, I log into my laptop as admin, and change my password back. [Bright spot in this story. Fucking hilarious. Great job, li’l Eevee. –ev]

I then write a public post about the experience, which ends up linked on a now-defunct drama site. A bunch of people — who are we kidding here, more adult men — have a grand laugh about, again, two teenagers having sex. It probably doesn’t help that the post is written in an almost painfully cutesy affect, since I am sixteen years old. Several dramamongers approach me personally to be nasty, including one who calls me a “sick fuck” for “doing kids”. I am sixteen years old.

One of the convention staff also emails me with a brief rant, asking why I’m trying to destroy the convention by writing about things that happened to me, because now he’s fielding accusations that the con is full of pedophiles (presumably, again, because I had sex with someone my age). I have no idea what to say to this and never reply.

I do show it to 🐯, hoping for support. I happen to think that it’s absurd to blame someone for posting that they had sex at a con. But 🐯 insists I’m wrong and should apologize. I deflate.

My father later talks to me about the event. The conversation is extremely one-sided, because I know what happens if I push back against anything. He tells me I’m cold, calculating, manipulative, evil. He tells me I care only about myself. That I have no soul. That he doesn’t want me in the house.

I am sixteen years old.

All of this is normal.


The irony is, unfortunately, lost on me — because as requested, I erased mention of 🐯, the twenty-six-year-old who had sex with a sixteen-year-old, from my story. I erased it so thoroughly that I will forget these two encounters happened on the same weekend until many years later, even as I will continue to be lightly haunted by a memory of horrendous sex I felt trapped in.

Sometime in the next week and a half, I admit to someone that I had sex with 🐯. [I don’t know who, but I think I was pointedly asked, and I didn’t really know how to reject questions, and I’ve never liked lying, so I can extremely see how I would end up just saying it. –ev]

This makes it through some unseen grapevine, and suddenly 🐯 is furious with me, threatening to end the friendship [lol –ev] unless I fix it somehow, by convincingly lying to someone in this gossip chain that I don’t know. I make a half-hearted attempt, which I hate, and am (unsurprisingly) not believed.

Our relationship, such as it is, deteriorates, both because 🐯 himself deteriorates and because I don’t seem to have as much interest in trying to be friends with the person I had inescapable nightmare sex with. I must feel resentful of him without ever wanting to confront him directly, because I will later discover a few remaining scraps of one of our last conversations:

🐯: Gods eevee you’ve become such an annoying little bitch, I can’t beleive I was ever even nice to you. I wouldn’t have come within 20 feet of you had I known you were this kind of person.

I am sixteen years old. I am being spoken to by a twenty-six-year-old man.

🐯: gods, you and your stupid faces

I am sixteen years old, and I use emotes as punctuation o.o to a ridiculous degree ^o.o^ like multiple times per line o.o and the twenty-six-year-old man who was so eager to have sex with me is now sick to death of how juvenile I am. If only there were some way he could have foreseen this.

I am sixteen years old, but I begin to realize I do not give a shit about this loser who can only bed teenagers, nor about his big important opinion of me. He’s mad at me, but it doesn’t matter. Adults have been mad at me my entire life. What’s he going to do, type at me? I glaze over. I become laminated. I rebuff everything.

He only talks to me once more, to say he misses seeing me around. I don’t care.

I am sixteen years old. I start to wonder if this isn’t normal.

I am eighteen years old

Someone new joins the Pokémon porn IRC channel. They are fifteen years old. I don’t think anything of it, just as no one thought anything of it when I first entered. This is normal. Sort of.

I recognize their name from the artwork that decorates several Pokémon fansites. I find it fascinating that they were able to create any of that. It’s like magic to me.

There are a few artists here already, but this is the first whose art was truly captivating to me. Somehow it feels more impressive yet also more real, like I can believe it was done by a person. It plants the tiniest seed that maybe, one day, I can do it too.

I approach them to say hi, that I like their art. We have an actual conversation, then another. It’s like a breath of fresh air. So many people I’ve talked to have just wanted to hit on me way past the point of comfort and barely have a personality beyond that. But nothing like that happens here.

Instead we talk about actual things: Pokémon, and art, and our lives, and all the wrinkles they’ve had so far. They like cats. I like puzzles. Sometimes they struggle with pressure from overbearing commissioners, and something about that must resonate with me, so I try to be supportive. Later I’ll admit I’m still struggling with affection and my inability to tell people no, and they’ll be supportive of me, too.

It’s nice.

One day, it’ll even be normal.

I am thirty-two years old

I’m at the DMV. My best friend, someone I met a lifetime ago — in a Pokémon porn chat, of all places! — is here with me.

We live together, now, with our five cats, and we’ve recently escaped someone we both struggled to push back against. It feels like a small victory, but it was hard-earned.

We both sign the marriage certificate.

I am thirty-eight years old

I’m thinking back on a lot of things. It’s almost dizzying to see so many little threads of causality. My parents, even teachers, practically training me to think that whatever other people want is paramount. The deeply fucked-up culture of early-00’s Internet, where people could just openly announce their interest in doing sex crimes and no one batted an eye. Even the notion of a 14yo in a space dedicated to porn sounds unthinkable by today’s standards, but I poked my head in a lot of sex-themed places back in the day and not one of them cared how old I was.

I suppose I was well-spoken enough to sound older (aside from the hailstorm of o.o), but at the same time my social development was… almost non-existent. Hence how I had 20-somethings talking to me like I was an equal, all while I didn’t even understand how to say “I don’t like this”.

It took me a few more years to extricate myself from the weird little rut I’d dug for myself. It certainly helped that, around nineteen or twenty, vastly fewer random older men were interested in me. I’ll just, uh, try not to think too hard about that.

I don’t know what would have helped me avoid this. I keep thinking back to the vague ambient warnings about the Internet in the early 00s, which mainly focused on how anyone might be lying to you, might be pretending to be your age to trick you into sex later.

But that never happened to me. It was so unlike my experience that it almost feels laughable. Everyone I had sex with was pretty open that they wanted to have sex with me, and I agreed. No one ever warned me that sex without pretense could have emotional consequences. Everything in my (regular, offline) life that tried to tell me anything about sex was laser-focused on either pregnancy, STIs, or a guy in a van offering me candy. Like, hello, I was a deeply lonely sixteen-year-old. They didn’t need to offer me candy. They just offered me sex!

And there are lingering consequences — although now that I’m happily married and no longer on the radar of a bunch of people who really want to sleep with a teenager, they largely don’t matter in practice. But I had so much terrible, uncaring sex with men that I feel a little anxious even considering the thought of doing it again. There’s no one besides my spouse who I want to have sex with at the moment, but I still don’t like having that stuck in me. Like a shackle around my ankle that isn’t chained to anything, but it’s still there, and occasionally I feel it rattle.


But what really struck me, what really compelled me to write this down, was the realization of a strange pattern in the post-con sequence of events.

I think it’s fair to say that 🐯 used me for sex. I played along, but I think there’s at least a little bit of a responsibility gradient here.

But then, wait. Some group of people confirmed with me that I’d had sex with 🐯, and then I guess started gossipping about it, possibly even harassing him. Do you know how many people from that circle reached out to me, to see how I was doing?

Zero. Nada. I was useful only as long as it took to crystallize a nugget of Drama™, and then I was no longer needed.

So let me recap, this time with some editorializing:

  • A man ten years my elder used me for sex.
  • A bunch of adult men used me for laughs.
  • Some kind of gossip ring used me for, well, gossip.
  • A con staff member used me to vent about something that, frankly, furry conventions seemed to deal with a lot in the 00s.

Not one of these many adults reached out to see if I was okay. The con staff guy didn’t know about 🐯, of course, but they did know I’d had a harrowing experience and now was having at least one more — because those are what my whole fucking post was about! — and yet the only reason they went through the effort to find my email and reach out was to blame me for it again.

But it’s the gossip ring that I truly cannot excuse. The sole reason there was any gossip to be had at all was the idea that a twenty-six-year-old having sex with a sixteen-year-old is, in some sense, bad. But this clearly didn’t actually mean anything to them! It was “bad” only in the abstract, “bad” only in the sense that it gave them an excuse to ostracize the “bad” person, or laugh, or whatever the fuck they were doing.

It’s no different than that drama-site clown calling me a “sick fuck for doing kids” or whatever the hell. You could not possibly read a post about how I had to wait for my dad to pick me up because the cops wouldn’t release a minor and not grasp that I am a minor. Like, I AMTHE KIDS”! You, my fucking guy, right now, are being cruel towards the people you’re feigning concern for! But it just didn’t matter what happened or who was involved or who was hurt by it. Some asshole — almost certainly yet another adult — just wanted to be nasty, and they thought they saw someone they were allowed to be nasty to, so they were.

None of these people were interested in helping a sixteen-year-old. They only wanted to lash out at someone. The best I got was a tiny apology from 🐯, of all fucking people, who eventually caught on that I had not fully enjoyed our time together. But he can, of course, shove that entirely up his ass.


For many, many years, I’ve avoided making any mention of the thing with 🐸, my first exposure to the Internet “Drama” Circuit. I feared it would happen again, or that I’d be called a pedophile some more by people who just conveniently forget that we were the same age. I’d completely forgotten that 🐯 happened at the same time — because he’d basically asked me to detach him from the rest of it! Rediscovering that little tidbit has sure cast this story in a different light.

But like, fuck that, regardless? I will talk about my own life in whatever goddamn way I please. As soon as I decided to write this down, I couldn’t even remember why I’d ever been scared to do it. I guess I had been pretty thoroughly punished for writing it down the first time.

And sure, with decades’ worth of hindsight, it was perhaps not a good idea to have described my underage sex life — or the brief entanglement of the police with it — in public. But I still reject the idea that it was wrong to do so, or that any subsequent ragging on the convention was my fault. The actual story here (once 🐯 was stripped from it) was that Some Fucking Guy overreacted and called the cops because his teenaged kid got laid and he didn’t like that. That is fucking bananas behavior for a grown-ass man, but somehow fingers ended up pointed at literally everyone else. Clown world.


And various people have been calling me a pedophile ever since anyway. I’m often not privy to why. Like, as best as I could discern, the Something Awful Pokémon crowd branded me a pedo at one point because I had some cutesy, non-sexual, unremarkable artwork of myself (i.e., an Eevee person) as the background of my website for a while. Like that’s it, that’s the whole thing. Conspicuously, I am not attracted to, or otherwise interested in, teenagers or children, but that just doesn’t seem to factor in. You’d think it would be kind of important, right? But there’s this weird chain of semantic implications that lets you suggest someone actively molests children based purely on vibes, without ever having to identify any concrete child, and that seems kind of bad to me, but if I try to explain it I’ll probably be called a pedophile, because why would anyone but a pedophile defend pedophiles by nitpicking the definition of “pedophile”, huh?

Meanwhile, I was actively pursued by much older adults! 🐯 isn’t even the oldest guy who had sex with me when I was sixteen! But I’ve spent half a lifetime nervous about even admitting that, out of some nebulous fear of the reaction, all while I get lumped in with the sort of people who did it to me because my website background doesn’t have a suit and tie or what the fuck ever. What a joke.

It makes me feel fucking crazy, sometimes, to watch our culture obsess over rooting out anyone with a whiff of “pursues sex with a minor” with the same furor and accuracy as we once rooted out people possessed by Satan, but with “the minor” — a person — reduced to a sort of… fantasy hypothetical? Or just dropped entirely, I guess. “Pedophile” is the thing you call someone that makes you win, because that’s the worst thing, and they can’t prove you wrong. Even the richest man in the world does it.

Sometimes I think about what might happen in another timeline, where I’m sixteen now and I post this story. I’m sure 🐯 would be absolutely roasted right off the Internet — but how many people would still check on me for anything other than more sordid details?

…But then, who have I checked on? How many times have I had the opportunity, and not taken it?

I can definitely think of one or two. But that’s a whole other rabbit hole.


This sucks. I feel like basically every adult in my teenaged life let me down, and I have no idea what to do with that information.

I guess all I can do is try to reach back in time with the power of blogging and say what I desperately needed to hear.

If you are a teenager reading this — I don’t know how or why, but I am functionally powerless to stop you — and even a little bit of it has resonated with you, then let me impress upon you this: how you feel matters. Even if it doesn’t seem to matter to the people around you, the people with power over your life, it should still matter to you. Hold onto it, even if you have to hide it, and do not let go for anyone.

I’m sorry for whatever you may feel trapped in. I’m sorry if it’s hard. It might keep being hard for a little while. But if you keep looking, you will find people who care about what you want, who will have your back when you struggle to stand up for yourself, and who won’t punish you for hurting.

Please take care of yourself.

P.S.: Sex is an amplifier, not an automatic good time. It’s like Mario Party: a hilarious chaotic mess with the right people, but a horrible fucking slog with the wrong people.


I am thirty-eight years old.

I still think about what happened to me when I was sixteen. Not all the time. But sometimes.

Maybe after today, I can finally stop.

The rise of Whatever

Post Syndicated from Eevee original https://eev.ee/blog/2025/07/03/the-rise-of-whatever/

This was originally titled “I miss when computers were fun”. But in the course of writing it, I discovered that there is a reason computers became less fun, a dark thread woven through a number of events in recent history.

Let me back up a bit.

Bitcoin

Back in the 00’s, if you wanted to move money between arbitrary people over the Internet, you realistically had one option: PayPal.

The thing about PayPal is that it holds onto your money, but it isn’t a bank? I do not fully appreciate the architecture or its implications here, but PayPal’s point of view seems to have always been that they can do whatever they want. They’ve always been pretty fussy about the use of PayPal to facilitate commissioning artists for drawings of unicorn wieners, for example, so if they thought you were doing that, they would just lock your account and also keep all your money for six months. For safekeeping, I guess. And interest.

Yet PayPal was the only option for many rinky-dink individuals selling one-off goods and services, so there was some amount of frustration that the only available middleman had exclusive right to say how you were allowed to spend your money, or what kind of indie business you were allowed to run. And if they caught you ignoring the rules then they got to keep your money for half a year.

And then in 2010 or so, I heard about Bitcoin. And it sounded like the wave of the future. Finally, a way to just send money to someone. What a fucking concept. And imagine what you could build with such a system! Websites could have real tip jars. Browsers could have tipping built right in that transfer only a few cents, since transactions would be so effortless.

I downloaded a miner (well, the miner at the time, I think) and ran it for like a day and failed to mine a coin. There was nothing else to really do, so I closed it and forgot all about Bitcoin.

Fast forward a bit, Bitcoin has reached mainstream awareness, and… none of that stuff happened. Bitcoin is not so much a currency as it is an entire ecosystem of schemes. The only mention I’ve heard in the last year of being able to actually buy anything with Bitcoin was gray market estradiol. (Even gray market FIP medication just takes credit cards!) The only browser with built-in tipping is the one spearheaded by a man whose other claims to fame are inventing JavaScript and wanting to outlaw my marriage, and the token it uses apparently had 80 whole sellers in the past 24 hours. Sounds like all of that is going great.

Meanwhile, fifteen years later, the state of the art in sending arbitrary people money seems to be… uh, PayPal. But now we have Stripe, too, which can take credit card payments if you know how to make a website that uses it, but which also forbids drawings of unicorn wieners. Patreon? Stripe and PayPal. Itch? Stripe and PayPal. Ko-fi? Stripe and PayPal. Nothing is fundamentally different.

But the dream has died. It almost came true, and then it was immediately co-opted by a bunch of get-rich-quick grifters and a bunch of turbo-libertarians whose entire identities are defined by the Things that they Own and who want to cryptographically impose that on everyone else too because they’re mad that World of Warcraft nerfed warlock or something.

And I suspect the core problem that has wended its way through the history of cryptocurrency is that the vast majority of people involved do not actually care what the thing they’re flocking to is. What they care about is that it has a graph, and that they get rich if the graph goes up, so they say whatever might make the graph go up. The graph even looks exactly the same for every coin and NFT and Whatever else: x-axis time, y-axis dollars. The only place the thing appears at all is in the title, where you can safely ignore it.

Plenty of people will talk up the supposed benefits of their pet thingamajig, of course, but my suspicion is that many of them don’t actually care that much. They have a vested interest in getting other people to buy into the thing, Whatever the thing may be, because then graph go up.

And so you have what I can only call a culture of Whatever. Bitcoin failed as a currency because the people who got most invested in it do not care about currency — it could be bottled dragon farts for all they care, except that putting it on the computer means there’s no need to actually worry about a product. It’s just something to pump the value of; the underlying asset could be, well, Whatever. And Bitcoin itself is open source, so you can copy it and make your very own coin, your very own Whatever. With NFTs, you can make an entire family of “collectible” Whatevers — a strange descriptor given that you can’t actually collect one of each of them, but who really cares if the description makes sense? It doesn’t matter what the art is, or how the technology works, or what the tokens are attached to. It just has to be something you can convince other people to buy. The actual thing can be Whatever.

I think this adequately explains why the proliferation of these guys helped suck all the air out of Twitter. Tens of thousands of grifters lining every sidewalk, each one passionately hawking an indistinguishable Whatever that they don’t actually care about. Endless, endless fake enthusiasm from people all trying to convince each other to buy into their boilerplate box of nothing. Buy my thing! Haha no don’t worry about how much of it I own — let’s talk about how much of it you should own! Hint: it’s a lot!

Kind of a bummer.

The shape of the Web

The Web is a cool thing because anyone can just put stuff on it. It is the largest town square bulletin board ever devised. Back in the day, your ISP would even give you your own website! I don’t think they do that so much any more, but there are more cheap or free options than ever — hell, you can host a little website on GitHub.

And it used to mostly consist of little things made by people, and that was pretty cool! You would see more than four websites in a day. Websites would have colors! They wouldn’t all be designed for a three-inch-wide screen and then just scaled up when you’re at your desk! Twitter once let you set your own background image for when people looked at your profile.

But the trouble with everyone having a bunch of websites is that you lost track of them all and you didn’t really know when they updated and it was hard to talk back to a website. Also, making your own website is kinda hard? You have to, like, learn things.

And so the entire Web sort of congealed around a tiny handful of gigantic platforms that everyone on the fucking planet is on at once. Sometimes there is some sort of partitioning, like Reddit. Sometimes there is not, like Twitter.

That’s… fine, I guess. Things centralize. It happens. You don’t get tubgirl spam raids so much any more, at least.

But the centralization poses a problem. See, the Web is free to look at (by default), but costs money to host. There are free hosts, yes, but those are for static things getting like a thousand visitors a day, not interactive platforms serving a hundred million. That starts to cost a bit. Picture logs being shoveled into a steam engine’s firebox, except it’s bundles of cash being shoveled into… the… uh… website hole.

Traditionally, the way to pay for keeping your website online has been to slather it in ads and suffer the humiliation of Pepsi trying to sell Pepsi halfway down your page. Ads don’t pay very much, but for a moderate-size endeavor, that’s fine. You write your article and put an ad on it and make twenty cents a month or whatever. I don’t know, I don’t run ads because they’re an embarrassing blight that make everything they touch worse.

Together, these forces push big platforms in a very specific direction: maximize how many ads people see. To the exclusion of just about anything else. So Engagement becomes king — it’s okay if your users are miserable, so long as they’re here. It’s okay if the ads are obnoxious, as long as they’re seen.

Then this model spread into phone software. And then into videography. And then, somehow, into fucking, Windows??

And when the primary focus of the business is on the ads, everything else is sort of ancillary — it’s only important insofar as it keeps people around, to look at the ads. It’s jingling keys. It’s… Whatever.

This is the driving force behind clickbait, behind thumbnails of white guys making 😯 faces, behind red arrows, behind video essayists who just read Wikipedia at you three times a week like clockwork, behind suggestion algorithms, behind recipe blogs that all look the same and have a mile of filler fluff, behind video game websites abandoning the idea of articles and instead turning into SEO vultures with inexplicably lengthy articles telling you “the blue key is under a rock by the river” so they have more paragraph breaks to put ads between, behind TikTok’s model of being a constant stream which I have to only guess at because I have never had any interest in TikTok but I assume it’s a worse version of YouTube Shorts and I already find those pretty irritating.

It’s all the same thing.

Look at it. Look at it, you stupid baby. Look how outlandish or shocking or extreme or dramatic, Whatever it is. Just shut up and look at it, so Home Depot will give me a quarter of a tenth of a cent.

At least when I write a lot, you know it’s because I wanted to write it. Also I’m probably not lying to you because someone paid me to do it!

And the only real hope I have here is that someday, maybe, Bitcoin will be a currency, and circulating money around won’t be the exclusive purview of Froot Loops. Christ.

Did you know there were entire get-rich-quick schemes about this? It’s like writing fake novels. Just make a website with a generic WordPress theme (every website looks the same anyway), write a bunch of bland nothing articles about things that seem a little obscure, and slather it in Google ads. Then let the money roll in from people accidentally finding your website and leaving when they find out it’s useless. But it’s too late because you already got the ad view!

I say “were” because bothering to write generic filler about nothing is passé — now the computer can do it for you!

I tried Mastodon for a while, but it was fairly quiet, and the user experience was… still… not… a good time.

Artificial reality

If you told me ten years ago that by 2025 we’d have the Star Trek computer, I would’ve been ecstatic. How fucking cool is that! You talk to your computer and it does things!

But we didn’t really get that. We got, I guess, sparkling autocomplete — a fancy chatbot that can string words together in the most inoffensive people-pleasing customer-service voice you’ve ever heard.

The result is something I adamantly do not want to interact with. I do not want to be exposed to LLM output at any time. It’s noise, and I feel like I get a little dumber every time I accidentally start reading it. My brain is already a bit glitchy, and I really cannot afford to have it work even more less good.

And speaking of things that work even more less good, the technology… sucks? It fundamentally doesn’t do the thing that its investors and diehard fans say it does. It just strings together text that is statistically plausible. And every new alleged advancement comes with some invested airhead billionaire boasting about how the computer is as smart as a Ph.D holder now, and then you see the output and it’s still the most generic banal brain-rotting sludge you’ve ever seen in your life.

Most of my exposure to LLM output is via Google cramming it everywhere they can think of, and in every instance the result is worse. Google Search keeps redesigning its way around my μBlock filters to dedicate an entire third of my desktop screen height to an “AI summary” — which either lightly restates the highlighted part of the top search result anyway, or is just total bullshit. YouTube keeps showing a sprinkling of “AI summaries” under video thumbnails that, without fail, restate the video title in more words. My phone’s fucking weather app has an “AI summary” with incredible insights like “it’ll get warmer over the course of the week”, which I could readily see for myself if this block of white noise weren’t pushing the temperature graph off the bottom of the screen. Over and over, actual information is moved out of the way to make room for an unreliable lossy compression of that information into text that takes longer to read.

But this is worth billions of dollars.

I think what really gets me here, and what no one really talks about, is that the bar has been revealed to be so low. LLM features get bolted onto fucking everything because what they do, what they really do, at their core, is this: Whatever. They do Whatever. And that’s great, because Whatever is something. There’s no such thing as an error, no empty results page, no such thing as a missing feature or an uncovered case. Almost without fail, you’ll get something. Is it useful? Is it correct? Is it remotely based in reality? Who cares? Far more important is that there is output. Whatever is apparently better than nothing. Cheap and inoffensive and disposable, like a red beer cup. We are doing to the Internet what we already did to the ocean: filling it with a great swirling vortex of trash.

Case study 1

Ah!” the Hacker News commenters cry. “But have you tried it?” they ask with all the indignity of a kindergartener offended that you won’t eat their mud pie.

But yes, thanks: I was once offered this challenge when faced with a Ren’Py problem, so I grit my teeth and posed my question to some LLM. It confidently listed several related formatting tags that would solve my problem.

One teeny tiny issue: those tags did not and had never existed. I typed this additional context into the computer, and it generated a profuse apology followed by a different set of fictional tags. That was the end of that grand experiment.

The trouble was likely that there was no built-in way to do what I wanted, and no one had ever successfully done it before, so the machine had nothing to draw from… and simply generated something that sounded plausible instead. Because that is what this technology does: it continues a conversation in a way that sounds plausible, as defined by similarity to existing conversations. If there are existing conversations about the topic, great! That makes for a more specific measure of plausibility. If not, even better! Just about anything might be plausible! It can just generate Whatever!

I cannot stress enough that this is worse than useless to me. Not only did it not answer my question, but it sent me on a wild goose chase making sure I had not somehow overlooked the fake API it generated.

Like, just to calibrate here: you know how some code editors will automatically fill in a right bracket or quote when you type a left one? You type " and the result is "|"? Yeah, that drives me up the wall. It saves no time whatsoever, and it’s wrong often enough that I waste time having to correct for it.

And that’s a predictable operation that inserts a single character! What we’ve invented is an entire fake persona that will waste your time entire paragraphs at once.

I can’t imagine using this to do any actual work and I don’t understand how anyone else does. This is a whole new kind of failure case we’ve invented. I did also ask people about this problem, and they responded in the ways people might: they said they didn’t know, or they suggested an elaborate and tedious workaround that would technically solve the problem (but introduce new ones). But the LLM statistically generated something that sounds like an API that could exist. It produced an answer that was plausible, thorough, informative, relevant, and contained no useful information whatsoever. It produced the opposite of information! It produced noise.

Why would I want this? Why would I want to use a machine that sometimes generates text that resembles a person confidently lying to me? People are sometimes wrong, sure — that’s why Stack Overflow has downvotes — but this is something else entirely. If a real person did this to you, you would stop asking them questions real fucking fast.

LLM output is crap. It’s just crap. It sucks, and is bad.

Anyway I went on to do the thing I wanted regardless, because I’m a programmer and I know how to make computers do things.

I mean, I get it. I was trying to do something that had never been done before. LLMs are fine at things that appear a zillion times in their training data — in fact, this is probably a big part of the trick, because the things that appear more often in their training data are the things people are more likely to ask about in general and thus the things people are more likely to ask an LLM. But whose creative output consists solely of doing things a million people have already done? Is everyone else working on projects built exclusively out of lists of primes and rebalancing binary trees?

Case study 2

Back in December, I was complaining about something else (surprise, it was Web ads!) and just happened to look at the Visual Studio Code website, most of which was devoted to its LLM code-completion service, Copilot. I don’t care to desecrate this blog with LLM output — it’s on Bluesky if you must — but suffice to say, it wasn’t great. It was a call to a web service, and the generated code failed to encode form data. You know, Computer 101 stuff. Also it was like twice as long as it needed to be. Also it wouldn’t work on HTTPS websites because the web service’s certificate expired three years ago — which is a fun footgun, since you very well might be on HTTP localhost, and then it’ll only break when you go live.

I found it highly unlikely that the latest and greatest API for “get website” couldn’t just encode form data for you, but lo and behold: it can! Copilot just didn’t bother to make use of it. And since Copilot is a Whatever machine and its answers are these one-time disposable things, there’s no mechanism for someone else to come in and go “hey, you forgot to encode the form data”.

What even is this thing we’ve invented? Stack Overflow, but you only get the answers people scramble to type first so they can get the points? Oh and they just lie to you sometimes? Why would I want this?

And I didn’t cherry-pick this example! They chose it! This was the front-page example for a state-of-the-art LLM integrated with the most popular code editor in the world, all built by one of the richest companies in human history, whose entire business is software and who has specifically invested a zillion dollars in this specific technology. This is the gizmo at its best! And it’s crap!

But it does something. And that’s what’s important.

The broader culture

There are people who use these, apparently. And it just feels so… depressing. There are people I once respected who, apparently, don’t actually enjoy doing the thing. They would like to describe what they want and receive Whatever — some beige sludge that vaguely resembles it. That isn’t programming, though. That’s management, a fairly different job. I’m not interested in managing. I’m certainly not interested in managing this bizarre polite lying daydream machine. It feels like a vizier who has definitely been spending some time plotting my demise.

It makes programming spaces feel bleaker. I don’t want to help someone who opens with “I don’t know how to do this so I asked ChatGPT and it gave me these 200 lines but it doesn’t work”. I don’t want to know how much code wasn’t actually written by anyone. I don’t want to hear how many of my colleagues think Whatever is equivalent to their own output. I don’t want to keep watching people fall for a carnival trick.

A couple days ago I saw someone (whose bio claimed they’re a Bluesky engineer, but who knows) insist that it’s “very stupid” to not use a chatbot for programming. I just cannot comprehend this. If the task is easy, I could just write the code about as fast as I could describe it anyway. If the task is hard, then it’s all the more likely the generated code will be subtly wrong (or overtly wrong). If it’s something I don’t know, I can go find out about it, and now I know more things. What are you all even writing that so much of it consists of generic slop?

But also… why do you care? Why would someone using a really cool tool that makes them more productive… feel compelled to sneer and get defensive at the mere suggestion that someone else isn’t doing the same? I know there are people who oppose, say, syntax coloring, and I think that’s pretty weird, but I don’t go out of my way to dunk on them. I can’t imagine having a stronger reaction than saying “lmao what” and immediately forgetting about it. I might have strong opinions about what code looks like, because I might have to read it, but why would I — why would anyone — have such an intense reaction to the hypothetical editor setup of a hypothetical stranger?

It feels like the same attitude that happened with Bitcoin, the same smug nose-wrinkling contempt. Bitcoin is the future. It’ll replace the dollar by 2020. You’re gonna be left behind. Enjoy being poor. Sure thing, Disco Stu! There have definitely never been any inventions that turned out to be bad ideas or were just plain forgotten about. But the Bitcoin people make more money if they can shame everyone else into buying more Bitcoin, so of course they’re gonna try to do it. What do programmers get out of this? Unless you work at Microsoft and have a lot of stock options, you aren’t getting rich off of how many people use Copilot.

It’s curiously similar to how, as a fitting segue, Microsoft is now gonna factor “AI” use into employee performance reviews:

AI is now a fundamental part of how we work,” Liuson wrote. “Just like collaboration, data-driven thinking, and effective communication, using AI is no longer optional — it’s core to every role and every level.”

Liuson told managers that AI “should be part of your holistic reflections on an individual’s performance and impact.”

What are we actually saying here — that even Microsoft has to evaluate usage of “AI” directly, because it doesn’t affect performance enough to have an obvious impact otherwise? That the technology is so limp that even its biggest investor has to strong-arm its own employees into using it? That their own employees don’t want to use it?

Genuinely good new tools don’t tend to need coercion to fuel their adoption only a few years into their existence, right? What the fuck is going on here?


Another Bluesky quip I saw earlier today, and the reason I picked up writing this post (which I’d started last week):

Quitting programming as a career right now because of LLMs would be like quitting carpentry as a career thanks to the invention of the table saw.

I’m not trying to put the author on blast or anything, so let’s leave it anonymous, but — my guy? My dude?

What on earth are you talking about?

I don’t know the context for this. What I do know is that a table saw quickly cuts straight lines. That is the thing it does. It doesn’t do Whatever. It doesn’t sometimes cut wavy lines and sometimes glue pieces together instead. It doesn’t roll some dice and guess what shape of cut you are statistically likely to want based on an extensive database of previous cuts. It cuts a straight fucking line.

If I were a carpenter, and my colleagues got really into this new thing where you just chuck 2×4s at a spinning whirling mass of blades until a chair comes out the other side… you know, I just might want to switch careers.

I keep seeing this — people compare LLMs to calculators, or screwdrivers, or digital cameras, or whatever. I’m left wondering if the people saying this stuff have ever used any of those things. A calculator does arithmetic for you — thus automating the tedious, repetitive part — but you still have to know which buttons to press to get the answer you want. You can’t just type the entire problem in and get Whatever — something that sounds plausible, with a microscopic disclaimer that checking it for accuracy is your problem.

Calculators do have limitations at their extremes, and if you’re working with extremes, you have to be aware of those. Table saws will (or, used to) cut through fingers just as happily as wood. Tools have edge cases — at their edges. LLMs have edge cases everywhere, and they are constantly changing, even minute to minute, even for exactly the same input fed to exactly the same model. It’s also possible to adjust or customize tools in various ways, whereas 90% of the times I’ve seen someone talk about their customized LLM, all they’ve done is prepend a paragraph like “Please answer as though speaking to a customer.” The state of the art is to ask the computer nicely to do something, add a disclaimer saying it’s not your problem if the computer is racist, and then charge for access.

This is not mere automation. This is a completely new type of thing. We’ve never had a machine that can take almost any input and just do Whatever. But I keep watching people act like it’s the same level of invention as the egg slicer and I feel like I’m losing my fucking mind.

But what if it gets better

I don’t know. What if it does? What does that mean? I hear “better” and I read the press release and in the fine print it says that now it can count the number of letters in “Mississippi” correctly or whatever. And then it’s still crap.

What if it didn’t produce crap? I struggle to imagine such a world, in no small part because the hype around the Whatever machine is so staggeringly overblown. My phone has a dedicated Tensor™ chip to simulate artificial intelligence in the palm of my hand, wow! Here’s what it does: tells me it’ll be hot this week.

But if the machine still just fabricates an elaborate plausible fiction when it doesn’t have an answer on-hand, what good is it? I can always just go find the place it got the answer from originally, and at least then I know that someone wrote it. Someone had a reason to think it, even if they were mistaken. Maybe the well is just permanently poisoned — anytime I see anything I know to be LLM output, my first assumption is that it’s nonsense, completely divorced from reality.

I know a lot of people have a lot of gripes with LLMs and generative “AI” that tie them to big grandiose concerns like intellectual property or environmental impact. My gripes are more of a tangled web that I can only summarize as: the vibes are bad. The tone is unbearable. The lying as a fallback is offensive. The advertising keeps focusing on how you can coast through life without caring about your work or family because you can just generate a birthday card or whatever. The people funding and pushing it keep openly salivating at the idea of replacing as much human input as possible with a machine best known for generating titles of books that don’t exist.

I don’t know how you get “better” than this. I don’t know how you make a better Whatever machine.

And then there’s the art thing

I glimpsed someone on Twitter a few days ago, also scoffing at the idea that anyone would decide not to use the Whatever machine. I can’t remember exactly what they said, but it was something like: “I created a whole album, complete with album art, in 3.5 hours. Why wouldn’t I use the make it easier machine?”

This is kind of darkly fascinating to me, because it gives rise to such an obvious question: if anyone can do that, then why listen to your music? It takes a significant chunk of 3.5 hours just to listen to an album, so how much manual work was even done here? Apparently I can just go generate an endless stream of stuff of the same quality! Why would I want your particular brand of Whatever?

Nobody seems to appreciate that if you can make a computer do something entirely on its own, then that becomes the baseline.

There is a lot that can be said about image generation (little of it polite), but I’m running out of steam a little here. I’d intended to comment on the ongoing efforts to make better and better photo-quality image generation, but I can’t think of much to say beyond: why the fuck would you work on that? We don’t have enough trouble with, say, the conservative “news” sphere inventing its own alternate reality that millions of people buy into, simply by lying — now we have to give them a machine tailor-made for creating fake photos and videos too? Why does this need to exist? Why is this in my phone’s fucking camera app? Christ I hope everyone working on this has their nipples fall off.

Also I could swear I saw Google advertise that Gemini can do your homework for you

This is starting to get away from the main thesis of Whatever but every time I hear about students coasting through school just using LLMs, I wonder what we are doing to humanity’s ability to think critically about anything. It already wasn’t great, but now we’re raising a whole generation on a machine that gives them Whatever, and they just take it. You’ve seen anecdotes of people posting comments and submitting papers and whatnot with obvious tells like “As a large language model…” in them. That means they aren’t even reading the words they claim as their own! They just produce Whatever.

Actually hang on this gets me into conclusion territory.

Enough of Whatever

I remember that Facebook literally proposed running a bunch of its own LLM-driven fake accounts on its own website. Fake people making fake posts about Whatever, so you’ll have more Whatever to look at, so you’ll see more ads along the way. Monetize the rot, I guess.

I can’t imagine publishing a game with, say, Midjourney-generated art, even if it didn’t have uncanny otherworldly surfaces bleeding into each other. I would find that humiliating. But there are games on the Switch shop that do it. Whatever.

It begins to feel like a broad celebration of mediocrity. Finally, society says, with a huge sigh of relief. I don’t have to write a letter to my granddaughter. I don’t have to write a three-line fetch call. I don’t have to know anything, care about what I’m doing, or even have an opinion.

I can just substitute some Content™. I can just ask the computer for Whatever

But I like programming. I like writing. I like making things and then being able to sit back and look at them and think, holy fuck, I made that. There is no joy for me in typing a vague description into a computer and refreshing my way through a parade of Whatever until something is good enough.

The most obnoxious people like to talk about how Stable Diffusion is “democratizing art” and that is the dumbest thing I’ve ever heard. There is no fucking King of Art decreeing who is allowed to draw and who isn’t. You could do it. You could do it right now. But it’s hard, so you’d rather spend that time crying on Twitter about how unfair it is that learning a skill takes work and thank god the computer can give you all of the admiration with none of the effort now.

This is an incredibly weird moment. There have always been inventions that make some craft easier (but sometimes a little more shoddy as well). There have always been people who resented the idea that the thing they work very hard at is now more accessible. America’s Protestant work culture is deeply entangled with this as well, but I don’t value sweat in and of itself — I have a broader objection.

Because this is something else. What’s being sold to us is a machine that is promised to do everything. That’s far beyond a tiny question like “should you know how to manually focus in order to take a photography” — it gets at the notion of thinking about, or doing, anything at all.

I don’t think anyone is obligated to do anything in particular. If you don’t want to draw, or write, or compose, or program, or whatever, then don’t! That’s fine.

But I think the core of what pisses me off is that selling this magic machine requires selling the idea that doing things is worthless. Because if doing something has some value, then it must be somehow better than pushing a button and receiving Whatever for essentially no cost. If you’re some assclown like Sam Altman, whose graph-go-up depends on convincing you to replace all your employees with ChatGPT, you have to destroy that idea. It is the greatest threat to your business model. You have to destroy the idea that things are worth doing.

I think that sucks, I think he sucks, and I think his machine sucks. So fuck him and fuck his machine.

Do things. Make things. And then put them on your website so I can see them.

Anise lives

Post Syndicated from Eevee original https://eev.ee/blog/2025/06/10/anise-lives/

close-up photo of a black sphynx cat face, staring directly and intently at the viewer from mere inches away; behind him are computer monitors and other desk clutter, but mostly obscured by cat face and blurred by the focal distance

(a post rescued from Cohost, originally Aug 2024)

Some backstory may be necessary.

Some backstory

FIP is a cruel joke of a cat disease. It’s a mutation of the feline coronavirus, which as you might imagine is fairly common, so virtually any cat might develop it at any time. It tends to afflict very young or very old cats. If left untreated, it is virtually always fatal in a matter of weeks. And there is no cure.

At least, that was the state of things when my first cat, Styx, died of FIP.

That was a long time ago now and it was very sad. It’s still very sad, just, less frequently. Sometimes I try to give his death meaning by reassuring myself that it led me to meet Anise, but that’s trading one companion for another, which is kind of weird? I think nowadays I find it more comforting to think about how the universe is chaotic and things just happen and there doesn’t need to be any… moral weight on them.

Anyway.

The regular story

Anise is my second cat and he has always been a sturdy guy. He’s never had any real health problems.

But then a couple years ago, maybe around the end of 2022, I noticed he was losing weight. And this freaked me out a bit because Styx’s first symptom was weight loss that only I had noticed — I’d gone out of town for a weekend and returned to find his back looking kinda bony. And now I realized Anise was looking kinda bony.

And then he started getting lethargic. He’d spend basically all day, every day, just sleeping. And yeah, I know, cats sleep a lot, but they don’t just sleep. Anise would get out of his cat bed, drink some water, maybe eat a single kibble, and then return to his cat bed. That was all I saw from him all day. And he’s usually very, um… sociable? Demanding? Sociamanding.

So we went to the vet (a different one, now), and they poked and prodded him a bit, and said he was basically fine. Great news.

But he kept slowly… shrinking. And he didn’t seem to enjoy eating. I thought about this some and wondered if maybe he had a dental problem, that chewing on kibble was painful. I took him back and asked them to look at his teeth real good, and lo and behold, he had a couple bad teeth! So we farted around for over a month with appointments and some other vet thing I can’t remember before he could actually get those teeth pulled, and then he had a month of meds afterwards, and in the meantime I’m doing stuff like putting kibble in a coffee grinder and turning it into a paste so he can just lick it up, because at least he seems to eat a bit more when I do that.

And then I wait for the post-op soreness to probably go away, which is mostly just waiting for some length of time that seems reasonable because cats aren’t real big on telling you where or how much it hurts, and meanwhile he’s now having diarrhea that seems to be especially unpleasant for him. So it’s back to the vet, and they still don’t see any clear problems, but maybe we could try this bland sensitive stomach food and mix in some pumpkin? And I go off and buy a bunch of prescription food and mix in a truly staggering amount of pumpkin purée — the advice is to give a cat up to a teaspoon a day, and I need to give him a tablespoon or more to keep him moderately regular — but it does seem to help, and he seems to enjoy eating it more. Progress! Progress?

We came to call this concotion Prince Food. Anise soon learned that the only source of Prince Food was me, and every four hours like clockwork, he would ask for some Prince Food. He did this by sitting on my desk, facing me, putting him at very nearly my eye line, and just staring at me. That’s what the photo is: Anise asking for Prince Food. I literally put my phone as close to my face as I could and took a picture. That is what my field of vision looked like, four to six times a day. For months. Absolutely ridiculous.

This is what I mean about Anise being sociamanding — he is very aware of the things he likes, and most of the ways he’s found to ask for them are almost cartoonishly obnoxious. Going a whole day without being physically bugged for something is rare.

…But he was still slowly losing weight. We went back and forth to the vet, trying various things, waiting weeks each time to see if anything would change — sphynxes especially seem to need time to adjust to a new diet, so it was really hard to know when to call something a definitive failure — and it wouldn’t. It was uniquely exhausting. I really didn’t like the endless treadmill of just trying endless minor variations of food and medication, because each one meant risking he’d be even more miserable for a while until we gave up on it. But even the super duper bland prescription food with a ton of pumpkin mixed in was just barely keeping him digesting anything, and he wasn’t gaining any weight back, so it didn’t seem like a permanent solution. And time continued to pass.

I think at the most extreme, I found out he’d dropped from 11 pounds to something like 7½. An entire third of my cat had disappeared. And the response from the vet felt like "Huh! That’s weird." Meanwhile I was losing my fucking mind in this slow burn that dragged on for months.

They eventually directed me to an internist — something I wish had occurred to me much, much sooner — who gave him an ultrasound. It showed his small intestine was… flattened? Like, you know how your intestines are full of cilia, all these tiny fleshy fingers, to increase surface area for absorbing nutrients? His were just like, flat. So his guts were straight up, uh, not working good. Well no fucking wonder. But we still didn’t know why.

We went through this cycle of trying a couple meds again — I remember steroids, because autoimmune was on the table — and still nothing changed. We were approaching a year of this at this point, I was constantly thinking about what a massive percentage of Anise’s lifespan that is, and I was about two seconds away from just blowing up the universe, when the internist said:

Maybe it’s FIP?”

And I said:

what”

Because it couldn’t be. He didn’t have any of the bloodwork of a cat with FIP. The usual FIP age range is very young or fairly old, and he was close to smack-dab in the middle of those. He didn’t have the swollen belly that most cats get with FIP. (Apparently that happens when there’s no immune response at all.) And most conspicuously, he was still alive, after this extensive period of fucking around.

But there is no conclusive test, so it’s hard to definitively say yes or no. The internist tested his poop for coronavirus antibodies and they were off the charts — like, I think, literally beyond what the test can accurately count — so she said, ok, let’s just assume it is.

And I said, I know exactly what to do.

The cure

Because you see, in the decade since Styx died, someone has found a cure for FIP. A cure that is effective as often as FIP itself is fatal, some ridiculous percentage like 97% of the time. It is just unbelievably good. The turnaround from “almost always die” to “almost always live” gives me fucking whiplash. It even works on cats who are in worse shape than Styx was when I euthanized him. Truly a shining moment of human ingenuity.

…There are some problems.

One is that the company that invented it has refused to submit it for FDA approval. I don’t really know why. I vaguely remember a suggestion that they wanted to market it as a treatment for human coronaviruses and thought submitting it for veterinary use would interfere with that? I don’t know. That sounds absurd to me. I definitely gave my cat several drugs I recognized as things we also give to humans in the course of this adventure, so why would this be a problem?

It doesn’t even have a real name. It’s just GS-441524. If you want some, you have to get it off-brand from a slightly dubious seller in China. I don’t know why it’s China but all the sellers seem to be in China.

The other problem is that you can’t really give it orally, because at this point the cat’s guts can’t absorb anything. So you have to give it subdermally.

Like, with a syringe.

To a cat.

Who has no idea what you’re doing.

And just as a bonus, it has to be suspended in an acidic solution, so it really stings.

And your vet can’t help you do it.

She did, however, prescribe us a big pile of gabapentin, a fairly safe anticonvulsant with the convenient side effect of significant drowsiness.

So once a day for over a month, Ash would give Anise a capsule of gabapentin, transforming him into Stumble Anise. Then I would load a syringe, we would hold him together, and Ash would inject him, and he would be real mad, and I would give him a little cat stew treat thing, and he would go in his toasty box.

(Anise started to get pretty cold, since we live in Colorado, it was winter, he doesn’t have fur, and he’d lost most of his body fat. There’s a furnace vent near my desk, so I got one of those Costco display boxes and set it up with a blanket inside overlapping the vent a bit, so the warm air would flow into it and keep it warmed up. Anise spent a lot of time in there that winter and would go there to sulk after we inexplicably bit him every day.)

And then a miracle occurred, and he started gaining weight.

After a month or so it’s apparently safe to switch from injections to tablets, so we did that, and he kept regaining weight. And he stopped having diarrhea.

And then he stopped asking for Prince Food. He would just go eat kibble and it would be fine. We might even still have a can or two of bland prescription food somewhere that I never ended up needing.

And now he’s just fine. He’s not bony any more. He’s active and engaging and incredibly annoying again. He doesn’t have such immense stomach pain that he wakes up growling.

It feels like a fucking miracle. He caught the same deadly disease that killed my first cat, and he fought it so hard no one even suspected he had it because he wasn’t sickly enough, and then with just a bit of black market medicine he shrugged it off like it was nothing.

I think that’s pretty cool of him.

The aftermath

This was all so stressful like you would not even believe, and the whole saga spanned over a year. It was often hard to work. Or sleep. At best, feeding him Prince Food every four hours was still an ADHD nightmare — I could only feed him on my desk lest other cats interfere, he would take some twenty minutes to eat (he’s always been a dawdling eater), and I couldn’t really do anything else with him in the way. I’m very glad it’s over, and I’m sure he is too.

All this has left me thinking about the series of cat eulogies I’ve written here and how I’m kind of tired of doing that. So I think I would like to post all about Anise while he’s, y’know, still alive. I’ll get on that.


And thank you, Ash, for doing some of the hard parts. I really struggle with wrangling a cat who really doesn’t want to do something — I would’ve had a hard time getting him to swallow a pill, let alone holding him still enough to stick a needle in him. I do not know how I would’ve done this without you. So as far as I’m concerned, you saved his life. Thank you.

🔞 vignettes

Post Syndicated from Eevee original https://eev.ee/blog/2025/04/21/vignettes/

vignettes is the spicy visual novel we’ve been plugging away at for the past year or so. It’s about transformation and sex and conflict and magic tricks. I think it’s pretty good! But I’m biased, so you’ll have to draw your own conclusions. By… playing it…?

It’s currently ten bucks on itch, but: we’ll be adding more stories over time, and slightly bumping the price every time. So this is probably the cheapest it’ll ever be. How compelling!

Some thoughts follow, as per usual.


I’ve been trying to finish another adult VN for a while. We did Cherry Kisses, which even did alright on Steam… but that was 2019.

Before that was Alice’s Day Off, a “demo” which never became a full thing because it relied on a combinatoric explosion and it turns out that might be a bad idea even if you know it’s a bad idea and think you can turn it into a good idea. (I will definitely try to make it work again one day.)

And then I don’t know what happened exactly. A couple years passed as a sort of indistinct haze. I wonder if anything happened in 2020 to cause that.

But by 2022 we got back to it and tried something more story-heavy this time: Clover and Over… “prologue”, which remains only a prologue. There was a branching story planned to go with it but we just… didn’t… do it.

I don’t even know why we didn’t do either of these things. We just ran out of steam, I guess. The thing itself was too big and time-consuming and it was just draining to keep working on something without feeling like we were getting meaningfully closer to an end point.

I’ve been struggling for a few years, really. Even fox flux has been blocked on level design in a way I don’t seem capable of resolving. I don’t know why I’m working on anything or who I’m working on it for. Redoing this website is one of the larger things I’ve done in ages and it still took way longer than it should have. It’s like I have a leak, and something is draining out of me faster than I can refill it, but I don’t know where it is or how to plug it.

well anyway

I did come up with a workaround here, at least — vignettes is really a framing device for multiple stories, meaning we can release something now and also build on it later. We have a loose arc in mind that’ll span half a dozen or so stories, but even if we vanish off the face of the Earth, what’s already there is still a… complete thought.

And that’s nice, I think.

I hope the next few parts don’t take so long to get out. This took us over a year — partly because of other things going on, partly because I feel like an empty husk. But I have a big pile of characters I originally designed for Clover and Over and haven’t really gotten to share with the world yet, so I’d like to do that.

I dunno. Yeah. I wanted to also say stuff about how this format lets me skip doing a bunch of Ren’Py setup work every time and makes it easier to play with the VN format without dedicating a whole entire big thing to it, but then this took a bit of a weird turn, sorry. Hope you enjoy the game.

Eevee gained 4,219 experience points…

Post Syndicated from Eevee original https://eev.ee/blog/2025/01/17/eevee-gained-4219-experience-points/

Eevee grew to level 38!

It’s been a few years since I did one of these. My birthday in 2022 was kind of overshadowed by the loss of our darling cat Pearl. But I think I’d like to get back into it, to christen the redone website.

This year

Untitled Trefoil game

Clip of a pixel art game where three chibi characters walk around a grassy field, encounter a sheep called a "Cubaa", and attack it until it's "not feeling it any more"

This was my entry for my annual horny game jam, 🔞 Strawberry Jam 8. Tragically, we did not make it. I think I bit off a bit more than I could chew by trying to design and also implement an RPG battle system in an engine I haven’t used much.

The engine in question is Godot, which I keep desperately trying to get a foothold in, and then… not… doing. By “foothold” I mostly mean a little bundle of common code I’ve written atop Godot for dealing with cases that come up a lot in games but that are too specific for the engine to include directly — a basic actor type, scene switching, that sort of thing. Just a mini library for me that’s already made all the decisions I would make, so I’m not starting completely from scratch.

I guess the other half of a “foothold” is figuring out how to make the engine do things at all. Other than a brief foray into Unity many years ago that didn’t go much further than twiddling with player physics, I just haven’t really tried using an integrated engine, and boy — in some ways, it’s harder than rolling your own everything. If a built-in gizmo doesn’t do something I take for granted that I should be able to do, then… fuck me, I guess?

But I would still like to get away from actually having to build every feature from scratch myself (like I do in LÖVE) because it just takes so much dang time, which I am then not spending on making a video game. So I would really like to get something resembling a game built and released in Godot! And this is the latest of several attempts in which I do not do that.

I think there were two big stumbling blocks here that were not conducive to wrangling a new-to-me engine in a jam setting, and I think both are partly effects of Godot’s being new-in-general:

  • There’s often not an obvious good way to approach a problem with Godot’s primitives. Nodes are a cool idea and all, but I think it’s less than obvious that you might want to use node names as an ad-hoc interface, e.g. by giving actors a collection of behavior nodes named after components or states or something.

  • There’s a lot of little oddball behavior and little feature gaps, most notably from GDScript, Godot’s bespoke language that’s “we have Python at home”. But for a non-code example: there’s no way to give a UI widget a maximum size, so if a long word sneaks into your text somewhere… don’t do that, I guess? Stuff like that that will cost you a few valuable hours chasing down only to find that it doesn’t exist.

I took notes at the time about a lot of the speed bumps I ran into, and many of them were about GDScript specifically, but I never wrote them up because… I mean, christ, I don’t want to do another epic teardown XD of a language. It’s embarrassing enough being known for the first one. Instead, let me try to summarize with a single bullet point that I hope will convey the vibe to anyone who’s ever thought about language design for a few minutes:

  • Some builtin functions can accept an arbitrary number of arguments. There is no way to write a function in user code that accepts an arbitrary number of arguments.

Anyway the short version here is that I picked too big of a project to do in a month and I tried to do it in an engine that still has a lot of rough edges.

Anise

Photo of a black sphynx cat in a wintery sweater looking somewhat solemnly at the camera, with an American flag background edited in around him and "anise 2020" poorly scribbled underneath

Anise was sick for much of 2023, which kind of fucked up that whole year, but we finally cured him this past spring. Hooray! Here is a photo of him from his 2020 Presidential campaign.

This is worth its own post, which I have already written, but it was on Cohost, which is now gone. Maybe I’ll port it over and add a bunch of cat photos to it.

Anyway he’s fine and that’s great.

vignettes

Screenshot of a visual novel where two sheep-like characters are out for a walk; one, named Clover, is saying "It's not too far, I think.  About half a mile past that burrito place where none of the waiters wear pants."

So, we released 🔞 Cherry Kisses a few years ago. (Five. Five years ago?? Oh my god) It’s a little spruced-up jam game where you walk around and talk to customers and do little sex scenes with them, accompanied by art, and also there’s an overarching puzzle aspect you can completely ignore if you want.

This was originally, as I said, a jam game, which we didn’t actually finish in time, but which took maybe a month and a half to do. At the time, I thought: wow, great! This porn stuff is E-Z. We should just crank a couple of these out a year, in between other stuff we’re doing!

Five years later, we have not yet released another porn game. Or another game on Steam at all! Not for lack of trying — we started several (overscoped) visual novels that never ended up finding their footing.

COVID and other world events kind of put a damper on things, creating a broader problem: it’s just been hard to drum up the right mood for writing extended lighthearted sex romps.

That said, we finally have something that is almost done. Actually it’s been asymptotically approaching “done” for a while. It’s tentatively called vignettes, and the idea is that we will release a shorter story, then go back and update the game later with more shorter stories, and also play around with the format if I feel like it too. Hopefully this will fix some of our scoping problems.

It’s still not done. But we did most of the work for it this past year. Like 90%. It’s so close. I’m getting back to it after I finish this post and another urgent thing.

I’m actually going slowly insane over this, because I’ve been designing characters and whatnot for VN purposes for years, and they have all been rolling around in my head like marbles that whole time, and no one outside this house knows anything about them. I need to let them out!

fox flux

Screenshot of a pixel art platformer, showing the protagonist (an orange fox) standing in a sort of basement of an abstract home, with jelly beans and chick-shaped candies floating next to her and gift boxes and furniture on a level above

Wow! When I sat down to write this post I thought I’d done basically nothing on fox flux all year. But I guess I did a lot actually. It’s not moving quite as quickly as I’d hoped, and the game is in a bit of disarray so there haven’t been Patreon builds in a bit, but, it is moving.

I don’t want to write out a whole gritty changelog here, but suffice to say I implemented a bunch of stuff that had been languishing as little stubs for a long time, so the game feels a lot closer to feature-complete. Now I just have to make a zillion levels! How hard could that be?

(It’s very hard. It’s where I got blocked, creatively! All my level ideas turned out not fun and I didn’t have any more so I went to work on other stuff for a while. Puzzle level design is fuckin’ gnarly my dudes)

Lexy’s Labyrinth

Screenshot of Lexy's Labyrinth, a tile-based browser puzzle game, showing a small fox player in a maze of ice, water, hot coals, and land mines, as well as a lot of surrounding UI

Lexy’s Labyrinth, my free Chip’s Challenge emulator, was like 90% finished, so I sat down and 100% finished it. Or, I dunno, 99%.

Highlights include:

  • Now has CCLP5, the latest and greatest community level pack! Adding this in is what got me back to working on LL, so, thanks for putting it together, everyone.

  • The tileset got a lot of touching up, and it now sports a brighter palette, instead of merely a copy of an old dull (not even pastel, just, dull) fox flux palette. The website is pink to match Lexy, too, though I fear it might be too reddish?

  • You can hold R to restart the level! At last!

  • Undo now uses much less memory, and the undo buffer is limited by size rather than time (though it will always save at least 30 seconds). On the most pathological built-in level I could find, 30 seconds was about 12 MB, and the limit is 10 MB, so this should be a huge improvement pretty much anywhere. On a sokoban-like level where the player is mostly stopping and thinking while nothing else happens, undo is virtually unlimited.

  • Rewind now accelerates the further back you go, too.

  • There are several touchscreen control schemes now: swipe, tap relative to the player, or tap relative to the viewport. So you can try whichever is least bad. There’s also partial gamepad support, though only within a level.

  • A bit more CC2 behavior is now shown visually within the level where it wouldn’t be in CC2, like dynamite always showing its full explosion radius.

  • Compatibility is vastly improved, and more of the built-in levels are beatable. (Some of the built-in levels are designed for CC1, but the default rules are CC2-like and slightly different. A couple levels now have manual patches specifically to make them beatable, a tactic borrowed from ZDoom.)

  • Support for Lynx mode has gone from “very bad” to “pretty solid”! It’s still not speedrun legal, largely because it doesn’t fully emulate frankly insane bugs like actors being able to teleport on top of each other, but it should be sufficiently accurate for normal purposes.

The editor is also vastly, vastly better; it has multiple new tools for otherwise awkward tasks, it supports arbitrary selections (including a new wand select tool), it supports CC1-style tile connections, and it can export levels in CC1 format!

I’d had code for that last thing written for ages and just never plugged it in, and I didn’t even notice until I saw someone in the Bit Busters Discord comment that LL wasn’t useful for CC1 level editing because it couldn’t actually export as CC1. Whoops.

There are also lots of experimental extra tiles, though they aren’t all fully implemented, and I haven’t made any “official” levels with them. I did start on my own level pack for Lexy’s Labyrinth specifically, but I completely forgot about it until I was writing this post just now. Wonder if I’ll ever finish that. 200 levels is a lot, but it’s also good practice.

Doom stuff

Screenshot of an "idgames archive" website listing, showing two Doom WADs that list their maps with some stats, whether they support skill levels, whether they have music, etc.

In August, Microsoft unveiled an entirely redone official Doom release, now with Boom support, making it compatible with more of the Doom ecosystem.

That was weird, because Boom is a third-party fork of the open source Doom release, meaning it’s GPL. And there was no release of the current Doom codebase.

Turns out that what Microsoft did was pay someone to cleanroom Boom from scratch, effectively laundering the GPL off of it, so that they could add open source extensions to Doom (an open source game) and make it proprietary again.

I found this… frustrating. But a lot of Doom people didn’t really care and mostly found it neat that they can play Doom on an XBox now. (It’s notoriously difficult to put someone else’s GPL code on a console. The console APIs are all covered under NDAs — you know, to prevent anyone from finding out that the XBox uses DirectX — so you’d be in a position where the GPL requires you to release your modified code, but the NDA requires you to not do that.)

Instead of sitting around being mad forever that the very people who’ve benefitted so much from Doom’s being open source don’t really care about open source, I tried to pour it into something slightly more constructive, and so I started tinkering with an improved idgames frontend. I guess the idea was that people mostly seemed to value having a WAD browser built into Microsoft Doom, but there’s no reason we can’t have that for the entire archive of everything ever made, right?

I ran out of steam before it got too far, but I did get it doing a few interesting things, like automatically producing screenshots of the opening shot of each level (which you can see in the screenshot above). I had some other ideas, like trying to infer qualitative descriptions of level size and difficulty, but didn’t quite get around to it. Oh well.

Screenshot of my Doom text generator, with a selection of fonts and colors and text rendering sliders, currently displaying "Instead, I worked on this some more"

So I went back to my Doom text generator, a former advent calendar project that I cranked out in a day and wrote about before. I’d seen a couple people mention having actually used it, which was cool, so I went and did some stuff to it.

  • It could only render its own built-in fonts, so an obvious extension was to extend it to load fonts of any format from a provided WAD or PK3, all client-side.

  • It has a truckload more built-in fonts now, courtesy of Jimmy Paddock’s collection. So the Doom text generator can now generate Duke Nukem text, too. Weird.

  • It can, finally, combine multiple fonts in a single message, using a tiny bbcode-like markup language.

  • It can generate a bunch of images in bulk, which is exceptionally handy for level authors targeting vanilla-like Doom, where you have to provide your own level name images. It can even read the level names directly from a MAPINFO file that more advanced ports would use to render names themselves.

Now it’s got a Doomworld thread and source code (little redundant since it’s all shipped to the client) and everything. It’s like a real project! I’m glad people find it useful.

It even got a Cacowards 2024 sidebar shoutout, which is cool, making this basically the only thing of note I’ve ever done in the Doom ecosystem. The Boom license laundering also got an explicit shoutout, though, so. Cool.

Sudoku

A sudoku with no given digits, but several diagonal clues outside the grid and some killer cages inside

I made some sudoku, after realizing I could just make some sudoku if I wanted to. My first one is appropriately titled 1 (killer + little killer), and the rest are on my new puzzle index. Speaking of which—

You are here

Screenshot of this post

I redesigned the website in the wake of Cohost’s shutdown, and after several years of not writing much. Time will tell if it encourages me to write more going forward, but so far, so good.

I also wrote those pages about stuff! The list of variant sudoku types (which I’ve even used for my own reference already), and ports of my Lights Out and Rush Hour CSS crimes from Cohost.

This year

I basically forget about any aspirational list like this within a week, but I would really really like to:

  • Get vignettes released, and get a couple more stories added to it!

  • Get fox flux out of its level design rut and just accelerate into building the game proper. Also more patron builds.

  • Write more, I think. I do kind of miss it.

I’d like to… reconnect with the world, I guess. Everything feels disconnected. I dropped Twitter and tried to rebuild on Cohost, did not really succeed at that (there’s a post in that, too), and then Cohost went down. Now there’s Bluesky, I guess, but I feel like I’m two platforms and several years in the hole. And a couple closer friendships disintegrated over the same period, so I have been adrift as all hell.

And the primary way I know how to connect with anyone is through my work! So I need to make some!

Fresh start

Post Syndicated from Eevee original https://eev.ee/blog/2024/12/03/fresh-start/

I hit a point where I just didn’t like this website any more. It was too… stuffy. Posts kept getting longer, more elaborate, more time-consuming to write. I didn’t recognize the tone any more, and when I look back at older posts, those are way snarkier than they need to be. I think I was trying to be taken seriously-but-not-too-seriously, and the voice that developed as a result was just really weird.

I kept looking at this blog and thinking… who is this? Who wrote this? And who is supposed to write more of this?

So I’ve changed everything.

Design

The previous design was based around “keep looking like sort of like the default Octopress theme I used to have”. I don’t think that was a great design philosophy, not least of all because I stopped using Octopress in 2012, and Octopress itself has been abandoned since 2015. But it was also just… beige. I think I was hoping that brown-ish would be reminiscent of Eevee colors?

So I redid it from scratch, based on the new design philosophy of “I like it”. And you know what? I like it! I hope you like it too. But also, I don’t care too much if you don’t, because it’s for me!

Also, hey, did you know CSS can do all kinds of crazy stuff now? Like nesting blocks? This blog used to use SCSS! Now it doesn’t need to! And I barely had to change anything! Maybe there’s a post in there.

You might need a recent browser, but you should be using a recent browser anyway.

Landing page

The landing page is also completely different. (I’ve preserved the previous one, if you’re interested.)

My time on Cohost, which allowed near-arbitrary inline HTML and CSS, has rekindled a joy in doing stupid tricks with CSS, and so I’ve glued together a mountain of stupid tricks to make something more playful and distinct. Also I can draw better now than I could a decade ago, so I flexed those muscles a bit, too.

One thing I do slightly lament is that my games used to be above the fold (at least on my screen), and now they’re not. But I think this design actually rewards… scrolling down? So hopefully that helps. Not like I’m collecting metrics or anything.

Résumé

I’ve intended to do this for ages. The old landing page contained an exhaustive list of… most things I’ve made or worked on, which made it kind of a cluttered mess. Now that exhaustive list has a real home as the landing page for c.eev.ee. I’ve been using this to host stuff (like Lexy’s Labyrinth) for ages, but the root page has been a 403 that whole time. Now it’s not! Wow!

Also: a list of my puzzles! There aren’t too many yet, but maybe there will be??

Articles

Pelican has both “articles”, which are dated, and “pages”, which are not. I looked over a lot of my old posts in the course of this redesign, and a lot of them are either out of date w.r.t. technical information, about an event that was only interesting for a brief time, or just… unmaintained?

Which all makes sense for something that has a date, right? Like, Wikipedia articles don’t have a date. Those are assumed to be reasonably current. And there’s something a little sad about writing a very lengthy post with a lot of details about something, and then watching it sink into the ocean of time. But keeping a post with “2015” in the URL up-to-date indefinitely doesn’t seem quite right.

So I’m taking a crack at “pages”. I expect the presentation will change a bit as I accumulate more, but I’ve seeded the idea with a couple starter pages:

  • Two pure-CSS toys/puzzles that were originally Cohost CSS crimes, now tidied up and with full
    explanations: Lights Out and Rush Hour.

  • A lengthy list of variant sudoku types with full rules and examples, something that I hadn’t seen anywhere else.

I changed all the URLs sorry

At some point I put the category in the URL, so “normal” blog posts were at /blog/foo, whereas my dev log posts were at /dev/foo. I don’t know why I thought that was a good idea, and it makes it annoying to reshuffle the categories, so I’ve collapsed everything back into /blog.

There are redirects up the wazoo so this shouldn’t matter to anyone. But if you find a link to my site that 404s, I must’ve missed a redirect, so, please let me know.

The cool news is that instead of reverse-chrono categories, there’s now a much better way to find a post you’re looking for: I made a full list of all my writing! Enjoy. But don’t read anything from before 2015.

Pardon our dust

I probably forgot a lot of little things, and the layout is still a bit work-in-progress on very small screens. I’m also not entirely sure how to convey the distinction between articles/pages at a glance, and I don’t have a real name for the c.eev.ee page, so it’s called something different everywhere it appears.

Feel free to send me your nitpicks; I’d like this design to be more actively maintained than the old one was.

Coming up next: Posts?? More posts?????? Remember when I wrote posts????????

Monday Night Itch #1: Mystery Trap Adventure

Post Syndicated from Eevee original https://eev.ee/blog/2022/01/31/monday-night-itch-1-mystery-trap-adventure/

Welcome to Monday Night Itch, a harebrained scheme to encourage folks to play more non-AAA games by adding a touch of social gamification. I thought I would be tweeting my adventures here, but I just had an experience so profound it can only be captured within a blog post.

The rules

Rules” is a strong word, but nevertheless:

  • Every Monday, find a game on itch.io, and pay at least $2 for it.

    You can buy a game with a price tag, or download a free game and leave a tip, but the point of this endeavor is to put money into more places in the ecosystem. (Note that it is possible, though uncommon, for a developer to disable payments altogether.)

  • Play it.

  • Leave a nice comment.

  • Tell at least one person what you played, and what you thought about it.

That’s it. Buy a game, play it, tell someone about it. You can stream it, tweet it, screenshot it, or just tell your boyfriend about it. You don’t have to like it

Your score is how many times you’ve done this, and your streak is how many weeks you’ve done it in a row.

Some other quick tips about itch

The itch app is cool. It’s a pretty thin wrapper around the website, but it adds automatic updating and big red “Launch” buttons and other stuff to make it feel a bit more like a Steam-ish thing. Do keep in mind that devs can upload whatever they want, and sometimes the itch app gets confused.

If you’re not a fan of running mystery software you downloaded from the Internet, you can just play web games and leave tips on those.

There are a lot of NSFW games on itch, but they’re hidden from the main browse pages by default. You can enable them site-wide in your user settings, or add /nsfw to the end of a browse page URL (for example, https://itch.io/gameshttps://itch.io/games/nsfw) to force a list of only NSFW games.

The main event

I decided I wanted to reward Linux releases, and also chip a few bucks towards games with a price tag that aren’t necessarily getting much exposure, so I went to the full list of recent paid Linux games. This is how I discovered Mystery Trap Adventure.

I found myself very much wanting to play this, but I also found myself wondering what sort of impact I should be trying for as the very first iteration of this project. Would I torpedo it if I played a game made by a less experienced dev? Are people looking to this expecting me to uncover unknown indie gems, like I’m wandering a beach with a metal detector?

I checked the dev’s itch profile and this is their ninth project. Every single previous work of their has only a single comment: from them, announcing that comments can be left below. That’s heartbreaking to me, and what made me absolutely sure I wanted to play this. I want to make their day.

And then, dear reader, I felt ashamed. Because who the fuck cares. The world already has enough people who believe that indie games are only valuable if they create the illusion of an eight-digit budget, and I am not here to enable them. Creative work does not need to be polished, mass-appeal, least common denominator stuff handed down from heaven by a billion-dollar international corporation in order to be interesting or worthwhile.

But more importantly, it’s my thing and I’m gonna do whatever the hell I want.

The title screen for Mystery Trap Adventure: a collage of mismatched artwork on a nearly cyan background

And so, Mystery Trap Adventure.

The first thing to note is that the game does not, in fact, have a Linux release. I did strongly suspect this, since a single download is flagged as all of Windows, Mac, and Linux, but the only way to be sure was to buy it. (They’re asking $4; I paid them $10.) Even Wine had trouble with it, for some reason, so I had to play it on our Windows media center.

It’s a sidescrolling platformer where you play as a dragon; you can jump about one tile high (roughly your own height) and shoot fireballs (useful for destroying bricks and defeating the boss). The main obstacle is spikes, which kill you instantly.

Right at the beginning, there’s a block you have to jump on top of, and it was very obvious that I sort of “stuck” to the side of it if I touched it. I thought at first that this was the result of a common platforming gotcha: if you model the player as a dynamic body and implement movement (including air control) as a force on them, then they will stick to walls as long as the corresponding direction is held. This happens because forces on dynamic bodies are external, as though a giant ghost hand were pushing them — so if a player is trying to air control into a wall, the friction against the wall will hold them in place, just as if you were holding a book against a wall with your hand.

(Solving that problem is beyond the scope of this post, sorry.)

Okay, common pitfall, no big deal. I wander ahead a bit. I encounter a slice of watermelon, which allows me to teleport a short distance once. I screw this up the first time while messing with the controls — there’s a wall directly in front of it, so the teleport must be used to skip past that wall — and have to restart.

Now something interesting happens. I’m in a pit with walls on both sides. I can’t teleport again, and even if I could, there are spikes beyond the next wall, so that would kill me immediately.

A screenshot of the situation just described

It dawns on me that this microscopic game has walljumping.

I’m still fairly certain that the player character is a dynamic body, but now I wonder: is the wall stickiness actually due to the friction interaction, or is it a deliberate feature to enable walljumping?

Or, perhaps more likely, is it both? Did the developer trip over this pitfall, and decide to make a gameplay feature out of it? It almost seems unbelievable. I wouldn’t consider walljumping a basic platforming ability, and it’s not obvious how to solve the friction problem, but it seems that this relatively new developer may have solved both problems by simply smashing them together.

And if that’s the case, dearest reader: I fucking love it. That is the true spirit of game development, I think — you have a big complicated simulation you want to make, and you have a big complicated engine that you want to make do it, and you have to kinda mold both of them into fitting better with the other.

I don’t know. I could be completely wrong about this came to be. Or they could have copy/pasted from someone else who had this idea. Either way, it made me smile to see.

The walljumping controls are, ahem, not exactly intuitive, which is why it took me nonzero time to realize it was an ability at all. But honestly, I liked that too. Nowadays, everyone knows exactly how every platforming ability is “supposed” to work, because devs are all copying the same ideas from each other that have been refined over a thousand different iterations. This reminded me of playing games in the early and mid 90s, before everything had standardized as much, when part of the game itself was just working out the right muscle memory to make the right things happen. It’s surprising to find nostalgia in a game because it’s not like others I’ve played before, but there it was. Working out the right timing without any visual cues felt like a puzzle in itself, and getting out of the pit without landing in the spikes was remarkably satisfying. (If it helps: I used different hands for movement and jumping, and I landed on top of the right wall before trying to jump over the spikes.)

Beyond this, the tone changes somewhat to IWBTG-esque traps with no telegraphing. Walking directly to the right will cause spikes to appear from the ground, killing you instantly. Thankfully there aren’t too many of these, and the game is very short, so simply memorizing the handful of places they appear is easy enough.

I have less to say about the rest of the game; you get another quirky powerup you only use once, dodge another couple surprise traps, and face a single boss. The boss is a very large human warrior dude who walks straight at you and swings his sword, which kills you. There’s another fruit above you, but it seems out of reach. He is definitely too tall to jump over. The only solution I found is to simply spam fireballs at him before he can reach you, but I don’t know if this is intended. It seems like it can’t be, since his “health bar” takes the form of a grid of his face behind him, and from where you enter the area, you can’t actually see the whole grid? So surely I’m supposed to be able to get further to the right? But I don’t know.


I finished the game and came back to the following reply to my original thread about this whole concept:

most, i.e. all, small Indy games are terrible.

What a snotty, entitled, mean-spirited sentiment. As if the very existence of a game with lower production values than Resident Evil 8 were a personal offense. It seems to be fairly common, too, and I just do not understand it. Small indie games aren’t trying to squeeze you for more money, lure you in with gambling, exploit your friendships, make your entire life revolve around them. They’re just there.

This attitude is like showing up to everyone who mentions YouTube just to proclaim that everything on it sucks, because Paramount movies are better. That’s great, no one asked! Sometimes I just want to see a seven-second clip of a kitten filmed in a dark room by a $20 phone, because dammit, kittens are still fun to watch. No one makes a point of dunking on videos like that, so I don’t know why anyone is so harsh on amateur games either. Especially when making games is so much more difficult!

Mystery Trap Adventure is that video. Someone had an idea, worked out how to express it, and put it out into the world just because they wanted to. I don’t expect anyone else to buy it or play it; I just want you to know that I did, and it made me smile for a few minutes.

Goodbye, Pearl

Post Syndicated from Eevee original https://eev.ee/blog/2022/01/25/goodbye-pearl/

Pearl laying on carpet, bathed in a sunbeam that highlights her peach fuzz

A Chronicling of the Lyfe and Times of one Miss Pearl Twig Woods, who has Passed at a Young Age from Troubles of the Heart. She is survived by Anise, her Arch Nemesis; Cheeseball, her Adoptive Ruffian; and Napoleon, her Star-Crossed Suitor for Whom she Longed from Afar.

Pearl is… difficult to describe. She had such a strong, vibrant personality.

She was lovely, that’s for certain. She loved everyone she met. And while various people — friends, vets, etc. — have met our cats and always liked them, I don’t believe anyone has met Pearl and not adored her. Anise will check out your stuff and perhaps jump on you; Cheeseball will do antics for you and rub on your leg; but Pearl would accept you into her life and be very directly, personally affectionate with you specifically. She made you feel special.

At the same time, she was very fussy, very particular, and had a very strong sense of… her place in the world, I suppose. If she liked something, she would be having it. If she didn’t like something, she would make that exceptionally clear. She was never mean, but she would be very vocal about her boundaries.

It wasn’t uncommon to wake up to Pearl repeatedly headbutting me right in the face, pressing her head up under my chin, or giving me a nuzzle with the entire length of her body, purring all the while. If she was happy to see you, she made an entire production out of it. It wasn’t just us; guests who slept on the couch also got the Pearl wake-up call.

It was also not uncommon to wake up because Pearl had decided that she needed my pillow, and somehow this very small cat took up the entire thing. I couldn’t move her; trying to displace her from a comfortable spot would generally earn you a sad, offended meow, after which you felt guilty for even having entertained the notion in the first place.

One of her particular quirks was to often “bury” her food when she was done with it, or at least paw fruitlessly at nearby carpet. On its own, this is endearing but not unusual — burying leftovers is a common cat instinct, even if we’ve not seen it in our other cats. What made it a uniquely Pearl trait was that she would also perform this ritual if offered something she didn’t want at all. I laughed every time; it was such an audacious way to indicate utter disinterest. Take it away, please. Put it in a hole, if you would.

She got, more or less, everything she wanted. If she claimed a spot, everything about her expression and body language indicated it was clearly hers, even if that spot was your body. (Naturally, if you moved too much or even sneezed suddenly, she would tell you off for that too.) If she wanted to ride on your shoulders, that’s what would be happening. If it was time to feed her and she was too comfortable in her cat tree, well, we’d just have to hold the food up for her. She had a way of looking very pleased with herself that was impossible to argue with.

I first met Pearl in 2014, shortly after we moved to Las Vegas. She was tiny, even for a kitten, and apparently the runt of her litter. I don’t remember what specifically compelled Ash to adopt another cat, except that they love cats, but what a selection.

I cannot stress enough how small she was. You know those solid wood desks that have a column of drawers built into them on one side? You know how they often have a little decorative shape carved out at the bottom with molded edges? Pearl could crawl into that space. I couldn’t believe it the first time I saw it; the gap is so short that I’d never even thought to categorize it as a space, let alone one a cat might enter, but she slunk into it like it was nothing. I was so worried we’d have to move the desk somehow to get her out, but she usually turned around and came right out again. I still remember the very last time she did it — I could tell she was having to shimmy a bit to fit in there, and she must have noticed too, because I never saw her even try it again.

The other cats had somewhat mixed feelings. Napoleon didn’t like her at all and hissed directly in her face, but… after that, I don’t remember any bad reactions from him at all, so I guess he warmed up quick. Anise did not seem to understand what a kitten was, tried to play with her, and then acted very confused when that didn’t seem to work. And Twigs…

Oh, Twigs. Twigs was jealous. He had always been Ash’s cat, he had made himself Ash’s cat, and he very quickly inferred that Pearl was a threat to his position. Another cat! In Ash’s lap! Unthinkable!

On one particular night Ash had barred Twigs from the bedroom to sleep with just Pearl, but came downstairs to visit the kitchen. Twigs ran up to them, looked them dead in the eye, and let out a huge sad wail to convey his feelings about the depths of this betrayal.

They let him into the bedroom after that, but he opted to sit across the room and stare daggers at Pearl, moving a little closer every half hour until he was on the far corner of the bed. Just staring.

Ash eventually had to bribe him by putting some cottage cheese on Pearl’s head, after which he decided Pearl was okay. Also he found out that he could fit himself in Ash’s lap alongside Pearl, so that probably helped.

Oh, and she loved to be cozy. She loved to be cozy. Sphynxes are naturally drawn to warmth, of course, but Pearl elevated it to an artform. If I’m propped up in bed, Anise might stand next to me to look at the covers expectantly, or he might just lay down nearby. Pearl would stand right on top of me and pull at the covers with impressive force until I lifted them for her, let her lay on my chest, and tucked her in.

We’d often find Pearl very awkwardly tucked under the edge of a blanket somewhere, having attempted to insert herself beneath it with mixed success. We described this as Pearl doing it all by herself, and complimented her on how talented she was, and then fixed the blanket for her.

We have heater vents in the floor, and one of her favorite pastimes was to sit on one of those, often covering the entire thing, and be gently toasted from below. Sometimes Anise would see what a great idea that was and try to share it and they would end up squabbling.

If there was a sunbeam to be found, Pearl would find it. Much like with vents, she didn’t like to share sunbeams, even if they were half the width of the room. She found it first, you see.

Other places she discovered that were lovely and toasty included: in front of the fridge where the warm air vented out from the bottom; straddling the PS4 so the fan blew onto her tummy; next to or underneath my laptop; on top of my computer case which has a fan vent on top; in front of the heat dish we got while our furnace wasn’t working; and in a laundry hamper full of freshly-dried laundry.

She liked to go outside, too, during the summer. All of our cats are indoor-only, but once in a while we’ll take the more well-behaved ones (not Cheeseball) into the backyard to wander around on the porch and sniff things and enjoy the sun and look at a bird.

And I have never known a cat to be quite so comfortable. Perhaps Anise, on occasion, but he doesn’t have the raw talent Pearl was born with.

You could tell she was settling in if she tucked her paws in against her chest, something she always did quite deliberately and distinctly. But that was only the first stage of comfort. If you were lucky, she would stretch out one arm really far, perhaps to place her paw on you. As she dozed off she might lay flat on her side with her limbs outstretched, which meant we always had to check blankets carefully for a flattened Pearl before sitting down. And if you were really lucky, you might witness Pearl in a chaos configuration, upside-down with her paws wherever.

But even just sitting up with her eyes closed, she looked so content. Looking at photos makes me want to take a nap with her.

Sadly, Pearl had some health troubles from the start. She had a kink right at the base of her tail from the day we got her, suggesting it had been injured while at the breeder and not healed right, so she was never able to raise her tail all the way. She also came home with some sort of intestinal parasite that gave her a lot of… um, gastric distress, and while we were able to clear that up quickly, it seemed to recur soon afterwards.

We took her to the vet again, suspecting more parasites, but multiple tests turned up nothing. We tried a number of things — different food, sensitive-stomach food, wet food, more water, different treats — but could not seem to figure it out, and so Pearl just had stomachaches on and off for a while. Sometimes she would sit by the litterbox and grumble, and all I could do was try to reassure her.

It wasn’t until a few years later that Ash’s then-husband, with no explanation whatsoever, spontaneously decided to just feed her some plain chicken mixed with pumpkin purée. Just like that, she was fine. I felt like kind of an idiot for not trying that earlier, but after giving her veterinary sensitive-stomach food and seeing no change, I thought we’d ruled out food sensitivity.

We swiftly outlined a general idea of what Pearl could or could not tolerate. Chicken, pork, pumpkin: OK. Beef or any kind of organs: she immediately threw up. Fish: no good. And yet manufactured food containing only very simple things still gave her stomachaches, so our best guess was that she also couldn’t tolerate fucking xantham gum or something, which is in pretty much all pet food, including the sensitive stuff.

Regardless, we had a diet she could stomach, so for the rest of her life we made her a custom diet of ground chicken, ground pork belly, pumpkin, and some nutrient powder that didn’t bother her (which took several attempts to find). That meant no more free-feeding the other cats, so we got a big dog cage to keep the kibble in, and we’d let the other cats in there while Pearl was eating her special princess food. Thus began a multi-year saga during which, every four hours, like clockwork, Anise would start bothering me to feed him.

Please do not tell me what I could have done to dissuade Anise or space out the schedule. I guarantee, he is vastly more dastardly and annoying than you are giving him credit for. The cats run this household, and I have long since made peace with that.

The closest to any real insight we got about Pearl was that perhaps her kitten parasites had left her with IBS — a very vague diagnosis of exclusion, and the best anyone could come up with. But Pearl was happy, so that was good enough. We eventually found new treats she could stomach, too.

Pearl had relatively intense relationships with the other cats, much like she did with people.

She adored Napoleon, our furred and largest cat, for some reason. She often trotted up to him, very eager to sniff him; or when he trotted towards the kibble cage in recent years, she would run alongside him, staring sideways at him. I don’t really understand what her feelings were, and Napoleon didn’t really return them, but he at least tolerated them. Curiously, I can’t remember many attempts on Pearl’s part to snuggle up to Napoleon; she mostly snuggled with the other sphynxes.

She and Twigs (her uncle, incidentally) spent a ton of time together, and Anise was often in the mix as well. They’d often end up in a pile under or within a blanket, or all wedged into the same cat bed, or piled on a chair that had a towel on it. Sometimes she’d grumble at Anise for being too much in her personal space, but somehow Twigs’s presence seemed to defuse everything. I can’t remember her ever grumbling at Twigs, in fact.

Cheeseball is the only cat we have who’s younger than Pearl. When he was a kitten, she kind of doted on him like a mom, frequently trying to groom his head. She kept doing this into his adolescence, even as he was swiftly growing bigger than her, which was endearing and also very funny.

We moved in 2018, and spent the summer with a former acquaintance’s parents, as they had a finished and furnished basement that was practically an apartment all on its own. Unfortunately, they had four cats of their own, for a total of nine crammed into a relatively small space. (One of the parents couldn’t be around cat hair in the medium term, due to reasons.)

One of the cats, Seamus, was a maine coon, and by all accounts kind of an asshole. He made a habit out of chasing Napoleon around, which Napoleon did not like at all, and which would result in Pearl chasing him to defend Napoleon, and then Anise chasing after Pearl because everyone is running around and he doesn’t quite understand why but he doesn’t want to be left out. We kept the cats separated as best we could, but we didn’t have much space to work with, and we were already trying to sequester Cheeseball, who we’d just adopted as a kitten. Everything was just kind of a mess.

Anyway this kinda stressed everyone out.

I bring it up because of one particular event. The only segregated parts of the basement were the bathroom and a somewhat awkwardly-shaped bedroom. The bedroom was exclusively for our cats. I don’t remember exactly what led up to this, but at some point Seamus made a beeline for the bedroom while Pearl was just inside the open door. I’m guessing Napoleon was in there too.

Pearl was absolutely not having this. She stood her ground and hissed hard enough to stop this absolutely massive cat in his tracks. She was so mad that she peed on the floor (which was, thankfully, vinyl). We got there to intervene about half a second later, but wow! She drew a line in the sand and under no circumstances was this bully going to cross it. We have always looked back fondly upon this “rage piss” incident.

I think Pearl was left a little rattled, though. Even at the time, she growled at the other maine coon there, who was an absolute sweetheart and rarely did more than sit nicely and ask to be pet. Once we were out of there, she seemed a little distrusting of Anise, often growling at him or biting his haunch merely for sitting nearby (which would entice a bewildered Anise into smacking her, justifying her reaction). I wish we hadn’t stayed there.

Cheeseball was also growing up and wanted to play with Pearl, because playing is how he engages with pretty much everything; alas, he was a bit too rowdy for Pearl. Twigs, infinitely patient, was there to absorb a lot of this.

But then Twigs died, and the cats’ relationships seemed to deteriorate. Cheeseball liked Pearl, but he always wanted to fight with her, which she didn’t like. Anise liked Pearl, but she seemed to resent him a lot of the time, and there was no Twigs to separate them. Pearl liked Napoleon, but Napoleon liked to be by himself.

It was okay, but tense.

Maybe I’m overstating this. Going back through photos of Pearl, I’ve found plenty from the post-Twigs era where she’s still hanging out with Anise peacefully. A number of their conflicts even started because she would approach Anise to sit by him, then growl at him. No wonder he was confused. Sometimes she would groom him and start growling, while licking his ear. Hello? What are you doing?? What do you want from him here.

Still, that must mean she still liked him. She just had some complicated feelings. It always made me a little sad when they couldn’t get along, though. I’d gotten Anise in the first place in part to give Twigs a friend, and Pearl and Twigs had always gotten along well, and now… well.

Having said all this about how great and lovely Pearl is, her presumptuousness also made her a huge pest in some very specific ways. For example, once we’d settled into the food routine that saved her from constant stomachaces, one of her favorite things to do was to go over to the kibble cage and try to find kibble that had escaped from it. If she could get away with it, she would stick her paw between the bars and pull kibble (or the entire bowl) out to eat.

It was slightly annoying, and also very funny. We called this pulling a heist. And then she’d have awful gas some hours later.

I also very distinctly remembering getting takeout one time, which happened to include a breaded and fried slab of fish. I had the little takeout container on the table in front of me, and I think I was fiddling with the wrapper on their plastic fork or something, when Pearl came along, sniffed it… and then bit the fish and pulled the whole filet out of the container. Right in front of me! Points for boldness, I guess. She wasn’t quite so audacious any other time, but she must’ve really liked the smell of that fish.

And while she was generally pretty picky about what she would consider a toy, she did, on occasion, like to bite the arms of my glasses. Once I was laying next to her and petting her while she purred, and she stuck a paw in between my glasses and my face, pulled them off, and tried to bite them — purring all the while.

My favorite Pearl trick was what we dubbed “mouse alert”. If Pearl was looking for someone — often anyone at all, but sometimes a particular person who was absent or in a room with a closed door — she would find one of her toy mice and carry it around doing a very loud, muffled meow. If she saw you she would then drop the mouse and trot over, making happy high-pitched meows instead.

Sometimes she’d start out with regular meows, which we could hear from the other side of the house, but then they’d abruptly turn deeper and longer, and we knew she’d picked a mouse up. It was so charming and so funny. Every so often we’d find a pile of mice outside a door and we knew that Pearl had been trying to open it. She later expanded her roster to include Big Mouse — a plush almost half her size who became her favorite — and a plush of a single HIV virus that she must’ve stolen from my desk.

She didn’t play with the mice, either. I have video of her playing with a mouse when she was fairly young, but it’s not one of the mice we have now. She seemed to regard them as precious, her comforting belongings that she could almost always lure us out of hiding with. “Come look at my mouse!” Sometimes she’d carry them around quietly, just to have one or two nearby in a comfortable spot.

I tried for her whole life to get a recording of this, which proved nearly impossible, because she’d stop if she knew anyone was nearby! I got a clear recording only once, a week before she died; I was in our dark bedroom, filming into Ash’s office, and I don’t think she realized I was there. There’s a link at the bottom.

Her other favorite possession was string. Pearl loved to play string. She would ask for it by name. No, really. If she wanted to play string, she would find (or bring) a string and sit on it hoping someone noticed, and if that didn’t work, I’m pretty sure she had a specific meow for asking you to please follow her to string and then play with it.

Playing string with her was a slightly frustrating affair, but perhaps I just didn’t understand the rules. They seemed to be: I should wiggle the string; then Pearl grabs the string; then Pearl keeps the string. That doesn’t end the game, though. I should keep trying, in vain, to get the string back, while Pearl simply keeps winning.

A great thing to do was dangle it above her, at which point she’d stand up to try to get it and chomp at it, audibly. I loved her little chomp sound. I can’t even do it myself; I feel like I’d hurt my teeth.

After she was through adolescence, string was the only thing she really wanted to play with. She might’ve chased a laser pointer a couple of times, but string was the one thing she would ask for. Occasionally I’d try to play with Anise with a string, but Pearl had a fucking sixth sense for when string was happening, and she would appear from nowhere and go absolutely nuts over it while Anise sat back and watched.

In March 2021, I took Pearl to an ER vet over very rapid breathing. They told me she’d had fluid in her lungs and diagnosed her with congestive heart failure. That’s when your heart can’t pump hard enough; part of Pearl’s heart wall had thinned and weakened, and one chamber was enlarged. She had to be hospitalized overnight. I drove home thinking I’d never see her again.

They couldn’t identify a cause. She was given a prognosis of “not fantastic” and prescribed a growing mountain of medication, which Ash dutifully gave to her every twelve hours for months on end, even when Pearl refused it. Sometimes Pearl had to be bribed with treats in order to eat at all, though I later traced that to a batch of food with insufficient pumpkin for her liking.

We had to keep her stress level low, which meant keeping her completely separated from the other cats (or at the very least Cheeseball) as much as possible. That meant Ash vanished into a closed room for most of every day to work while keeping an eye on Pearl — who was, after all, Ash’s cat. That also left me with three other cats constantly vying for my attention.

For several months we often couldn’t even sleep in the same room — Pearl and Anise couldn’t be left together, and Anise makes a racket all night if he’s shut out. Early on, our roommate would often take Pearl overnight (even despite being allergic to cats), but as time went on, Ash felt a stronger impulse to be around her as much as possible. Eventually we found we could have both Anise and Pearl overnight as long as we put a sweater on Anise and had sufficient extra blankets on the bed, but honestly it felt like a constant logistical nightmare.

Even with all this, we still had several more ER visits, several more hospitalizations.

Still, Pearl seemed to be doing okay. She was happy, she engaged with us, she purred, she snuggled, she nuzzled, she played. She was fine, and stable, until she wasn’t.

It was January 11, and it was the first ER visit for rapid breathing in a while. We handed her over, they hospitalized her, and we left, assuming we’d pick her up in the morning and she’d be fine, as had always happened.

We weren’t home for long before they called us. Pearl wasn’t recovering this time, and wouldn’t make it through the night.

We raced back. We saw Pearl, struggling to breathe, even on oxygen. We pet her and told her it would be okay. She cried out for help. Ash held her.

And then we let her go.

I love and miss so many little things. She had such beautiful eyes, like Twigs did, though she squinted a lot so it always felt like a special treat when I could see them clearly. Her whole face scrunched when she meowed. She had a marble pattern, so I guess she would’ve been a calico. I didn’t even notice it when we first got her, and then one day it jumped right out at me and I felt briefly like our kitten had been replaced with a different one. She had a funny little clump of four hairs that stuck out from her hip. She had marbling on her pawpads, too.

I love her wide vocabulary of very cute little meows, in contrast with Twigs’s more raucous ones. She reserved them for special occasions, opting to chirr most of the time.

I love how, when she was surprised by something, she would simply jump straight up in the air an inch, then come down. No other movement. It was like she was tweened. I never tried to spook her on purpose to see this, but she was a little prone to being spooked.

I love how, when she’d knead at a soft blanket, she did just a few quick little motions and then she was done. It was so dainty. I always called it kitty paws, to distinguish from cat paws.

I love how she’d do a straight upwards stretch that somehow made her ears flick inside out briefly.

I love the very deliberate way she tucked her paws, and how she would gently hold onto someone’s shoulders while getting a taxi ride. Everything she did came across as so purposeful.

I love how Ash had found that rubbing their face on Pearl’s side as a kitten would get her to purr, and that kept working for her whole life, and it’s basically what she ended up doing to people in return.

I love how she had a funny obsession with water. I can’t really explain it, and I don’t know what she found so interesting. If I took a swig from my water bottle with Pearl nearby, she would climb on whatever was necessary to sniff at the nozzle. If I opened a soda with Pearl nearby, she’d stick her nose right in the opening, then recoil when the bubbles fizzed her. She didn’t enjoy baths or anything, she just liked… water. From afar. Like with Napoleon, perhaps.

I love how she nuzzled so hard that she hit maximum nuzzle, and so she would also sort of gently swipe the air with her paw as well, for extra nuzzling power.

I love her funny “bug off” sweater, illustrated with a ladybug, which seemed to capture her personality well: don’t be rude to me, but expressed in a very cute manner.

I love how she adopted the sort of extended windowsill in our bathroom as her own, and would lay there on sunny days and roll around on a towel.

I love that she was pampered right to the end. Over the course of recent weeks, Ash would keep giving me updates on Pearl’s development of a new routine, where she would sit in a Treat Spot she had designated, possibly meow once or twice, and wait very nicely until Ash gave her a treat. And then Ash would eventually capitulate, helpful before the polite ministrations of this very tiny cat, and give her a treat. It seemed that the number of treats Pearl was managing to get per day was gradually increasing, and so I asked every time: why not simply not give her a treat? But I knew the answer.

If you cried, there were decent odds that Pearl would come and comfort you, come chirp at you and nuzzle until you felt better.

When we first moved here, Ash’s ex-husband had driven the truck containing all our stuff, and he slept here one night before leaving for good. The day after he’d left, we heard Pearl doing mouse alert in the room he’d slept in, and I just broke down sobbing at the kitchen table, thinking about how Pearl liked him despite everything and was just trying to find him, and we had no way to tell her he wasn’t coming back or explain any of it to her. To her, one of her favorite people had just disappeared, and that was so sad.

But Pearl heard me, came over, jumped on the kitchen table, and purred and headbutted me like crazy. The idea that I was sad for her and she still wanted to comfort me made me cry harder.

She would also headbutt and nuzzle Ash specifically on the mouth when they sang, or do the same to me if I whistled competently. I suppose she liked music, but only from us.

Most of all, I love… how much she doted on Ash. She slept alongside them (me only a few times), she followed them around, she waited outside doors for them. They were her favorite person. I feel so bad for them, to have lost both Twigs and Pearl back to back.

It’s been… two weeks now. Just over, because it took me another day to finish this post.

I don’t know if it’s fully clicked yet. I didn’t see Pearl much during the day, since she’d be tucked away in Ash’s office slash our bedroom. I saw her mostly at night and first thing in the morning. So while I’m out here, at my desk, it’s like nothing has changed. It only sinks in when I go upstairs and see the door left open, see a bed with no Pearl tucked in it somewhere.

It’s kind of dumbfounding just how much of this house and our lives had warped around Pearl, around this one tiny cat who loved everyone. So many things have disappeared or seem superfluous now. I was already free-feeding the other cats again since Pearl wasn’t allowed to roam the house unsupervised, but now we don’t need the kibble cage at all. Half our doors had been kept closed to make a few different places for Pearl to stay, but now none of that is necessary. Litterboxes had ended up scattered throughout the house so Pearl would always have access to one; now they’re back to being in a few central locations.

Ash doesn’t have to wake up at a specific time every day to give Pearl medicine. Pearl won’t wake us up to feed her. We don’t have to make her food, ever again.

And there are so many things that were only for Pearl. This wasn’t the case for anyone else. Styx only had communal cat sweaters; his favorite toy was loose change on my desk. Twigs, too, only had sweaters that Anise and Pearl inherited; his one dedicated toy was a single very tiny mouse he sometimes played with.

But Pearl? Half the sweaters we have only fit Pearl. Her mice were very much hers. Even her string was very much hers. We have a mortar and pestle that were specifically for grinding up her medication, oral syringes only Pearl used. She had possessions of her very own, things she’s left behind.

We knew this was coming, of course. Without the intervention of modern medicine, she would have died last March, and the outlook for heart failure in a cat isn’t great. I’ve already grieved for her several times over the past year. I didn’t see her much during the summer, but I’d been trying to spend more deliberate time with her in recent months, and I’m glad I did. I regret nothing. I earned her purrs, I played string with her exactly the right amount, I woke up to her stealing my pillow. I got the full Pearl experience.

And so did she. Ash took her outside extra over the summer, let her see a bit of the outside world (even if it was only our yard). We let her roam the house when we could, banishing Cheeseball to a room by himself if necessary, though she usually ended up sitting on a vent or my lap (or trying to heist some kibble). She got lots of treats, lots of love, lots of blankets, and even a vent all to herself. What more could she ask for?

She was living on borrowed time, but we borrowed every second we could. I don’t know what else we could’ve done. And we were there for her right up until the end. We didn’t have that opportunity with Twigs; he died in the back room, surrounded by strangers.

In the end, her heart was literally too big.

This sucks.

Pearl deserved better. She was dealt a bad hand from the beginning, but she was still friendly and kind, and then this happened. She was so young, too — her eighth birthday would’ve been next month. She, like Twigs, should’ve had twice as long.

Things won’t be difficult for her any more, I guess. I don’t know how much that comforts me.

Everything else moves on. Pearl continued until the night of January 11, 2022, but can go no further. We’re forced to leave her there, retaining only memories, while time carries us gently forward, ever further away.

So here is my landmark, my stake in the ground. Pearl was here. May this mark out the shape of who she was and leave that impression upon the world for much longer.

The finality of death resolves so many questions. I often wished I could improve Pearl’s tense relationships with Anise and Cheeseball, but now there’s no problem to solve. The interactions they had are all the interactions they will ever have. The tension is gone, now. The worries about how long Pearl’s heart will last are gone too.

The cat dynamic has shifted, again. Cheeseball and Napoleon have been much more affectionate towards Ash, and Napoleon has suddenly become a lap cat. I suppose the rest of the cats missed Ash while they were siloed away with Pearl for so long. Maybe they’re grieving? Cats are so open with their emotions, but sometimes they’re still inscrutable.

Pearl’s urn is on the dresser in our bedroom, right next to Twigs. Hers is bigger than his, somehow. But that’s Pearl for you — she always knew how to take up space.

No, this is too dire an ending. Pearl was dealt a bad hand, but she always tried to be nice despite that. She got to see a lot of places and make a lot of friends, both people and cats and even one dog. Even when she had complex and skeptical feelings about Anise, she kept trying to be friends with him. She faltered at times, but she always did her best to uphold her principles of loveliness, strong boundaries, and please give me a treat.

That’s a lot for a tiny cat. I admire her for it, and I will not forget it.

Pearl sitting contently next to Ash at their desk

Thank you for reading about Pearl. I hope you’ll remember her too. We loved her very much, and she put a lot of love back into the world. If you would like to experience more Pearl, here are some videos of her. I have some more to sift through, so this list may grow in the coming days.

And here are some games she has starred in. Or, rather, her fursona Purrl has starred in them.

Recommended GZDoom settings

Post Syndicated from Eevee original https://eev.ee/blog/2021/12/11/recommended-gzdoom-settings/

GZDoom is the fanciest way to play Doom. Unfortunately, it has also historically been difficult to recommend to newcomers, because its default settings are… questionable.

Conspicuously, for over a decade, it defaulted to traditional Doom movement keys (no WASD) and no mouselook. I am overjoyed to discover that this is no longer the case, and it plays like a god damn FPS out of the box, but there are still a few twiddles that need twiddling. Mostly the texture filtering. Christ, the texture filtering.

Anyway GZDoom has a lot of options, so here is a handy list of the important ones. There are fewer than I expected, which is good.


Note that the routes given to the various settings are for the full options menu. Out of the box, GZDoom shows a reduced options menu, because it has a lot of options. You can get to the full menu from Full options menu near the bottom, and from there turn off the simple menu (if you want). If you get lost, you can also use the option search.

Also, virtually every setting in GZDoom takes effect instantly, even while the menu is still visible. (That’s why there are no screenshots here! Just try stuff out yourself.) It remembers where your cursor was, too, so you can exit the menu to try stuff out, then bring it back up and mash Enter a few times to get back to where you were.

Absolute necessities

I do not understand how anyone could argue with these.

  • Disable texture filtering.

    Display options > Texture options > Texture filter mode: None (linear mipmap)

    By default, GZDoom uses linear upscaling on all sprites and textures, turning them into a blurry mess. This is objectively ludicrous, since the sprites and textures are pixel art.

    None restores the crispy aesthetic that God intended — and when I say God, I of course mean John Carmack. No, wait, maybe I mean Adrian Carmack?

    The “linear mipmap” bit means that GZDoom will still use linear downscaling, so that distant textures still somewhat resemble the actual texture and do not simply collapse into a pixel of arbitrary color. If you find this objectionable, you may of course simply set it to None.

  • Fix the lighting.

    Display options > Hardware renderer > Sector light mode: Doom

    GZDoom has half a dozen different lighting models (for… some reason), all of which are way off from how Doom actually looked, except for this one.

  • Fix the partial invisibility effect.

    Display options > Hardware renderer > Fuzz style: Software

    GZDoom defaults to rendering spectres (the harder-to-see variants of the pink demons) with a sort of translucent effect, which is easier to see, which sort of defeats the purpose of making them harder to see.

    This will emulate the appearance of the original game, scaled up to big chunky pixels. I actually prefer Smooth fuzz, which fits better at high resolutions and still looks like a rendering error, but pretty much anything is better than the Shadow default.

    For testing purposes, it may help to pop open the console with the backtick key (top left) and type summon spectre to… well, summon a spectre.

And if all you want is something that looks kinda like Doom, you’re done! Feel free to stop reading here.

If you’re pickier…

My own preferences

These are also all correct.

  • Always run.

    Player setup > Always run: on

    I don’t know why you would walk anywhere in Doom. We’re in a fucking hurry, man. There are demons.

    While you’re here, you may want to set your gender as appropriate to fix pronouns in obituary messages. You can also turn autoaim down, or off.

  • Show a crosshair.

    HUD options > Default crosshair: Cross 2
    HUD options > Scale crosshair: 0.00

    I just feel better with a little symbol in the middle of the screen. I’m holding all my guns at chest height, for some reason, so the sights on those are useless.

    By default the crosshair is humongous, though, hence the scaling.

  • Speaking of which, fix the HUD scale.

    HUD options > Scaling options > User interface scale: 3

    The automatic setting is okay (and better than it used to be), but still leaves some things like pickup messages and the console as microscopic. I play in a 1080p window on a 1440p monitor, and this seems nice for me. Adjust as desired.

  • Use the alternative HUD.

    HUD options > Alternative HUD > Enable alternative HUD: On

    You’ll need to press + until the status bar disappears to actually see it.

    The alternative HUD shows you everything you need to know about the state of the game, while consuming minimal space and still letting you see the weapon sprites in their full glory. It also shows you a count of kills and secrets, so you have some idea of the progress you’ve made. And it tells you a few things that you had to keep track of yourself in vanilla Doom, like what color of armor you have and whether you have the berserk fist.

    (This replaces a stock fullscreen-with-info HUD that didn’t exist in vanilla Doom, but which only shows you health, armor, keys, and ammo for your current weapon. Note that if you play a WAD that heavily alters the game, there’s a chance it will add custom stuff to the stock HUD, and that stuff will not appear on the alternative HUD. It’s explicitly not moddable.)

  • Draw shadows in corners.

    Display options > Hardware renderer > Postprocessing > Ambient occlusion quality: Medium

    Doom has static lighting that affects the walls and floor equally, so the transition from wall to floor/ceiling is pretty flat. A little AO helps that stand out, even if ambient occlusion is a fake idea.

  • Fix fake contrast.

    Display options > Use fake contrast: Smooth

    Fake contrast” refers to a clever trick in the Doom engine wherein horizontal (as seen on the automap) walls draw darker than the room, and vertical walls draw lighter. In rectangular rooms, this helps avoid the “flat” feeling mentioned previously.

    Unfortunately, with complex geometry — as you see frequently in modern maps, but also occasionally in the original ones — this can backfire. I’ve been fooled into thinking one particular wall in a curved hallway is a secret, just because it happened to be vertical and appeared lighter than its neighbors. Meanwhile, rooms at a slant don’t benefit at all.

    Smooth preserves the effect, but gradually transitions between the original effect for orthogonal walls and normal lighting for walls at a 45° angle. (That is, a wall at a 22.5° angle will have half the fake contrast effect.)

  • Turn on antialiasing.

    Display options > Hardware renderer > Postprocessing > FXAA quality: Low

    This smooths out lines in the geometry (or straight horizontal lines in textures) when drawn at an angle, without sacrificing those crunchy pixels.

  • Use particles.

    Display options > Hardware renderer > Particle style: Round
    Display options > Rocket trails: Particles
    Display options > Blood type: Sprites & particles
    Display options > Bullet puff type: Sprites & particles

    The default particles are linear filtered, which looks awful, but I don’t think anything uses particles by default so you’d never notice. You can also set them to Square, but I think having a single pixel floating in the air looks a bit silly.

    Adding particles to blood splatters and bullet puffs just looks nice. I replace the rocket trails entirely because the original Doom rocket cloud is just kinda big and clumsy and ugly.

  • Enable dynamic lighting.

    This is on by default… sort of. GZDoom needs to be able to find the lights.pk3 and brightmaps.pk3 files bundled with it, but if it runs at all, it probably knows where they are.

    So all you have to do is check Load lights and Load brightmaps in the little dialog you get when launching the game.

    Probably. See, for some reason, those checkboxes are only there on Windows — in fact, I didn’t know they existed at all until two minutes ago. Even though they set a config setting, they aren’t accessible via the options menu. So if that doesn’t work for you for whatever reason, try popping open the console and doing:

    autoloadlights true
    autoloadbrightmaps true

    Then restart the game. Glowing objects should now cast (fairly subtle!) light on nearby walls. You can see this immediately in Doom II’s first map — there should be a green glow on the floor underneath the armor bonus in the far right corner of the room. Or for a more dramatic demonstration, IDKFA and fire a rocket.

    It’s just a nice touch. And unlike many attempts to add dynamic lighting to Doom, it’s not so over-the-top as to be distracting.

For the extremely ornery

At the other end of the scale, there are those who want an experience as close as possible to vanilla Doom. Those people might just want to use a port closer to vanilla, like a PRBoom variant or even Chocolate Doom, but GZDoom is willing to do its best:

  • Quantize light levels.

    Display options > Hardware renderer > Banded SW lightmode: On

    Doom maps support light levels from 0 to 255, but in practice, Doom only understood… 16, I think? That’s because it was a paletted game, and it needed a colormap telling it how to darken each color while still sticking to the palette. The game only shipped with 15 such mappings, probably because 255 of them would have been ludicrous, and thus there are only 16 light levels in practice.

    GZDoom’s hardware renderer isn’t bound by a palette, so it happily supports all 256 light levels. If you can’t stand this, well, it can simulate 16 for you.

  • Disable the hardware renderer altogether.

    Set video mode > Render mode: True color SW renderer

    If the very notion of accelerated rendering offends you, the original core of Doom’s renderer is still in there, just waiting for you. All you need do is turn it on. Note that this will severely restrict your ability to mouselook and will draw without vertical perspective, as the Doom renderer was designed around drawing vertical lines.

    What’s that? Even true color is too much? You need the paletted glory that was the best a 386 could do? Well, Doom software renderer is also an option.

  • Disable mouselook.

    Mouse options > Always mouselook: Off

    Doom didn’t support looking up and down. Why should you?

    Despite the name, this still allows you to look around horizontally. I guess technically that’s turning, not looking. Also, moving the mouse up and down will now move you (slowly) forwards or backwards.

  • Disable WASD.

    Customize controls > Preferred keyboard layout: Classic ZDoom, then Reset to defaults

    Okay now you have gone too far. This restores the very keyboard bindings I wanted to rally against — arrow keys to move, turning by default, Alt to strafe…

  • Disable teleporter zoom.

    Display options > Teleporter zoom: Off

    GZDoom does a brief zoom-in effect on your field of view after (non-silent) teleporting. Looks sick. If you hate it, here’s how to turn it off.

  • Restore the vanilla lite-amp goggles.

    Display options > Hardware renderer > Enhanced night vision mode: Off

    In vanilla Doom, the lite-amp goggles simply make the entire world render as fullbright, which looks fucking terrible. GZDoom defaults to a “night vision goggles” sort of effect that also highlights objects, but if you really can’t stand that, this twiddle is here for you.

  • Enable randomized pitch on sound effects.

    Sound options > Randomize pitches: On

    For the very ornery, I believe this behavior was in the original release of Doom but (accidentally?) broken in Doom 1.2 and all later versions. It’s really weird, but it’s the intended behavior, I guess!

  • Restore Doom’s automap colors.

    Automap options > Map color set: Traditional Doom

    This will change the automap back to its red-and-yellow-on-black glory.

    It will also remove the colors that tell you where locked doors and the exit are. You might argue that those are cheating. I argue that they are the entire point of a map.

    You can also turn off the automap’s monster and secret counts here if you truly wish to be as lost as possible.

  • Twiddle with compatibility settings.

    Compatibility options > Compatibility mode: ?

    You might want Doom (strict) for the closest vanilla experience that GZDoom can provide. Might. The most notable effects are:

    • Monsters will wake up when seeing a player with a blur sphere. By default, they usually won’t, a behavior inherited from Hexen.
    • Arch-viles can resurrect crushed corpses as “ghosts” that cannot be shot, only harmed by splash damage from rockets.
    • Pain elementals will be unable to spawn new lost souls if there are at least 21 already present in the level.
    • Monsters can’t be knocked off of high ledges.
    • You will be unable to crowdsurf, meaning you will be blocked both by imps at the foot of a cliff below you, and by cacodemons flying above you.

    You can also toggle these on or off individually at your leisure.

Gamedev from scratch 1: Scaffolding

Post Syndicated from Eevee original https://eev.ee/blog/2021/01/26/gamedev-from-scratch-1-scaffolding/

Welcome to part 1 of this narrative series about writing a complete video game from scratch, using the PICO-8. This is actually the second part, because in this house (unlike Lua) we index from 0, so if you’re new here you may want to consult the introductory stuff and table of contents in part zero.

If you’ve been following along, welcome back, and let’s dive right in!

← Part 0: Groundwork

Recap and short-term plans

So far, I have… this. Which is something, and certainly much more than nothing, but all told not a lot.

Star Anise walking around the screen and turning to face the way he's moving

Most conspicuously, this is going to be a platformer, so I need gravity. The problem with gravity is that it means things are always moving downwards, and if there’s nothing to stop them, they will continue off indefinitely into the void.

What I am trying to say here is that I feel the looming spectre of collision detection hanging over me. I’m going to need it, and I’m going to need it real soon.

And, hey, that sucks. Collision detection is a real big pain in the ass to write, so needing it this early is a hell of a big spike in the learning curve. Luckily for you, someone else has already written it: me!

Before I can get to that, though, I need to add some structure to the code I have so far. Everything I’ve written is designed to work for Star Anise and only Star Anise. That’s perfectly fine when he’s the only thing in the game, but I don’t expect he’ll stay alone for long! Collision detection in particular is a pretty major component of a platformer, so I definitely want to be able to reuse it for other things in the game. Also, collision detection is a big fucking hairy mess, so I definitely want to be able to shove it in a corner somewhere I’ll never have to look at it again.

A good start would be to build towards having a corner to shove it into.

Adding some structure

As of where I left off last time, my special _update() and _draw() functions are mostly full of code for updating and drawing Star Anise. That doesn’t really sit right with me; as the main entry points, they should be about updating and drawing the game itself. Star Anise is part of the game, but he isn’t the whole game. All that code that’s specific to him should be put off in a little box somewhere. Cats love to be in little boxes, you see.

This raises the question of how I want to structure this project in general. And, I note: structuring a software project is hard, and you only really get a good sense of how to do it from experience. I’m still not sure I have a good sense of how to do it. Hell, I’m not convinced anyone has a good sense of how to do it.

Thankfully, this is a game, so it’s pretty obvious how to break it into pieces. (The tradeoff is that everything in a game ends up entangled with everything else no matter how you structure it, alas.) Star Anise is a separate thing in the game, so he might as well be a separate thing in the code. Later on I’ll need some more abstract structuring, but as an extremely rough guideline: if I can give it a name, it’s a good candidate to be made into a thing.

But what, exactly, is a thing in code? Most commonly (but not always), a thing is implemented with what’s called an object — a little bundle of data (what it is) with code (what it can do). I already have both of these parts for Star Anise: he has data like his position and which way he’s facing, and he has code for doing things like updating or drawing himself. A great first step would be to extract that stuff into an object, after which some other structure might reveal itself.

I do need to do one thing before I can turn get to that, though. You see, Lua is one of the few languages in common use today that doesn’t quite have built-in support for objects. Instead, it has all the building blocks you need to craft your own system for making objects. On the one hand, the way it does that is very slick and clever. On the other hand, it means you can’t write much Lua without cobbling together some arcane nonsense first, and also no one’s code quite works the same way.

Which brings me to the following magnificent monstrosity:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function nop(...) return ... end

--------------------------------
-- simple object type
local obj = {init = nop}
obj.__index = obj

function obj:__call(...)
    local o = setmetatable({}, self)
    return o, o:init(...)
end

-- subclassing
function obj:extend(proto)
    proto = proto or {}

    -- copy meta values, since lua doesn't walk the prototype chain to find them
    for k, v in pairs(self) do
        if sub(k, 1, 2) == "__" then
            proto[k] = v
        end
    end

    proto.__index = proto
    proto.__super = self

    return setmetatable(proto, self)
end

How does this work? What does this mean? What is a prototype chain, anyway? Dearest reader: it extremely does not matter. No one cares. I would have to stare at this for ten minutes to even begin to explain it. Every line is oozing with subtlety. To be honest, even though I describe this series as “from scratch”, this is one of the very few things that I copy/pasted wholesale from an earlier game. I know this does the bare minimum I need and I absolutely do not want to waste time reinventing it incorrectly. To drive that point home: I wrote collision detection from scratch, but I copy/pasted this. (But if you really want to know, I’ll explain it in an appendix.)

Feel free to copy/paste mine, if you like. You can also find a number of tiny Lua object systems floating around online, but with tokens at a premium, I wanted something microscopic. This basically does constructors, inheritance, and nothing else.

(Oh, I don’t think I mentioned, but the -- prefix indicates a Lua comment. Comments are ignored by the computer and tend to contain notes that are helpful for humans to follow. They don’t count against the PICO-8 token limit, but they do count against the total size limit, alas.)

The upshot is that I can now write stuff like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
local vec = obj:extend{}

function vec:init(x, y)
    self.x = x or 0
    self.y = y or 0
end

function vec:__add(v)
    return vec(self.x + v.x, self.y + v.y)
end

function vec:__sub(v)
    return vec(self.x - v.x, self.y - v.y)
end

function vec:iadd(v)
    self.x += v.x
    self.y += v.y
end

This creates a… well, terminology is tricky, but I’ll call it a type while doing air-quotes and glancing behind me to see if any Haskell programmers are listening. (It’s not much like the notion of a type in many other languages, but it’s the closest I’m going to get.) Now I can combine an x- and y-coordinate together as a single object, a single thing, without having to juggle them separately. I’m calling that kind of thing a vec, short for vector, the name mathematicians give to a set of coordinates. (More or less. That’s not quite right, but don’t worry about it yet.)

After the above incantation, I can create a vec by calling it like a function. Note that the arguments ultimately arrive in vec:init, loosely called a constructor, which stores them in self.x and self.y — where self is the vec being created.

1
2
3
-- this is example code, not part of the game
local a = vec(1, 2)
print("x = ", a.x, " y = ", a.y)  -- x = 1 y = 2

That iadd thing is a method, a special function that I can call on a vec. It’s like every vec carries around its own little bag of functions anywhere it appears — and since they’re specific to vec, I don’t have to worry about reusing names. (In fact, reusing names can be very helpful, as we’ll see later!)

The name iadd is (very!) short for “in-place add”, suggesting that the first vector adds the second vector to itself rather than creating a new third vector. That’s something I expect to be doing a lot, and making a method for it saves me some precious tokens.

1
2
3
4
5
-- example code
local v = vec(1, 2)
local w = vec(3, 4)
v:iadd(w)
print("x = ", v.x, " y = ", v.y)  -- x = 4 y = 6

Finally, those funny __add and __sub methods are special to Lua (if enchanted correctly, which is part of what the obj gobbledygook does) — they let me use + and - on my vecs just like they were numbers.

1
2
3
4
5
-- example code
local q = vec(1, 2)
local r = vec(3, 4)
local s = q + r
print("x = ", s.x, " y = ", s.y)  -- x = 4 y = 6

This is the core idea of objects. A vec has some data — x and y — and some code — for adding another vec to itself. If I later discover some new thing I want a vec to be able to do, I can add another method here, and it’ll be available on every vec throughout my game. I can repeat myself a little bit less, and I can keep these related ideas together, separate from everything else.

Get the basic jist? I hope so, because I’ve really gotta get a move on here.

Objectifying Star Anise

Now that I have a way to define objects, I can turn Star Anise into one.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
function b2n(b)
    return b and 1 or 0
end

local t = 0
local player

local anise_stand = {1, 2, 17, 18, 33, 34}
local anise_jump = {3, 2, 17, 18, 19, 35}
local anise = obj:extend{
    move = vec(),
    left = false,
}

function anise:init(pos)
    self.pos = pos
end

function anise:update()
    if self.move.x > 0 then
        self.left = false
    elseif self.move.x < 0 then
        self.left = true
    end

    self.pos:iadd(self.move)
end

function anise:draw()
    local pose = anise_stand
    if (self.move.x ~= 0 or self.move.y ~= 0) and t % 8 < 4 then
        pose = anise_jump
    end
    local y = self.pos.y
    local x0 = self.pos.x
    local dx = 8
    if self.left then
        dx = -8
        x0 += 8
    end
    local x = x0
    for i = 1, #pose do
        spr(pose[i], x, y, 1, 1, self.left)
        if i % 2 == 0 then
            x = x0
            y += 8
        else
            x += dx
        end
    end
end

function _init()
    player = anise(vec(64, 64))
end

function _update()
    t += 1
    t %= 120
    player.move = vec(
        b2n(btn(➡️)) - b2n(btn(⬅️)),
        b2n(btn(⬇️)) - b2n(btn(⬆️)))
    player:update()
end

function _draw()
    cls()
    player:draw()
end

What a mouthful! But for the most part, this is the same code as before, just rearranged. For example, the new anise:draw() method has basically been cut and pasted from my old _draw() — all except the cls() call, since that has nothing to do with drawing Star Anise.

I’ve combined the px and py variables into a single vector, pos (short for “position”), which I now have to refer to as self.pos — that’s so PICO-8 knows whose pos I’m talking about. After all, it’s theoretically possible for me to create more than one Star Anise now. I won’t, but PICO-8 doesn’t know that!

A Star Anise object is created and assigned to player when the game starts, and then _update() calls player:update() and _draw() calls player:draw() to get the same effects as before.

I did make one moderately dramatic change in this code. The wordy code I had for reading buttons has become much more compact and inscrutable, and the moving variable is gone. A big part of the reason for this is that I consider Star Anise’s movement to be part of himself, but reading input to be part of the game, so I wanted to split them up. That means moving is a bit awkward, since I previously updated it as part of reading input. Instead, I’ve turned Star Anise’s movement into another vector, which I set in _update() using this mouthful:

1
2
3
4
5
6
7
8
9
-- top-level
function b2n(b)
    return b and 1 or 0
end

-- in _update()
    player.move = vec(
        b2n(btn(➡️)) - b2n(btn(⬅️)),
        b2n(btn(⬇️)) - b2n(btn(⬆️)))

The b2n() function turns a button into a number, and I only use it here. It turns true into 1 and false into 0. Think of it as measuring “how much” the button is held down, from 0 to 1, except of course there can’t be any answer in the middle.

Unpacking that a bit further, b2n(btn(➡️)) - b2n(btn(⬅️)) means “how much we’re holding right, minus how much we’re holding left”. If the player is only holding the right button, that’s 1 – 0 = 1. If they’re only holding the left button, that’s 0 – 1 = -1. If they’re holding both or neither, that’s 0. The results are the same as before, but the code is smaller.

Once Star Anise’s move is set, the rest works similarly to before: I update left based on horizontal movement (but leave it alone when there isn’t anyway), I alter his position (now using :iadd()), and I use the walk animation when he’s moving at all. And that’s it!

From one to many

I like to use the term “actor” to refer to a distinct thing in the game world; it conjures a charming and concrete image of various characters performing on a stage. I think I picked it up from the Doom source code. “Entity” is more common and is used heavily in Unity, but can be confused with an “entity–component–system” setup, which Unity also supports. And then there are heretics who refer to game things as “objects” even though that’s also a programming term.

This code is a fine start, but it’s not quite what I want. There’s nothing here actually called an actor, for starters. My setup still only works for Star Anise!

I’d better fix that. The notion of an “actor” is pretty vague, so a generic actor won’t do much by itself, but it’s nice to define one as a template for how I expect real actors to work.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
local actor = obj:extend{}

function actor:init(pos)
    self.pos = pos
end

function actor:update()
end

function actor:draw()
end

How does a blank actor update or draw itself? By doing nothing.

(I do assume that every actor has a position; this may not necessarily be the case in games with very broad ideas about what an “actor” is, but it’s reasonable enough for my purposes.)

Now, to link this with Star Anise, I’ll have anise inherit from actor. That means he’ll become a specialized kind of actor, and in particular, all the methods on actor will also appear on anise. You may notice that anise was previously a specialized kind of obj (like actor and vec) — in fact, the only reason I can call vec(x, y) like a function is that it inherits some magic stuff from obj. Surprise!

1
local anise = actor:extend{

I can now delete anise:init(), since it’s identical to actor:init(). I still have anise:update() and anise:draw(), which override the methods on actor, so those don’t need changing.

Everything still only works for Star Anise, but I’m getting closer! I only need one more change. Instead of having only player, I will make a list of actors.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
-- at the top
local actors = {}

function _init()
    player = anise(vec(64, 64))
    add(actors, player)
end

function _update()
    -- ...mostly same as before...
    for actor in all(actors) do
        actor:update()
    end
end

function _draw()
    cls()
    for actor in all(actors) do
        actor:draw()
    end
end

This does pretty much what it reads like. The add() function, specific to PICO-8, adds an item to the end of a list. The all() function, also specific to PICO-8, helps go through a list. And the for blocks mean, for each thing in this list, run this code.

Now, at last, I have something that could work for actors other than Star Anise. All I need to do is define them and add them to the actors list, and they’ll automatically be updated and drawn, just like him!

Admittedly, this hasn’t gotten me anywhere concrete. The game still plays exactly the same as it did when I started. I’m betting that I’ll eventually have more than one actor, though, so I might as well lay the groundwork for that now while it’s easy. It doesn’t take much effort, and I find that if I give myself little early inroads like this, it feels like less of a slog to later come back and expand on the ideas. This is the sort of thing I meant by more structure revealing itself — once I have one actor, a natural next step is to allow for several actors.

Preparing for collision detection

I’ve put it off long enough. I can’t avoid it any longer. But it’s complicated enough to deserve its own post, so I don’t quite want to do it yet.

Instead, I’ll write as much code as possible except for the actual collision detection. There’s a bit more work to do to plug it in.

For example: what am I going to collide with? The only thing in the universe, currently, is Star Anise himself. It would be nice to have, say, some ground. And that’s a great excuse to toodle around a bit in the sprite editor.

A set of simple ground tiles, drawn in the PICO-8 sprite editor

I went through several iterations before landing on this. Star Anise lives on a moon, so that was my guiding principle. The moon is gray and dusty and pitted, so at first I tried drawing a tile with tiny craters in it. Unfortunately, that was a busy mess to look at when tiled, and I didn’t think I’d have enough tile space for having different variants of tiles. I’m already using 9 tiles here just to have neat edges.

And so I landed on this simple pattern with just enough texture to be reminiscent of something, which is all you really need with low-res sprite art. It worked out well enough to survive, nearly unchanged, all the way to the final game. It was inspired by a vague memory of Starbound’s moondust tiles, which I was pretty sure had diagonal striping, though I didn’t actually look at them to be sure.

You may notice I drew these on the second tab of sprites. I want to be able to find tiles quickly when drawing maps, so I thought I’d put “terrain” on a dedicated tab and reserve the first one for Star Anise, other actors, special effects, and other less-common tiles. That turned out to be a good idea.

You may also notice that one of those dots on the middle right is lit up. How mysterious! We’ll get to that next time.

With a few simple tiles drawn, I can sprinkle a couple in the map tab. I know I want Metroid-style discrete screens, so I’m not worried about camera scrolling yet; the top-left corner (16×16 tiles) is enough to play with for now.

I draw two rows of tiles at the bottom of that screen. It’s a little hard to gauge since the toolbar and status bar get in the way, but the bottom row of the screen will be at y = 15. You can also hold Spacebar to get a grid, with squares indicating every half-screen.

PICO-8's map editor, showing two rows of moon tiles

Finally, to make this appear in the game, I need only ask PICO-8 to draw the map before I draw actors on top of it.

1
2
3
4
5
6
7
function _draw()
    cls()
    map(0, 0, 0, 0, 32, 32)
    for actor in all(actors) do
        actor:draw()
    end
end

The PICO-8 map() function takes (at least) six arguments: the top-left corner of the map to start drawing from, measured in tiles; the top-left corner on the screen to draw to, measured in pixels; and the width/height of the rectangle to draw from the map, measured in tiles. This will draw a 32×32 block of tiles from the top-left corner of the map to the top-left corner of the screen.

Of course, with no collision detection, those tiles are nothing more than background pixels, and the game treats them as such.

Star Anise standing in front of the moon tiles

No problem. I can fix that. Sort of.

Not quite collision detection

I’m not going into collision detection yet, but I can give you a taste, to give you an idea of the goals.

The core of it comes down to this line, from the end of anise:update().

1
    self.pos:iadd(self.move)

That moves Star Anise by one pixel in each direction the player is holding. What I want to do is stop him when he hits something solid.

Hm, sounds hard. Let’s think for a moment about a simpler problem: how can I stop him falling through the ground, in the dumbest way possible?

The ground is flat, and it takes up the bottow two rows of tiles. That means its top edge is 14 tiles, or 112 pixels, below the top of the screen. Thus, Star Anise should not be able to move below that line.

But wait! Star Anise’s position is a single point at his top left, not even inside his helmet. What I really want is for his feet to not pass below that line, and the bottom of his feet is three tiles (24 pixels) below his position. Thus, his position should not pass below y = 112 – 24 = 88.

That sounds doable.

1
2
3
4
    self.pos:iadd(self.move)
    if self.pos.y > 88 then
        self.pos.y = 88
    end

And sure enough, it works!

Star Anise walking through the air, but not through the floor

This isn’t going to get us very far, of course. He still walks through the air, he can still walk off the screen, and if I change the terrain then the code won’t be right any more. I’m also pretty sure I didn’t actually write this in practice. But hopefully it gives you the teeniest idea of the problem we’re going to solve next time.

Part 2: Collision → (coming soon!)

Appendix: the Lua object model

Really, really, really quickly, here’s how that obj snippet works.

Lua’s primary data structure is the table. It can be used to make ordered lists of things, as I did above with actors, but it can also be used for arbitrary mappings. I can assign some value to a particular key, then quickly look that key up again later. Kind of like a Rolodex.

1
2
3
4
5
local lunekos = {
    anise = "star anise is the best",
    purrl = "purrl is very lovely",
}
print(lunekos['anise'])

Note that the values (and keys!) don’t have to be strings; they can be anything you like, even other tables. But for string keys, you can do something special:

1
print(lunekos.anise)  -- same as above

Everywhere you see a dot (or colon) used in Lua, that’s actually looking up a string in a table.

With me so far? Hope so.

Any Lua table can also be assigned a metatable, which is another table full of various magic stuff that affects the first table’s behavior. Most of the magic stuff takes the form of a special key, starting with two underscores, whose value is a function that will be called in particular circumstances. That function is then called a metamethod. (There’s a whole section on this in the Lua book, and a summary of metamethods on the Lua wiki.)

One common use for metamethods is to make normal Lua operators work on tables. For example, you can make a table that can be called like a function by providing the __call metamethod.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
local t = {
    stuff = 5678,
}
local meta = {
    -- this is just a regular table key with a function for its value
    __call = function(tbl)
        print("my stuff is", tbl['stuff'])
    end,
}
setmetatable(t, meta)
t()  -- my stuff is 5678
t['stuff'] = "yoinky"
t()  -- my stuff is yoinky

One especially useful metamethod is __index, which is called when you try to read a key from the table, but the key doesn’t exist.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
local counts = {
    apples = 5,
    bananas = 3,
}
setmetatable(counts, {
    __index = function(tbl, key)
        return 0
    end,
})
print(counts.bananas)  -- 3
print(counts.mangoes)  -- 0
print(counts.apples)  -- 5

Instead of a function, __index can also be another (third!) table, in which case the key will be looked up in that table instead. And if that table has a metatable with an __index, Lua will follow that too, and keep on going until it gets an answer.

This is essentially what’s called prototypical inheritance, as seen in JavaScript (and more subtly in Python): an object consists of its own values plus a prototype, and if code tries to fetch something from the object that doesn’t exist, the prototype is checked instead. Since the prototype might have its own prototype, the whole sequence is called the prototype chain.

That’s all you need to know to follow the obj snippet, so here it is again.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function nop(...) return ... end

local obj = {init = nop}
obj.__index = obj

function obj:__call(...)
    local o = setmetatable({}, self)
    return o, o:init(...)
end

-- subclassing
function obj:extend(proto)
    proto = proto or {}

    -- copy meta values, since lua doesn't walk the prototype chain to find them
    for k, v in pairs(self) do
        if sub(k, 1, 2) == "__" then
            proto[k] = v
        end
    end

    proto.__index = proto
    proto.__super = self

    return setmetatable(proto, self)
end

The idea is that types are used both as metatables and prototypes — they are always their own __index. At first, we have only obj, which looks like this:

1
2
3
4
5
6
local obj = {
    init = nop,
    __index = obj,
    __call = function() ... end,
    extend = function() ... end,
}

Now we use obj:extend{} to create a new type. Follow along and see what happens. Lua only looks for metamethods like __call directly in the metatable and ignores __index, so I copy them into the new prototype. Then I make the prototype its own __index, as with obj, and also remember the “superclass” as __super (though I never end up using it). Finally I set the “superclass” as the prototype’s metatable.

(Oh, by the way: in Lua, if you call a function with only a single table or string literal as its argument, you can leave off the parentheses. So foo{} just means foo({}).)

That produces something like the following, noting that this is not quite real Lua syntax:

1
2
3
4
5
6
7
local vec = {
    __index = vec,
    __super = obj,
    __call = obj.__call,

    METATABLE = obj,
}

Remember this syntax?

1
2
3
4
function vec:init(x, y)
    self.x = x or 0
    self.y = y or 0
end

That is exactly equivalent to:

1
2
3
4
vec.init = function(self, x, y)
    self.x = x or 0
    self.y = y or 0
end

So after all is said and done, we have:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
local vec = {
    __index = vec,
    __super = obj,
    __call = obj.__call,

    init = function() ... end,
    __add = function() ... end,
    __sub = function() ... end,
    iadd = function() ... end,

    METATABLE = obj,
}

Now for the magic part. When I call vec(), Lua checks the metatable. (The __call in the main table does nothing!) The metatable is obj, which does have a __call, so Lua calls that function and inserts vec as the first argument. Then obj.__call creates an empty table, assigns self (which is the first argument, so vec) as the empty table’s metatable, and calls the new table’s init method.

Ah, but the new table is empty, so it doesn’t have an init method. No problem: it has a metatable with an __index, so Lua consults that instead. The metatable’s __index is vec, and vec does contain an init, so that’s what gets called. (If there were no vec.init, then Lua would see that vec also has a metatable with an __index, and continued along. That’s why I didn’t need an anise.init.)

That’s also why defining vec:__add works — it puts the __add metamethod into vec, which becomes the metatable for all vector objects, thus automatically making + work on them.

That’s all there is to it. It’s possible to get much more elaborate with this in a number of ways, but this is the bare minimum — and it could still be trimmed down further.

Note that you can’t actually call obj itself. Pop quiz: why not?

Eevee gained 3367 experience points

Post Syndicated from Eevee original https://eev.ee/blog/2021/01/24/eevee-gained-3367-experience-points/

Eevee grew to level 34!

I super almost forgot to write one of these!

What a very, very long year. I went back through my dev journal to see what I’d done and could not believe most of this happened in the past year. Even stuff from August feels like it must have been at least a year ago.


I made our first Steam release: Cherry Kisses, a polished version of a jam game we made (though didn’t finish in time to get in the jam, oops) the year before. It’s sold pretty decently, especially considering the reduced audience (adult games are hidden on Steam unless you opt into them), so that’s been nice.

I started HRT! Then I stopped HRT. Alas.

I dipped my toes into Godot for real this time with Rogue Ike, a Strawberry Jam game that was perhaps much too ambitious for a first (and time-limited) attempt but worked out as a proof of concept. I don’t think I’ll pick this back up until I’ve made something a bit more substantial, though; I’ve got a lot of bits and pieces of Godot code now but still don’t feel like I have a solid grasp of how I’d approach architecture for a new game.

I poured some feelings into a little PICO-8 game: Star Anise Chronicles: Oh No Wheres Twig??, a charming little platformer about my cat’s fursona. It’s probably my favorite thing I’ve ever released.

I did actually an incredible lot of work on fox flux over the summer and made massive strides with it in a relatively short span of time? It was a broken hopeless mess at the start of the year, and now it’s… well, not. Better art, better physics, more plot ideas, a lot more little bits and pieces implemented, a whole minigame conceived and mostly implemented, a level tally… it feels like a real game, even!

I also took a crack at a possible port of fox flux to Godot, which was informative both about Godot itself and about designing complex actors in general, but I don’t think I’m going to continue with it. Godot does make some stuff easier, but at the cost of a lot of rough edges that will seriously slow me down — a lot of basic functionality I’ve been taking for granted in my current setup of LÖVE-duct-taped-to-Tiled just does not exist in Godot, and some of the 2D tooling has major oversights that I’d have to work around. Some of this will be fixed in Godot 4, but I don’t want to wait for that just to continue on this game that I’ve already poured a lot of work into. I’ll probably do something simpler in Godot 4 when it comes out.

I poured most of the last four months of the year into a surprise project, by which I mean, I surprised myself by doing it: Lexy’s Labyrinth, a web-based and unencumbered Chip’s Challenge 2 emulator — the first of its kind! It still has some teeny compatibility issues, but for the most part it faithfully plays both the original Chip’s Challenge 1 and 2 as well as tons of community levels created over the years. It needs a bit more polish, and then I’m gonna call it “basically finished” and make a bigger effort to drum up interest in it.

I think I worked on baz, the game engine I wanted to make that was intended as a bridge between MegaZeux and PuzzleScript and bitsy? But I haven’t touched it in a while now. I also started a web-based Sudoku player and then lost interest in Sudoku again. And then there was the AC:NH companion, which I kept up with until I lost interest in Animal Crossing. Hmmm.

I did dip my toe back into blogging with the well-received CSS post, and then not so much for a while. I started the “gamedev from scratch” series to replace the ill-fated book I toyed with writing, but it has yet to see a second installment.


I feel like I miss making video games, even though I did rather a lot of it this year. I guess I don’t feel like I released any; Cherry Kisses was an existing game, Rogue Ike didn’t get further than a handful of rooms, fox flux is still quite a ways off from being done, and Lexy’s Labyrinth is really a game engine. That leaves the Star Anise game as the only “““real””” one I released, but that may not be an entirely fair way to gauge how much work I’ve done.

I do miss writing more often. I guess after everything that happened three years ago, I never quite figured out how to reconnect with the universe. Sometimes I go on a tweeting spree for a couple days, and that feels nostalgic, but in general I’ve gotten more withdrawn and don’t quite know how to shake it. I’m still trying.

I like how well Cherry Kisses did, and I’d kinda like to do small adult game releases more regularly — they’re fun to design and write, they make folks happy, and they bring in a steady trickle of sales. I have a concept for one I’m going to start on during Strawberry Jam 5 next month, but it’s a bit more ambitious, so I might have to do something smaller for Steam purposes this year. Maybe I should take this as an opportunity to get a real foothold in Godot? Cherry Kisses wasn’t terribly complicated; I could recreate something like that without much trouble, and spend some time ironing out wrinkles.

I do want to keep working on fox flux — it’s been just about four years since the jam version now, and I still love the idea and would like to get it seriously going. I’ve spent so much time on engine and design stuff that I still barely have any areas to show!

And of course I would very much love to get that gamedev from scratch series going. I promised one installment per month, and I already missed December because I was neck-deep in Lexy’s Labyrinth, so I really ought to write two in the next week. We’ll see how that goes.


I don’t know how I feel about being 34. Solidly in my mid-30s. I still remember the days, twenty years ago now, when I was the youngest person I knew in almost any circles: online, at school, whatever. Now I’m usually one of the oldest, as most folks my age are off with children and careers; whereas I’ve made a life out of making weird stuff on the internet, just like I did as a teenager.

Still, I guess that means I’m exactly where I always wanted to be.


Browsers all have autoplay restrictions now, so you’ll have to hit play on this yourself.

Cherry Kisses, on Steam

Post Syndicated from Eevee original https://eev.ee/blog/2020/11/30/cherry-kisses-on-steam/

Cherry Kisses title screen, showing Cerise at a counter

🔗 Steam release
🔗 itch release

Whoops! I meant to write about this when it originally came out, in April, but never quite got around to collecting my thoughts. Here is a very rushed subset of them.

The game is extremely NSFW, but the commentary below is not.


The game itself

I like the game. It’s essentially a visual novel, but disguised.

I’ve played a decent number of visual novels, and I’ve thought a lot about them and their role as kind-of-games, and I’ve noticed the thorny bits that I don’t like. And my thoughts have circled around the notion of player agency.

Agency is what makes a game feel like a game. You have input, in a broad sense. You can do something to the game, and it will react appropriately (fingers crossed).

This theory explains the awkward position of visual novels. The bulk of the experience is reading a passage, pressing spacebar, and GOTO 10. You don’t have meaningful input; pressing spacebar isn’t a decision, it’s scrolling.

When you do have input, it generally comes in the form of a menu. But this doesn’t feel like you’re making a choice; it feels like one is being extracted from you in the middle of an otherwise passive reading experience. The base form of the game is reading, and that has been interrupted at a predetermined point to demand something of you. You often don’t have enough information to make a meaningful choice, either, so this becomes a game of saving at each branch and performing an exhaustive depth-first search of the story. As time goes on, you end up skipping through more and more of the early parts, and may hit a point where you go down a decision branch not even remembering what form the story took before you got there.

This is a weird experience.

I wanted to try to improve the feeling of a VN without altering the substance, so this one is disguised as an RPG. I mean, not really an RPG, but that brand of top-down “walk around and interact with stuff” framing.

You play as Cerise, and the entire game takes place in her shop. At any given time, zero or more customers are present, and you can either twiddle your thumbs at the counter or talk to one of them. Whatever you do will generally advance time by an hour, which may change the set of customers; some folks left or arrived while you were busy doing something else. And different folks have different reactions to being ignored, so the whole game becomes one large meta scheduling puzzle.

The thing is, this could’ve been done just as well with a menu at the start of each hour, asking who you want to talk to. The gameplay would’ve been functionally identical. But this scheme feels completely different (at least to me) for several reasons:

  1. Instead of choices being “on top of” the prose, the prose is on top of the choices. It feels like the choices you make cause the prose to happen, rather than being forks in the middle of a river you can’t escape. You can wander around the shop as long as you like, taking breathers, and time will not pass until you, the human at the controls, cause something to happen. (You could say the same about a menu in a VN, but there you can’t do anything else either; the entire game is frozen until you interact with this modal dialog.)

  2. You can do other things. Not many, granted, but you can examine every single object in the shop, and they all have different descriptions (even if they look identical). A typical visual novel doesn’t give you the opportunity to go on frivolous tangents, but I think a big part of games is being able to forget about the progression for a minute and fuck around with something that looks interesting. Stop and smell the roses, in this case literally.

  3. A menu spells out all possible options with equal priority. They’re just items in a list, after all. A physical world, on the other hand, can add subtle differences — choices may be more or less obvious, more or less compelling, or be presented in some way that adds to the narrative. For example, while customers tend to show up at arbitrary spots throughout the shop, your girlfriend Lexy will wait for you right behind the counter, suggesting a more personal relationship even if you don’t yet know who she is. Or consider the ubiquitous option of ignoring everyone in the shop and passing time at the counter instead. That would usually be pointless, so it would be obnoxious to list in every single menu, but having it as an option in-world makes it less obvious… which is perfect puzzle fodder. Just saying.

As an added bonus, every character in the game has a “happiness” rating from -3 to 3. If you can help them with their problems, their happiness will increase. The numbers are largely arbitrary, but you do get a final score tally at the end, and that gives some sense of measured accomplishment that’s more nuanced than a mere good/bad ending. You can ignore it altogether and be happy with the story you got, or you can go down the rabbit hole and try to find the unique path through the game that will make everyone happy and get you a perfect score.

These feel like really subtle design decisions that have an equally subtle impact on the experience. I don’t know what impact it had on anyone else, but I really liked the results. I didn’t mind playing through the game a gazillion times while I was developing it, because it’s just nice to play. The story isn’t especially deep, but it has a lot of little lighthearted interactions with a variety of characters, and sometimes different threads impact each other in really subtle ways. Sometimes I ran across an interaction I’d forgotten I’d written! It feels like the kind of story game that you can’t merely grind every ending out of, one that always has a chance to surprise you a little.

I still have other ideas for making narrative games that feel more player-controlled, so fingers crossed that I can pull them off.

Steam, numbers, business

This is the first game I’ve put on Steam, a platform I’ve long had mixed feelings about. On the one hand, it’s cool that video games have something like a package repository. On the other hand, that package repository is owned and controlled by a single company that sits back and rakes in billions (30% off of every sale!) from a glorified FTP server, something that Linux distributions do for free. And it’s normalized casual DRM, which I do not enjoy. (If I did it right, then manually running Cherry Kisses while Steam is closed should simply run the game without interacting with Steam at all.)

On the other hand, I can’t deny the impact. The Steam release earned more in its first two weeks than the itch release did in more than a year.

…okay, that isn’t an entirely fair comparison. The itch release also had a free “demo” version that was exactly like the “real” version, only with lower-resolution artwork. Loads of people played that (almost 20k downloads as of now), and in retrospect we may have shot ourselves in the foot a bit by offering a free version. But I do like when people can play my games, and releasing anything only in a paid form feels like extorting people out of their money.

I am not good at business. It mostly feels bad.

Despite that, the game has somehow grossed a bit over $10k in the last eight months (which shrinks to $6k net after the Steam tax, VAT, and refunds). That’s not a windfall, but it’s far more than I ever expected to earn on the back of a month-long jam game, and it all went to paying our 2019 taxes so it’s like nothing ever happened. It certainly makes me optimistic about selling something meatier.

Creating the Steam release

We did update the game somewhat for Steam, a process that ended up consuming almost a month somehow and still didn’t cover everything we wanted. The most obvious in-game things were the addition of character profiles, an image gallery, and an options menu — which is to say, all UI things, which I had to build in LÖVE, by hand, which was an incredible pain in the ass. But it works, somehow.

Of course I also added a bunch of Steam achievements, which were kinda fun to decide upon. It’s a story game, so they’re mostly of the form “encounter this bit of the story”, but that’s fine?

But oh boy, the thing that really took the longest time was linking to Steam at all. You get a DLL/SO, some header files, and some hit-or-miss documentation, and the rest is up to you.

The library is, of course, designed for C++.

I am not using C++. I am using Lua.

This posed something of a problem.

I prefer not to touch C++ with a ten-foot pole, so writing some glue on the C++ side did not sound appetizing. (That would’ve also left me with the difficult problem of compiling that code for platforms I do not own or develop on.) That left me with binding to the Steam API from the Lua side.

After several days of Googling, finding years-old projects that promised to do this, and completely failing to get anywhere at all with them, I resigned myself to writing something from scratch. LÖVE uses LuaJIT, which comes with the excellent FFI library, meaning I could bind to C with nothing more than a header file.

The Steam API does have a C compatibility layer, but it is basically not documented, so I had to do some guesswork to get from the documentation to the parts I actually needed. Also, the core of the Steam API is this hokey async messaging system built out of macros and C++ metaprogramming, so I had to do a clumsier polling thing using disparate parts of the C API instead. I finally discovered that there’s example code in a big honking comment in the headers themselves, except the example code is wrong, so I had to fix that as well. Plus all the obtuse bugs like with padding on different platforms which for some reason is baked into the messages that Steam sends because C programmers don’t know how to actually fucking serialize anything. It was an adventure!!

But after all that, I managed to get achievements working, and also leaderboards. Neat, cool, etc.

The game does leak coroutines indefinitely if it’s run through Steam but can’t connect, though. Sorry.

Man. The Steam website has so many features, and the documentation explains them all in one succinct list, but fuck me if I can actually find any of them. So many things are not linked from obvious places; there have been many times I knew a particular page existed but could not figure out how to get there, and ultimately I started relying on address bar history instead of trying to navigate this website.

And so many features are awkwardly built on top of older features that are actually something completely different. Like we have a “developer” page on Steam, but the only part of it we can really control is a single line of plain text at the top. If you go to the “about” tab, it just shows you that line again! That’s all we can put there! You have to click “visit group page” (why would you do that??) in the sidebar of that page to actually get to something we can control.

In stark contrast to itch, Steam really wants your store page to look like a Steam store page and not like a your-game store page. Your artwork (and there is so much artwork) has to be manually approved by a human, and along the way I discovered some extremely unintuitive rules, like that the library header has to be SFW even though it’s only visible to people who already own the game. Store pages also have a “legal” section, but I couldn’t list open source libraries I used (and their licenses) in that section, because I’m not allowed to have links. Like, at all. They really don’t want you to have links. Games exist independently of the humans that made them in the world of Steam; they are isolated jewels floating in a vast space that is linked directly to gaben’s bank account.

I cannot comprehend how weirdly low-key hostile the whole experience felt. All so they could take a third of my money.

Oh, and there’s no Mac release, because I do not have a Mac on which to sign Mac software and do not wish to pay Apple for the privilege, and Mac software does not run any more if it’s not signed. Sorry. Yes, I fucking know about fucking right-click open, please stop fucking telling me about that, that is not useful for software that is run from someone else’s launcher.

Reception

People seem to like it?? I mean, I’ve had a dozen or so people tell me to my face that they had an especially good experience with it, that it was cozy and upbeat and just nice. For a few of them, it apparently helped ease some aversion they’d had to sex, simply by showing it playing out well.

It’s funny that I thought so hard about the general design and how agency worked and all that, but 99% of the feedback has been about the feeling of the prose itself — something that just kinda fell out of my fingers. I guess I’m not surprised — after all, if these players thought as hard about game design as I do, they’d probably be designing games.

As of this writing, there have been 19.5k downloads on itch and 1750 sales on Steam. Of the Steam sales, a hair under 80% of the people who own the game have actually played it, so if I extrapolate wildly, maybe 17,000 people have played it.

But I don’t see anyone talk about it outside of my immediate circles, which feels a bit weird. Maybe? I’m not sure what the “normal” amount of conversation about an admittedly niche game is. I don’t know how things really spread by word of mouth, and I thought this might be an opportunity to gleam some insight about that, but it has not visibly materialized even though the game is being bought by people I don’t personally know.

On the one hand, it’s a sex game, so many folks are less likely to talk about it. (A couple people even specifically asked if Steam has a way to hide what game you’re playing from your friends — and, alas, it does not.) On the other hand, it’s a furry sex game, and furries are traditionally not so tight-lipped.

Maybe there’s not that much to say; the impact it’s had on people I know has been fairly personal, and if it didn’t have that kind of impact then it’s just a cute little story game.

Lessons learned

I have no idea. There are so many confounding factors here that I don’t know how to conclude anything.

I guess I’m pleasantly surprised by how many people bought a fairly short game for $7. As it turns out, people will give you money for a thing if you ask for it? That’s nice to know.

Releasing on Steam is such a huge pain in the ass lol.

Sales spiked right at the beginning and then flattened fairly quickly, but it still sells a few copies a week, so it looks like it’ll be a little trickle of income for a while. It’d be cool to get a few medium-sized games on Steam as an extra source of income. I suspect porn games have a bit more staying power, too.

Writing UI by hand sucks ass. I gotta switch to Godot asap.

Cherry Kisses, on Steam

Post Syndicated from Eevee original https://eev.ee/release/2020/11/30/cherry-kisses-on-steam/

Cherry Kisses title screen, showing Cerise at a counter

🔗 Steam release
🔗 itch release

Whoops! I meant to write about this when it originally came out, in April, but never quite got around to collecting my thoughts. Here is a very rushed subset of them.

The game is extremely NSFW, but the commentary below is not.


The game itself

I like the game. It’s essentially a visual novel, but disguised.

I’ve played a decent number of visual novels, and I’ve thought a lot about them and their role as kind-of-games, and I’ve noticed the thorny bits that I don’t like. And my thoughts have circled around the notion of player agency.

Agency is what makes a game feel like a game. You have input, in a broad sense. You can do something to the game, and it will react appropriately (fingers crossed).

This theory explains the awkward position of visual novels. The bulk of the experience is reading a passage, pressing spacebar, and GOTO 10. You don’t have meaningful input; pressing spacebar isn’t a decision, it’s scrolling.

When you do have input, it generally comes in the form of a menu. But this doesn’t feel like you’re making a choice; it feels like one is being extracted from you in the middle of an otherwise passive reading experience. The base form of the game is reading, and that has been interrupted at a predetermined point to demand something of you. You often don’t have enough information to make a meaningful choice, either, so this becomes a game of saving at each branch and performing an exhaustive depth-first search of the story. As time goes on, you end up skipping through more and more of the early parts, and may hit a point where you go down a decision branch not even remembering what form the story took before you got there.

This is a weird experience.

I wanted to try to improve the feeling of a VN without altering the substance, so this one is disguised as an RPG. I mean, not really an RPG, but that brand of top-down “walk around and interact with stuff” framing.

You play as Cerise, and the entire game takes place in her shop. At any given time, zero or more customers are present, and you can either twiddle your thumbs at the counter or talk to one of them. Whatever you do will generally advance time by an hour, which may change the set of customers; some folks left or arrived while you were busy doing something else. And different folks have different reactions to being ignored, so the whole game becomes one large meta scheduling puzzle.

The thing is, this could’ve been done just as well with a menu at the start of each hour, asking who you want to talk to. The gameplay would’ve been functionally identical. But this scheme feels completely different (at least to me) for several reasons:

  1. Instead of choices being “on top of” the prose, the prose is on top of the choices. It feels like the choices you make cause the prose to happen, rather than being forks in the middle of a river you can’t escape. You can wander around the shop as long as you like, taking breathers, and time will not pass until you, the human at the controls, cause something to happen. (You could say the same about a menu in a VN, but there you can’t do anything else either; the entire game is frozen until you interact with this modal dialog.)

  2. You can do other things. Not many, granted, but you can examine every single object in the shop, and they all have different descriptions (even if they look identical). A typical visual novel doesn’t give you the opportunity to go on frivolous tangents, but I think a big part of games is being able to forget about the progression for a minute and fuck around with something that looks interesting. Stop and smell the roses, in this case literally.

  3. A menu spells out all possible options with equal priority. They’re just items in a list, after all. A physical world, on the other hand, can add subtle differences — choices may be more or less obvious, more or less compelling, or be presented in some way that adds to the narrative. For example, while customers tend to show up at arbitrary spots throughout the shop, your girlfriend Lexy will wait for you right behind the counter, suggesting a more personal relationship even if you don’t yet know who she is. Or consider the ubiquitous option of ignoring everyone in the shop and passing time at the counter instead. That would usually be pointless, so it would be obnoxious to list in every single menu, but having it as an option in-world makes it less obvious… which is perfect puzzle fodder. Just saying.

As an added bonus, every character in the game has a “happiness” rating from -3 to 3. If you can help them with their problems, their happiness will increase. The numbers are largely arbitrary, but you do get a final score tally at the end, and that gives some sense of measured accomplishment that’s more nuanced than a mere good/bad ending. You can ignore it altogether and be happy with the story you got, or you can go down the rabbit hole and try to find the unique path through the game that will make everyone happy and get you a perfect score.

These feel like really subtle design decisions that have an equally subtle impact on the experience. I don’t know what impact it had on anyone else, but I really liked the results. I didn’t mind playing through the game a gazillion times while I was developing it, because it’s just nice to play. The story isn’t especially deep, but it has a lot of little lighthearted interactions with a variety of characters, and sometimes different threads impact each other in really subtle ways. Sometimes I ran across an interaction I’d forgotten I’d written! It feels like the kind of story game that you can’t merely grind every ending out of, one that always has a chance to surprise you a little.

I still have other ideas for making narrative games that feel more player-controlled, so fingers crossed that I can pull them off.

Steam, numbers, business

This is the first game I’ve put on Steam, a platform I’ve long had mixed feelings about. On the one hand, it’s cool that video games have something like a package repository. On the other hand, that package repository is owned and controlled by a single company that sits back and rakes in billions (30% off of every sale!) from a glorified FTP server, something that Linux distributions do for free. And it’s normalized casual DRM, which I do not enjoy. (If I did it right, then manually running Cherry Kisses while Steam is closed should simply run the game without interacting with Steam at all.)

On the other hand, I can’t deny the impact. The Steam release earned more in its first two weeks than the itch release did in more than a year.

…okay, that isn’t an entirely fair comparison. The itch release also had a free “demo” version that was exactly like the “real” version, only with lower-resolution artwork. Loads of people played that (almost 20k downloads as of now), and in retrospect we may have shot ourselves in the foot a bit by offering a free version. But I do like when people can play my games, and releasing anything only in a paid form feels like extorting people out of their money.

I am not good at business. It mostly feels bad.

Despite that, the game has somehow grossed a bit over $10k in the last eight months (which shrinks to $6k net after the Steam tax, VAT, and refunds). That’s not a windfall, but it’s far more than I ever expected to earn on the back of a month-long jam game, and it all went to paying our 2019 taxes so it’s like nothing ever happened. It certainly makes me optimistic about selling something meatier.

Creating the Steam release

We did update the game somewhat for Steam, a process that ended up consuming almost a month somehow and still didn’t cover everything we wanted. The most obvious in-game things were the addition of character profiles, an image gallery, and an options menu — which is to say, all UI things, which I had to build in LÖVE, by hand, which was an incredible pain in the ass. But it works, somehow.

Of course I also added a bunch of Steam achievements, which were kinda fun to decide upon. It’s a story game, so they’re mostly of the form “encounter this bit of the story”, but that’s fine?

But oh boy, the thing that really took the longest time was linking to Steam at all. You get a DLL/SO, some header files, and some hit-or-miss documentation, and the rest is up to you.

The library is, of course, designed for C++.

I am not using C++. I am using Lua.

This posed something of a problem.

I prefer not to touch C++ with a ten-foot pole, so writing some glue on the C++ side did not sound appetizing. (That would’ve also left me with the difficult problem of compiling that code for platforms I do not own or develop on.) That left me with binding to the Steam API from the Lua side.

After several days of Googling, finding years-old projects that promised to do this, and completely failing to get anywhere at all with them, I resigned myself to writing something from scratch. LÖVE uses LuaJIT, which comes with the excellent FFI library, meaning I could bind to C with nothing more than a header file.

The Steam API does have a C compatibility layer, but it is basically not documented, so I had to do some guesswork to get from the documentation to the parts I actually needed. Also, the core of the Steam API is this hokey async messaging system built out of macros and C++ metaprogramming, so I had to do a clumsier polling thing using disparate parts of the C API instead. I finally discovered that there’s example code in a big honking comment in the headers themselves, except the example code is wrong, so I had to fix that as well. Plus all the obtuse bugs like with padding on different platforms which for some reason is baked into the messages that Steam sends because C programmers don’t know how to actually fucking serialize anything. It was an adventure!!

But after all that, I managed to get achievements working, and also leaderboards. Neat, cool, etc.

The game does leak coroutines indefinitely if it’s run through Steam but can’t connect, though. Sorry.

Man. The Steam website has so many features, and the documentation explains them all in one succinct list, but fuck me if I can actually find any of them. So many things are not linked from obvious places; there have been many times I knew a particular page existed but could not figure out how to get there, and ultimately I started relying on address bar history instead of trying to navigate this website.

And so many features are awkwardly built on top of older features that are actually something completely different. Like we have a “developer” page on Steam, but the only part of it we can really control is a single line of plain text at the top. If you go to the “about” tab, it just shows you that line again! That’s all we can put there! You have to click “visit group page” (why would you do that??) in the sidebar of that page to actually get to something we can control.

In stark contrast to itch, Steam really wants your store page to look like a Steam store page and not like a your-game store page. Your artwork (and there is so much artwork) has to be manually approved by a human, and along the way I discovered some extremely unintuitive rules, like that the library header has to be SFW even though it’s only visible to people who already own the game. Store pages also have a “legal” section, but I couldn’t list open source libraries I used (and their licenses) in that section, because I’m not allowed to have links. Like, at all. They really don’t want you to have links. Games exist independently of the humans that made them in the world of Steam; they are isolated jewels floating in a vast space that is linked directly to gaben’s bank account.

I cannot comprehend how weirdly low-key hostile the whole experience felt. All so they could take a third of my money.

Oh, and there’s no Mac release, because I do not have a Mac on which to sign Mac software and do not wish to pay Apple for the privilege, and Mac software does not run any more if it’s not signed. Sorry. Yes, I fucking know about fucking right-click open, please stop fucking telling me about that, that is not useful for software that is run from someone else’s launcher.

Reception

People seem to like it?? I mean, I’ve had a dozen or so people tell me to my face that they had an especially good experience with it, that it was cozy and upbeat and just nice. For a few of them, it apparently helped ease some aversion they’d had to sex, simply by showing it playing out well.

It’s funny that I thought so hard about the general design and how agency worked and all that, but 99% of the feedback has been about the feeling of the prose itself — something that just kinda fell out of my fingers. I guess I’m not surprised — after all, if these players thought as hard about game design as I do, they’d probably be designing games.

As of this writing, there have been 19.5k downloads on itch and 1750 sales on Steam. Of the Steam sales, a hair under 80% of the people who own the game have actually played it, so if I extrapolate wildly, maybe 17,000 people have played it.

But I don’t see anyone talk about it outside of my immediate circles, which feels a bit weird. Maybe? I’m not sure what the “normal” amount of conversation about an admittedly niche game is. I don’t know how things really spread by word of mouth, and I thought this might be an opportunity to gleam some insight about that, but it has not visibly materialized even though the game is being bought by people I don’t personally know.

On the one hand, it’s a sex game, so many folks are less likely to talk about it. (A couple people even specifically asked if Steam has a way to hide what game you’re playing from your friends — and, alas, it does not.) On the other hand, it’s a furry sex game, and furries are traditionally not so tight-lipped.

Maybe there’s not that much to say; the impact it’s had on people I know has been fairly personal, and if it didn’t have that kind of impact then it’s just a cute little story game.

Lessons learned

I have no idea. There are so many confounding factors here that I don’t know how to conclude anything.

I guess I’m pleasantly surprised by how many people bought a fairly short game for $7. As it turns out, people will give you money for a thing if you ask for it? That’s nice to know.

Releasing on Steam is such a huge pain in the ass lol.

Sales spiked right at the beginning and then flattened fairly quickly, but it still sells a few copies a week, so it looks like it’ll be a little trickle of income for a while. It’d be cool to get a few medium-sized games on Steam as an extra source of income. I suspect porn games have a bit more staying power, too.

Writing UI by hand sucks ass. I gotta switch to Godot asap.

Gamedev from scratch 0: Groundwork

Post Syndicated from Eevee original https://eev.ee/blog/2020/11/30/gamedev-from-scratch-0-groundwork/

You may recall that I once had the ambitious idea to write a book on game development, walking the reader through making simple games from scratch in a variety of different environments, starting from simple level editors and culminating in some “real” engine.

That never quite materialized. As it turns out, writing a book is a huge slog, publishers want almost all of the proceeds, and LaTeX is an endless rabbit hole of distractions that probably consumed more time than actually writing. Also, a book about programming with no copy/paste or animations or hyperlinks kind of sucks.

I thus present to you Plan B: a series of blog posts. This is a narrative reconstruction of a small game I made recently, Star Anise Chronicles: Oh No Wheres Twig??. It took me less than two weeks and I kept quite a few snapshots of the game’s progress, so you’ll get to see a somewhat realistic jaunt through the process of creating a small game from very nearly nothing.

And unlike your typical programming tutorial, I can guarantee that this won’t get you as far as a half-assed Mario clone and then abruptly end. The game has original art and sound, a title screen, an ending, cutscenes, dialogue, UI, and more — so this series will necessarily cover how all of that came about. I will tell you why I made particular decisions, mention planned features I cut, show you the tradeoffs I made, and confess when I made life harder for myself. You know, all the stuff you actually go through when doing game development (or, frankly, any kind of software development).

The target audience is (ideally) anyone who knows what a computer is, so hopefully you can follow along no matter what your experience level. Enjoy!


This is part zero, and it’s mostly introductory stuff. Please don’t skip it! I promise there’s some meat in the latter half.

Table of contents

Here’s what you have to look forward to (though it is of course a WIP until the series is done). Occasionally there’ll be a snapshot of the game, but these were made on a whim during development and aren’t particularly meaningful as milestones.

For reference, I started working on the game the morning of April 29, and I released it the night of May 10, for a total of twelve days.

  • Part 0 (you are here): introduction, tour of PICO-8, putting something on the screen, moving around, measuring time, simple sprite animation

Introduction

This is not a tutorial. Please set your expectations accordingly. Honestly, I don’t even like tutorials — too many of them are framed as something that will teach you a skill, but then only tell you what buttons to press to recreate what the author already made, with no insight as to why they made their decisions or even why they pressed those particular buttons. They often leave you hanging, with no clear next steps, no explanation of what to adjust to get different results.

I’ve never seen a platformer tutorial that actually produced a finished game. Most of them give you just enough to have a stock sprite (poorly) jump around on the screen, perhaps collect some coins, and that’s it. How do you fix the controls, add cutscenes, even make a damn title screen? That’s all left up to you.

This is something much better than a tutorial: a story. I made a video game — a real, complete video game — and I will tell you everything I can remember doing and thinking along the way. Every careful decision, every rushed tradeoff, every boneheaded mistake, every weird diversion. I don’t guarantee that anything I did is necessarily a good idea, but everything I did is an idea, and sometimes that’s all you need to get the gears turning.

If you’re interested in making a video games, I don’t promise that this series will teach you anything. But with a little effort, you can probably learn something. And to be frank, if you’re starting with zero knowledge but still manage to muddle through the whole series, you’ve got more than enough curiosity and determination to succeed at whatever you feel like doing.

The game in question is Star Anise Chronicles: Oh No Wheres Twig??, which I made with the PICO-8. (If you are from the future, I specifically used version 0.2.0i; later versions may have added conveniences I’m not using.) This is not a whizbang fully-featured game engine like Godot or Unity. If I want to draw something, I have to draw it myself. If I want physics, I have to write them myself. If I want shaders… well, that’s not going to happen, but a little ingenuity can still go a long way.

And that kind of ingenuity is what makes game development appealing to me in the first place. It’s one big puzzle: given the tools I have, what’s the most interesting thing I can make with the least amount of hapless flailing? That question will come up a number of times in this series.

If any of this sounds appealing to you, keep reading! Follow along if you can. You can get the PICO-8 (tragically not open source) for $15, and chances are you already own it — it was in the itch.io BLM bundle, so if you bought that, you’re free to download it whenever you want.

Conventions

In order to replicate the experience of reading the book, I’m porting these little “admonition” boxes from what I’d started. I have a somewhat meandering writing style, and hopefully these will help get tangents out of the main text, while also better highlighting warnings and gotchas.

Here they are, in no particular order:

I reserve the right to invent more, if they’re needed and/or funny.

Setting expectations, again

Game development is about a lot more than programming, but this will contain an awful lot of programming. The PICO-8 in particular tends to blur the lines between code and assets if you want to do anything fancy.

That puts me in a tricky position as an author. I want this to be accessible to people with little or no programming experience, but I can’t realistically explain every single line of code I write, or this series will never end (and will be more noise than signal for intermediate programmers).

Thus, I’m trusting you to look up basic concepts on your own if you need to. I’m writing this to fill a perceived gap, so I’ll try to focus on the gaps — finding resources on from-scratch collision detection is a crapshoot, but the web is awash in explanations of what a “variable” is. PICO-8 uses a programming language called Lua which is pretty simple and easy to pick up, so if you’re having trouble, maybe thumb through the Programming in Lua book a bit too.

Of course, if you’re just here for the ride and not too worried about writing your own game, you can skip ahead whenever you like. I’m not your mom.

(Oh, and if you’ve used Lua before, you should know that PICO-8’s Lua has been modified from stock Lua. The precise list of changes would be a big block of stuff in the middle of this already too long intro, so I’ve put it at the bottom. The upshot is: numbers are fixed-point instead of floating-point, you can use compound assignment, and the standard library is almost completely different.)

That’s probably enough words with no pictures. Time to get started.

The PICO-8

A fresh PICO-8 window, with white old-school text on a small black screen and a command prompt

As mentioned, this is a game built with the PICO-8. I promised I’d tell you a story, but I can’t even explain why I chose PICO-8 if you don’t know what the thing is.

PICO-8 is a “fantasy console” — a genre that it pioneered. It has a fixed screen size, its own palette, its own font, a little chiptune synthesizer, its own idea of what buttons the player can press, and so on. It’s like an emulator for an 8-bit handheld that doesn’t actually exist, plus a bunch of relatively friendly tools for making cartridges for that handheld. It even has some arbitrary limitations to preserve that aesthetic. (I carefully avoid calling them artificial limitations, because there are some technical reasons for them, and a lot of programmers do a thing with their face if you say “artificial” to them. Like you’ve just spat in their lunch.)

If you’ve got PICO-8 open, you can type splore at this little command prompt to open the cartridge explorer, which lets you download and play cartridges that have been posted to the PICO-8 BBS (forum). You might want to try a few to get a sense of what the PICO-8 can do, though bear in mind that some of the best games are incredible feats of ingenuity and not representative. A good place to start is the “featured” tab, which lists games that… I believe have been hand-picked as high-quality? Some suggestions:

  • Star Anise Chronicles: Oh No Wheres Twig is in there, as is our older (and first!) game Under Construction.

  • The original PICO-8 version of Celeste, if you weren’t aware of its origins.

  • Dusk Child, one of the earliest games I played and a big inspiration — it’s pretty and expansive, but doesn’t do anything I couldn’t figure out.

  • Just One Boss, which is just so damn crisp.

  • Dank Tomb, a dungeon crawler with absolutely beautiful lighting effects.

  • PicoHot, which is absolute fucking nonsense how dare you.

Note that when playing most games, the PICO-8 functions as though it only had six buttons: a directional pad bound to the arrow keys, and “O” and “X” buttons bound to the Z and X keys. Most games refer to those buttons by name (the PICO-8 font has built-in symbols for them) rather than keyboard key, since you might be playing on a controller or with some other bindings. You can always press Esc for the built-in menu.

Had fun? Great! Pressing Esc takes you back to the prompt. From there, you can press Esc again to switch to the editor (and vice versa).

Now, this is not a PICO-8 tutorial. But the PICO-8’s design and constraints immensely impact how much I could do and how I planned to do it, so I can’t very well explain my thought process without that context. Luckily, all the code and assets for the last game you played stay loaded, so I might as well give you the whirlwind tour. Even if you’re not following along with an actual copy of PICO-8, you should keep reading so you understand what I’ve got to work with.

Code editor

A very small text editor, populated with code

This is the code editor, a very tiny text editor. If you’ve loaded Under Construction, feel free to page through and see what I did. (Keyboard shortcuts help a lot; see the manual for a full list of them. There are also some cheat sheets floating around, though they focus more on programming capabilities.)

You may have noticed the ominous 7695/8192 in the bottom right. That’s hinting at one of the PICO-8’s limitations: the token count. A cartridge’s source code cannot exceed 8192 tokens, or it will not run at all. A “token” is, in general terms, a single “word” of code — a number like 133, a name like animframedelay, an operator like +, a keyword like function, and so on. The term “token” is borrowed from the field of parsing, which is an entire tangent you are free to look up yourself.

The PICO-8’s definition of “token” is slightly different from its typical usage and includes a few exceptions. The common Lua keywords local and end don’t count at all; nor do commas, periods, semicolons, or comments. A string of any length is one token. A pair of parentheses, brackets, or braces only counts as one token. Negative literal numbers (e.g., -25) are one token.

The token limit is the most oppressive of the limits on your code, but there are two others. The full size of your code cannot exceed 64KiB, though in practice I’ve never come anywhere near that size and I think you’d only approach it if you were committing some serious shenanigans. More of concern, the compressed size of your code cannot exceed 15,616 bytes. I do wind up battling that one near the end of this project (as I did with Under Construction), and it can be extra frustrating since it’s hard to gauge exactly what impact any particular change will have on compression. Thankfully, and unlike with the token limit, the PICO-8 will still run a game that’s over the compressed size; it just physically cannot export it to a cartridge.

Incidentally, you can use Alt and an arrow key to move between the editors.

Sprite editor

A very small sprite editor, showing the mole player character from Under Construction

Here we have a tiny pixel art editor. As you might have guessed, the “native” size for a tile is 8 × 8 pixels, though you can use the bottom of the two sliders to edit bigger blocks of tiles at a time. (The screen is 128 × 128 pixels, or 16 × 16 tiles.) You have at your disposal a spritesheet of 256 such tiles, which are arranged at the bottom of the screen in four tabs of 64 tiles each. 001 here is the tile number. Each tile has its own set of 8 flags you can toggle on and off, which are represented by the eight circles just above the tabs; here, all the flags are off. The flags do nothing by themselves, but you can use them for whatever you like, and they turn out to be pretty handy.

The palette is 16 colors, as shown. There are 16 more colors on the “secret palette” which I’ll be dipping into later, but you can only swap them in; you can never have more than 16 distinct colors on screen at the same time. This is reminiscent of how some early systems actually worked.

Map editor

A very small map editor, showing the upper left of a cave-like area from Under Construction

The map editor edits the map. You only get one; if you want to carve it up somehow, that’s up to you. It’s extremely simple: you have a grid of 128 × 64 tiles (that’s 8 × 4 screenfuls), and you can pick which tile goes in each cell. No layers, no stacking, no two things in the same cell. You can pan around with the middle mouse button and zoom with the mouse wheel (or check the manual for the keyboard equivalents).

The especially nice thing about the map is that you can draw entire blocks of it with the built-in map function, which saves a whole lot of tokens over drawing a bunch of tiles by hand. Even if you’re making a game that doesn’t have a literal map, it’s a convenient way to define and draw blocks of multiple tiles.

The catch is that the bottom half of the spritesheet and the bottom half of the map are shared, so you can’t actually have a full map and a full set of tiles in the same cartridge. You could have a full 8 × 4 map and 128 tiles, or you could have a full set of 256 tiles but only an 8 × 2 map, or you can split the space up somehow, but you can’t have the maximum of both. Drawing in the bottom half of one will immediately update the other with garbage. It’s beautiful, actually, if you’re into the aesthetic of arbitrary memory being drawn as tiles.

If you have a cartridge open, you can see this yourself: check out the bottom half of the map (it helps to use Tab or the buttons in the upper left to hide the tile palette) and tabs 2 and 3 of the sprite editor. If they’re not both completely empty, something will be full of garbage. Try drawing in one or the other, if you like, and you’ll see the other update with junk. That’s the memory layout of pixel data being interpreted as map data, or vice versa. Cool, right?

Sound editor

A very small sound editor, showing a sound as bars representing pitch
The same sound, but shown using a tracker-like interface

The sound editor (or SFX editor) does a lot, despite being very simple conceptually, and it can be a little intimidating if you’ve never worked with sound or music before. These screenshots are the two display modes, “pitch mode” and “tracker mode” — allegedly pitch mode is more suitable for sound effects and tracker mode is more suitable for music, but I honestly have no idea how anyone does anything in pitch mode, and I use tracker mode for both. Your mileage may vary. As with the map editor, use Tab or the buttons in the top-left to switch views.

There are 64 sound effects to work with, each consisting of 32 notes played by a little chiptune synth. Notes consist of a pitch (i.e., the actual note being played), an instrument, the volume, and an optional effect.

I could say an awful lot about sound and chiptunes and what any of this means, but this is not a chiptuning tutorial, so I’ll save that for when I actually made some sounds for the game. Do feel free to mess around here, though.

There’s also a music editor, but all it does is arrange several sound effects to play at the same time, so it’s not especially interesting.

And that’s everything at my disposal! I guess that means it’s time to get started, for real. Go back to the command prompt and use reboot to get a fresh blank cartridge, if you’re planning on following along.

Inspiration

The first step to making a game is having a game you want to make.

I started on this at the end of April, after a very rushed month spent preparing the Steam release of Cherry Kisses. I was pretty pumped about having just published something in a very visible place for the first time, and I wanted to keep that energy going, but I didn’t want to immediately jump into an even larger thing. I wanted to make something small, something self-contained, something I could do entirely on my own. (My spouse is the better artist by far, and they did all the art for Cherry Kisses.)

The PICO-8 came to mind as the obvious platform to use. For one, the limitations make it very difficult for a game’s scope to balloon very far; you will simply run out of space and have to cut some ideas. For two, the art and audio are fairly low-resolution, so I wouldn’t have much opportunity to endlessly fuss over trying to make them perfect. For three, it runs in a browser, even on phones, so the resulting game would be easy for anyone to play. (Having to download a thing will discourage a surprising amount of casual passersby, especially if the thing is fairly small and thus low-reward.)

I also just find the PICO-8 endlessly charming, and I hadn’t touched it in a couple years and was curious how it had improved in the interim. It’s great for a game started on a whim, too, since I can jump in and start slapping stuff on the screen without worrying that my ADHD brain will start fretting over how everything should be organized.

That only left the question of what to make.

Two and a half years prior — almost three, now — I’d started on a platformer where you played as Star Anise, my cat’s fursona. It was intended to be a goofy Metroidvania where you collected cat-themed powers, ran around defeating little monsters, collected useless garbage, and generally left a trail of minor mayhem in your wake. Sadly, it was interrupted by real-life events and we haven’t touched it since.

A clip of a pastel game where a small cat meows loudly and shoots a bubble gun that knocks jars off of shelves.

I loved how this game was shaping up! It was so goofy, but its goofiness really opened up the design. Star Anise is great to build a game around. I can give him all manner of strong yet absurd motivations, and as long as I tie them to something vaguely cat-themed, they’ll be memorable and feel sensible. I can load him up with goofy cat-themed powers without needing any kind of justification, because he’s a cat, and everyone knows cats are basically magic anyway. He has a group of friends already built in: other cats. And most importantly, he’s just fun to play as, because everything he does is ridiculous and overboard, but you never have to feel guilty about his mischief because he’s a cat.

It’s such a good hook. I’ve wanted to make a whole series of little Star Anise games, but the furthest I’d gotten so far was Star Anise Chronicles: Escape from the Chamber of Despair — which is good, but is also a text adventure, one of the most impenetrable genres imaginable.

So why not take another crack at it? I couldn’t fit the entire original vision into a PICO-8 game, but surely I’d have enough room for Star Anise, a few of the abilities we’d come up with, and some things to interact with. At long last, a Star Anise platformer.

You could say the stars aligned. The stars. Get it? Like Star Anise. Okay.

From zero to something

Before I could do anything, I needed some art. Okay, that’s not true; I could have boxes moving around on the screen, but I’ve done this enough that I am beyond tired of boxes. If I’m gonna make a Star Anise game then I want to have Star Anise on the damn screen right from the start.

And right away I had to make some decisions. I wanted this to be a little bit Metroidvania style, where Star Anise gained his handful of powers throughout the game and could then explore new areas.

That meant I wanted as much map space as humanly possible, so from the very beginning I knew the sprite/map split I wanted: all map. 32 screens, but only 128 sprites.

And that made several other decisions, automatically. I probably wouldn’t have enough sprite space to include a gun and enemies and whatnot, but a puzzler would let me skip all of that.

This is why I chose PICO-8! The game basically decided its own design with only minimal input from me. Puzzle platformer with some powerups.

Now, to draw Star Anise, which meant deciding how big he should be. A very conspicuous part of his design is his huge helmet, which wouldn’t fit especially well in a single 8×8 tile, or even in two of them stacked. I decided to go one bigger and make a 2×3 block.

A charming little Star Anise sprite, with some extra bits next to him

This wasn’t especially complicated to draw. At this size, it feels like a lot of the sprites draw themselves, too. It did help that I’d already seen my spouse’s interpretation of Star Anise from the prototype game above, but I think the general lesson there is to look at existing art that’s similar to what you want to draw and reverse-engineer the bits that make it work. Here, I made a big circle, squeezed in the narrowest possible face — a pixel each for the eyes, then three pixels for spacing — and gave him a rectangle for his body. Toss a couple stars into the inside of the helmet and, presto, that’s Star Anise.

You might be wondering about those weird extra tiles on the side! I’ll get to those in a moment.

With Star Anise drawn, the obvious first thing is to put him on the dang screen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function _init()
end

function _update()
end

function _draw()
    cls()
    spr(1, 64, 64, 2, 3)
end

Some explanation may be in order. For starters, a “function” is a block of code that can be used repeatedly. (But then, this is not a programming tutorial.) These particular functions are special to the PICO-8: _init runs when the cartridge starts, _update runs every frame, and _draw also runs every frame.

What’s a frame, you ask? Well, you know how movies aren’t really showing movement, but are more like a very fast slideshow? Real life is “continuous” — that is, events occur smoothly over time, so when an object moves, it goes through every point between where it started and where it ends up. But we have no way to record that motion in full, becuase that would be an infinite amount of information! The best we can do is take a lot of snapshots very close together. And it turns out our eyes also work with snapshots (more or less), so it works well enough.

Likewise, simulating continuous behavior is extremely difficult, so video games tend to cheat the same way. We slice time into thin chunks — also called frames — and during each one, we move everything in the world ahead by that amount of time. If frames are short enough, you get the illusion that the world is behaving smoothly. Surprise! It’s all fake.

Modern games can (or should) deal with a varying frame rate, where each frame is a slightly (or greatly) different duration for any of myriad reasons. Since the PICO-8 is a faux-retro console, I’ll be using the retro term tic. It means the same thing, but it’s sometimes used for older systems where the framerate is reliably fixed, usually because it’s tied to (or even enforced by) hardware somewhere. Here it’s just emulated, but, you know, close enough.

Right, so, back to the PICO-8 itself. Every tic (of which there are 30 per second), the PICO-8 does two things: it calls _update to advance the game, then it calls _draw to draw the new state of the game to the screen. You might immediately wonder: why have these be separate if they happen one after the other anyway? Great question! The answer is that the PICO-8 does something clever — if it notices that the _update + _draw combination is taking longer than one tic (and the game is thus starting to lag), it will automatically drop down to 15 FPS. In this mode, it will call _update twice and then call _draw. Here is a terrible ASCII diagram.

1
2
3
4
5
        | tic                   | tic                   |
--------+-----------------------+-----------------------+
30 FPS: | _update() _draw()     | _update() _draw()     |
--------+-----------------------+-----------------------+
15 FPS: | _update() _update() _draw()                   |

As you can see, the game still updates twice in the same amount of time, so it still runs at the same speed, but it only draws half as often. With any luck, that saves enough effort that the game can keep running at the intended speed.

All of that is to say: the _draw function draws to the screen.

The first thing you (usually) want to do in _draw is clear the screen, which is accomplished by the charmingly terse cls(). If you don’t do this, your game will merrily draw right on top of whatever was on the screen previously: the prompt, a previous game, even the code editor.

After that, I called spr() to draw Star Anise. The usual arguments are spr(n, x, y), where n is the sprite number (visible near the middle of the screen in the sprite editor) and x, y say where to place him. He’s made up of six tiles, and you might think that drawing six tiles would thus require calling spr() six times, but it helpfully takes two more optional arguments: how many tiles to draw, as a single rectangle taken from the spritesheet. The above code thus draws a 2-by-3 block of tiles, starting from tile 1, at the coordinates (64, 64) — the center of the screen.

As is programming tradition, sprites are drawn from their top-left corner, so the initial tile is the top-left of the rectangle that gets drawn, and the coordinates are where the top-left of the drawn rectangle appears on screen. Thus, Star Anise appears with his top left “corner” in the middle of the screen.

Star Anise standing near the middle of the screen, as promised

There he is! How immensely satisfying. I always try to get something “real” drawing as early as humanly possible. It helps me feel like I’ve made some progress, like I’m working on a specific game and have made steps towards making it exist. This is already, quite clearly, a Star Anise game, but that wouldn’t be obvious if I’d started out with rectangles.

Now what? A good start would be to have him move around a bit. That’s easy enough if I introduce some state.

I do need to check what buttons the player is pressing, which I can do with btn(b), where b is the button… number. Left is button 0, right is button 1, up is button 2… but that makes for some unreadable garbage, so instead, let’s use a recently-introduced shortcut. If you hold Shift and press U, D, L, R, O, or X, the PICO-8 will insert a symbol representing that button. (I will be representing those symbols as ⬆️⬇️⬅️➡️🅾️❎, which is how the PICO-8 stores them on disk.)

That’s enough to move him around:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function _init()
end

local px = 64
local py = 64

function _update()
    if btn(⬆️) then
        py -= 1
    end
    if btn(⬇️) then
        py += 1
    end
    if btn(⬅️) then
        px -= 1
    end
    if btn(➡️) then
        px += 1
    end
end

function _draw()
    cls()
    spr(1, px, py, 2, 3)
end

Here I’ve put his position (still anchored at his top-left) into some variables, and during _update() I update them. (If you’re familiar with Lua, you may balk at += and -= — these are extensions added by PICO-8, and they save enough space that they’re definitely worth it.)

Star Anise sliding around the screen

This is already halfway to being a game — it does something when I press buttons! Excellent. But also weird. This doesn’t look like Star Anise is walking around; it looks like he’s a static image being dragged by an invisible cursor or something. A very easy aesthetic improvement would be to make him not moonwalk when moving left.

That’s easy enough; the spr() function takes two more optional arguments, indicating whether to flip the sprite horizontally and/or vertically. I can just slap those in when he’s moving left. Or, well, not quite — I want to flip him when the last direction he moved was left. If he moves left and then stops, or moves left and then up and down, he should still be facing left.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function _init()
end

local px = 64
local py = 64
local left = false

function _update()
    if btn(⬆️) then
        py -= 1
    end
    if btn(⬇️) then
        py += 1
    end
    if btn(⬅️) then
        px -= 1
        left = true
    end
    if btn(➡️) then
        px += 1
        left = false
    end
end

function _draw()
    cls()
    spr(1, px, py, 2, 3, left)
end
Star Anise sliding around the screen, but turning around when moving left

Making progress, but obviously he’d look a lot better if he were animated, right?

Which, finally, brings us back to those extra tiles I drew. They’re copies of Star Anise’s legs and antenna, lightly edited to look like he’s in mid-step. The legs are sticking out all the way, and the antenna is adjusted to be… positioned slightly differently, since it’s bouncy. It’s a bit rough, but I can touch it up later.

Star Anise's walk animation

Note that I’ve crammed as much movement into as little space as possible here. This is only a two-frame animation, so the leg movement is exaggerated to get the most bang for my buck. I don’t even duplicate the entirety of Star Anise for the other frame; instead, I only copied the tiles that change. That’ll make him more complicated to draw, but it does save me sprite space — remember, I only have 127 tiles available, and 9 of them is already 7% gone. (Writing more code to save on limited asset space is, in my experience, a pretty common PICO-8 tactic.)

Unfortunately, this makes flipping his sprite somewhat more complicated. I can’t just use that argument to spr(), because— well, I’ll get to that in a second. Here’s the updated code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
local anise_stand = {1, 2, 17, 18, 33, 34}
local anise_jump = {3, 2, 17, 18, 19, 35}

function _init()
end

local t = 0
local px = 64
local py = 64
local left = false
local moving = false

function _update()
    t += 1
    t %= 120

    moving = false
    if btn(⬆️) then
        py -= 1
        moving = true
    end
    if btn(⬇️) then
        py += 1
        moving = true
    end
    if btn(⬅️) then
        px -= 1
        moving = true
        left = true
    end
    if btn(➡️) then
        px += 1
        moving = true
        left = false
    end
end

function _draw()
    cls()

    local pose = anise_stand
    if moving and t % 8 < 4 then
        pose = anise_jump
    end
    local y = py
    local x0 = px
    local dx = 8
    if left then
        dx = -8
        x0 += 8
    end
    local x = x0
    for i = 1, #pose do
        spr(pose[i], x, y, 1, 1, left)
        if i % 2 == 0 then
            x = x0
            y += 8
        else
            x += dx
        end
    end
end

That sure got longer in a hurry! A quick overview:

I’ve introduced a global called t to act as a clock. I intend to use this for animation and other global cycles, so I don’t care about the actual time — that’s why I take it mod 120.

If you’re not familiar, the % (or “modulus”) operator gives you the remainder after division. It’s super duper useful and I wish we taught it as a primitive math operation! You can think of it like “clock arithmetic” — if it’s 9 o’clock and you wait 4 hours, it becomes 1 o’clock, which is the remainder when you divide 9 + 4 by 12. Or you can think of it as removing all chunks of something — to convert the 24-hour “13 o’clock” to 12-hour, you remove all the 12s, leaving just 1 behind. Or you can think of it as coiling the entire number line into a circle, so after 11 you wrap around to 0 and start over. (That’s not quite how clocks work, but using 0–11 turns out to be much simpler than using 1–12.)

The upshot here is that t will hit 119 and then wrap back around to zero, which is important because PICO-8 numbers can’t go any higher than 32767. If I left it to its own devices, it would still wrap around, but to the more cumbersome -32768. I don’t want a negative clock!

But why 120? Because I want to be able to divide the clock cycle into smaller animation cycles, and I can only do that evenly if the whole clock’s length is a multiple of the smaller cycle’s length. (On a more powerful system, I’d have a more elaborate animation setup, but that would cost more space and code than I’m willing to spend here.) Consider if I had a clock that wrapped around at 10, and I wanted an animation 3 tics long. I would use modulo 3 to shrink the clock, resulting in:

Whoops! Frame 0 will show twice in a row, intermittently, even seemingly at random. That’s not great. For the best chance of avoiding that problem without having to think too hard about it, I want a clock whose length is divisible by as much stuff as possible — a highly composite number. And, of course, 120 is one such number.

Next, I track whether Star Anise is moving at all, so I know whether to play the walk animation. Note that I always assume he isn’t moving, and then correct myself if it turns out he is; otherwise, the new value of moving would persist into future tics and he’d never stop.

That brings me to the new drawing code, which is a little tricky, so here it is a bit at a time:

1
2
3
4
5
6
7
8
9
-- top of the file
local anise_stand = {1, 2, 17, 18, 33, 34}
local anise_jump = {3, 2, 17, 18, 19, 35}

    -- in _draw()
    local pose = anise_stand
    if moving and t % 8 < 4 then
        pose = anise_jump
    end

This decides which tiles I’m going to draw. I can’t draw the walking part (which I’ve called “jump” because it does look like a jump in isolation, and I’ll be reusing them for that later) as a single block with spr() like before, and I’d like to share the code, so both frames are now assembled from individual tiles.

Note that tiles 1, 2, 17, 18, 33, and 34 are exactly the ones I was drawing in a single spr() call before. (The numbers increase by 16 when jumping to the next row, which makes sense, because each row has 16 tiles in it.) The other set is similar, but it has the alternate tiles substituted in.

I only want to use the jump tiles if Star Anise is moving, and if t % 8 < 4. That % turns my 120-tic clock into an 8-tic clock, then checks if we’re in the first half of it. Essentially: if it’s before noon, show the alternate frame; otherwise, show the normal standing frame.

The use of a global timer does have some subtle drawbacks here. If I tap an arrow key to move Star Anise only very briefly, then he may or may not animate, depending on whether the tap happens to be during the “stand” or “jump” intervals. A more powerful system, where every animation kept track of its own time, would always briefly show him moving. (On the other hand, this is an interesting aesthetic in its own right that kinda complements the very low-res and exaggerated animation.)

Next I need to draw the tiles, but we’ve come to the catch I mentioned before. When I draw Star Anise flipped, I’m now drawing him as a bunch of separate tiles. If I drew them in the same left-to-right order, then his left side would be flipped, and his right side would be flipped, but the whole image wouldn’t be. Er, just look at this picture.

Star Anise's walk frames, flipped one tile at a time

See? The tiles are arranged the same way, but each one is individually flipped, and the result is… not what I want. I’ll need to also draw the columns in reverse order. And that’s exactly what I do:

45
46
47
48
49
50
51
    local y = py
    local x0 = px
    local dx = 8
    if left then
        dx = -8
        x0 += 8
    end

Here I’m determining the start point and how far apart the tiles are. The variable names are fairly terse, for a couple of reasons: one, the PICO-8 screen is not very wide, so long variable names make code much harder to read; but also, math code tends to be easier to follow with shorter names anyway. I’ve even taken the naming conventions from math — the initial state of a variable is often written with a subscript zero (\(x_0\)) and a change is written with the Greek letter delta (\(\Delta x\)), so I’ve used the ASCII equivalents of those, x0 and dx.

I’m starting from Star Anise’s position, of course, and then each tile is 8 pixels right of the previous one… if he’s not flipped. If he is flipped, I want to move left, which will draw the tiles in reverse order. But that would change where he draws from, so to compensate, I also start drawing 8 pixels right of where I usually would. (Try to convince yourself that this is correct; on a flipped Star Anise, tile number 1 should draw 8 pixels left from his upper-left corner.)

52
53
54
55
56
57
58
59
60
61
    local x = x0
    for i = 1, #pose do
        spr(pose[i], x, y, 1, 1, left)
        if i % 2 == 0 then
            x = x0
            y += 8
        else
            x += dx
        end
    end

All that’s left to do is the drawing itself. For each tile in the pose list, I draw that tile. Each row is two tiles wide, so after every second tile, I reset the horizontal “cursor” (x) back to where it started and move down by one row’s worth of pixels. For any other tile, I just move horizontally by dx.

The results are basically magic.

Star Anise walking around the screen and turning to face the way he's moving

And that’s a good place to pause for now. Yes, I know, we didn’t get very far, but this is part zero! It’s mostly a test of this series and its tone for me, and a test of fortitude for you. I hope you could follow along with the minor mathematical hijinks above, because next time it gets much worse — before I can do anything else at all, I have to write collision detection. Oh boy! Stay tuned! And always feel free to ask questions, of me or anyone else!

Appendix: PICO-8 Lua extensions

Here are all the modifications PICO-8 has made to the language (based on Lua 5.2). If you’ve never used Lua, keep in mind that these won’t carry over if you try to write Lua anywhere else. Some of these are advanced features, so if you have no idea what something means, that’s probably fine.

Spoilers: it’s mostly that the standard library has changed.

  • Numbers are signed 15.16 fixed-point, rather than stock Lua’s 64-bit floating point. That means fractions can only be represented in increments of 0.0000152587890625 (= \(2^{-16}\), a cumbersome number I refer to as the “Planck size”), and numbers can’t exceed ±32768.

  • Compound assignment is supported: a += b works as in a = a + b in stock Lua, where + can be replaced with any binary operator.

  • != is allowed as an alias for ~=.

  • if (foo) bar = 1 is shorthand for if foo then bar = 1 end. The parentheses are required, and the condition ends at the end of the line. (I strongly advise against using this unless you’re very desperate for space; it scans poorly and doesn’t even save tokens.)

  • The new @, %, and $ unary prefix operators read 1, 2, or 4 bytes from a memory address. (PICO-8’s memory, not system RAM!)

  • The ? unary prefix operator is equivalent to print. (I’ve never used it, and it’s not even directly documented.)

  • The built-in functions collectgarbage, dofile, error, pcall, require, select, and xpcall are not available (though the lack of select might be a bug).

    The built-in variables _G and _VERSION are not available.

    load has been replaced with a function that loads PICO-8 carts from files.

    print has been replaced with a drawing function, which prints a single string at a position on screen.

    tonumber and tostring have been replaced with tonum and tostr, which behave slightly differently (but tostr does still respect the __tostring metatable field).

    (assert, getmetatable, ipairs, next, pairs, rawequal, rawget, rawlen, rawset, setmetatable, and type still exist and work as in stock Lua.)

  • The coroutine library is not available, but most of its contents are exposed directly as cocreate, coresume, costatus, and yield. There is no equivalent for coroutine.running or coroutine.wrap.

  • The require function and package library are not available, though the #include syntax can be used to textually substitute the contents of a Lua file.

  • The string library is not available. Replacement string functions are: chr, ord, split, and sub.

  • The table library is not available. Replacement table functions are: add, del, deli, count, all, foreach. There is no built-in way to concatenate or sort a list.

  • The math library is not available. Replacement math functions are: max, min, mid, flr, ceil, sin, cos, atan2, sqrt, abs, rnd, srand. There is also an integer division operator, \.

  • The bit32 library is not available, but bitwise operations are available as both functions — band, bor, bxor, bnot, shl, shr, lshr, rotl, rotr — and operators — &, |, ^^, ~, <<, >>, >>>, <<>, >><.

  • The io library is not available. Running PICO-8 cartridges have no notion of a filesystem.

  • The os library is not available. Running PICO-8 cartridges have no direct access to the underlying operating system. (Some facilities are exposed through the “syscall” function stat, such as accessing the current UTC or local time.)

  • The debug library is not available.

  • A number of other new functions were added, though I won’t list them all here; they’re generally for drawing, working with assets, or interacting with the PICO-8’s faux hardware.

Lexy’s Labyrinth

Post Syndicated from Eevee original https://eev.ee/release/2020/09/26/lexys-labyrinth/

Screenshot of a small tile-based puzzle with a number of different elements, taken from CCLP1

🔗 Lexy’s Labyrinth
🔗 Source code on GitHub
🔗 itch.io later

Here is Lexy’s Labyrinth, a web-based Chip’s Challenge emulator.

It’s easy to get into and mostly speaks for itself, so here is a story.


Once upon a time, there was a puzzle game called Chip’s Challenge. It was created in 1989 for the Atari Lynx, an early handheld that is probably best known for… uh… Chip’s Challenge. It stood out as a curious blend of Sokoban head-scratching with real-time action, and it was one of the first computer puzzle games that had a whole pile of different mechanics and relied on exploiting the interesting interactions between them[citation needed].

The game found wider recognition with its inclusion in Microsoft Entertainment Pack 4, and later the Best of Windows Entertainment Pack (charmingly abbreviated “BOWEP”).


That in itself is a curious story — numerous features of the Atari Lynx version were lost in translation, most notably that the Lynx version has the player and monsters slide smoothly between grid cells, whereas the Microsoft port has everything instantly snap from one cell to the next. Also conspicuous is the presence of several typos in level passwords, which are exactly consistent with a set of notes a player took about the Lynx game, but which would be impossible in a straight port — the Lynx level passwords weren’t manually set, but were generated on the fly by a PRNG.

Screenshot of the Microsoft edition of Chip's Challenge, showing the first level, courtesy of the BBC wiki

The most obvious explanation is that the developer responsible for the Microsoft port didn’t have access to the Lynx source code, and in fact, had never played the original game at all. That would explain nearly every major gameplay difference between the Lynx and Microsoft versions, which are all things you’d never notice if you only had static screenshots and maps to work from. Given that restriction, hey, not a bad job.


I played the BOWEP edition of Chip’s Challenge as a kid and was completely enamoured. I suppose what got me the most was the same thing that I found so compelling about Doom: the ability to modify your environment, whether by using blocks to clear water or toggling green blocks or generating new monsters from a clone machine. Being able to affect my environment in (more or less) free-form ways felt curiously powerful.

Well, let’s not think about that too hard. I’ll save it for my therapist.

Some years later I discovered an incredible tool called The Internet, and with it I learned of the impending Chip’s Challenge 2, a sequel with way more tiles and possibilities! Fantastic!

Unfortunately, there was a complication. Epyx, the original publisher of Chip’s Challenge, had gone bankrupt (somehow!) and had sold most of its assets, including the Chip’s Challenge rights, to a company called Bridgestone Media (now Alpha Omega Productions), a Christian propaganda distributor.

You read that correctly.

Bridgestone, a company that generally dealt in movies, had some very peculiar ideas about the video game industry. Apparently they expected the assets they’d acquired to magically make them filthy rich — you know, just like Jesus would want — despite having acquired them from a company that had just evaporated. As such, they told the original developer, Chuck Somerville, that he could only release Chip’s Challenge 2 if he paid them one million dollars upfront.

He did not have one million dollars, and so Chip’s Challenge 2 languished forever.

(At this point, in hindsight, I wonder why Chuck didn’t simply change the story and tileset and release the game under a different name. Apparently he did start on something like this some years later, in the form of an open clone from scratch called Puzzle Studio, but it was eventually abandoned in favor of Chuck’s Challenge 3D. But I still wonder: why start a brand new thing, rather than rebrand and release the existing thing?)

We did have some descriptions of new Chip’s Challenge 2 mechanics, and so at the ripe old age of 15, with no idea what I was doing, I decided I would simply write my own version of Chip’s Challenge 2.

In QBasic.

Also I didn’t really understand how to handle the passage of time, so the game was turn-based and had no monsters.

But, given all that, it wasn’t that bad. I found the source code a few years ago and put it on GitHub along with a sample level and a description of all the tiles you can use in the plaintext level format. I’ve got a prebuilt binary for DOS (usable in DosBox) too, if you like — just have a levels.txt in the same directory, and be sure it uses DOS line endings. I used to have one or two actual levels, but they have tragically been lost to the sands of time.

Screenshot of my QBasic implementation of Chip's Challenge, using all character-based graphics

That would’ve been 2002.


Thirteen years later, in April 2015, a miracle occurred and defeated the Christians. Chip’s Challenge 2 was released on Steam.

It was fine. I don’t know. Over a decade of anticipation gets your hopes up, maybe. It’s a perfectly good puzzle game, and I don’t want to dunk on it, but sometimes I interact with it and I feel all life drain from my body.

Screenshot of CC2, with an overlaid hint saying: "This is Melinda.  Being female, she does some things differently than Chip."
Screenshot of CC2, with an overlaid hint saying: "She doesn't slide when she steps on ice.  But she needs hiking boots to walk on dirt or gravel."

I don’t even know whether to talk about this completely unreadable way of showing hints or the utterly baffling justification of “being female” for these properties.

But it’s fine. The game was Windows-only, but it was old Windows-only, so Wine handled it perfectly well. I played through a few dozen levels. Passwords were gone, so you were free to skip over levels you just didn’t feel like playing.

And then they patched a level editor into the game, and it completely broke under Wine. Completely. Like, would not even run. It’s only in recent years that it even tries to run, and now it can’t draw the window and crashes if you attempt to do anything.

The funny thing is, apparently it doesn’t draw for some people on Windows, either. It doesn’t for me in a Windows VM. The official sanctioned solution is to… install… wined3d, a Windows port of the Wine implementation of Direct3D.

I don’t know. I don’t know! I don’t know what the hell anything. This situation is utterly baffling. What even are computers.


I gave up on the game until recently, when something reminded me of it and I tried it again in Wine. No luck, obviously. I spent half a day squabbling with bleeding-edge versions and Proton patches and all manner of other crap, then resorted to the Bit Busters Club Discord, but they couldn’t help me either.

And then something stirred, deep inside of me. This game wasn’t that complicated, right? I actually know how to make video games now. I even know how to make art, sort of. And sound. And music. And…


And here I am, a month later, having replicated Chip’s Challenge in a web browser, fueled entirely by some new emotion I’ve discovered that lies halfway between spite and exhaustion. My real goal was to clone Chip’s Challenge 2 so I can actually fucking play this game I bought, but it is of course a more complex game. Still, CC2 support is something like 60% done; most of what remains is wiring, tracks, and ghost/rover behavior.

CC1 support is more interesting, anyway — there are far more custom CC1 levels around, and Lexy’s Labyrinth exposes almost 600 of them a mere click away. Given that the original Microsoft port was 16-bit and is now difficult to run (and impossible to buy), and the official (free!) Steam release is fairly awkward and unmaintained (the dev mostly makes vague statements about “old code”), and even the favored emulator Tile World has the aesthetics and usability of a 1991 Unix application, I’m hoping this will make the Chip’s Challenge experience a little more accessible. It has a partially working level editor, too, which lets you share levels you make by simply passing around a URL, and I think that is fucking fantastic.

LL cannot currently load level packs from the Steam release, but it’s a high priority. In the meantime, if you really want to play the original levels (even though CCLP1 is far better in my experience), it’ll load CHIPS.DAT if you’ve got it lying around. Also, it works on phones!


Probably the most time-consuming parts of this project were the assets. I had to draw a whole tileset from scratch, including all of the CC2 tiles which you don’t even get to see yet (and a few of which aren’t actually done). That probably took a week, spread out over the course of the entire last month. Sound effects took several days, though they got much easier once I decided to give up on doing them by wiring LFOs together in SunVox and just use a bunch of BeepBox presets. I spent a couple days on my own music track, and half a dozen other kind souls chipped in their own music — thank you so much, everyone!

And thank you to the Bit Busters Club, whose incredibly detailed knowledge made it possible to match the behavior of a lot of obscure-but-important interactions. The Steam version of CC1 comes with solution replays, and LL can even play a significant number of them back without ever desyncing.

I’ve been ignoring pretty much everything else for a month to get this in a usable state, so I’d like to take a break from it for now, but I’d really like to get all of CC2 working when I can, and of course make the level editor fully functional. I love accessible modding tools, you don’t see many of them in games any more, and with any luck maybe it’ll inspire some other kid to get into game development later.


…okay, I haven’t been ignoring everything else. I also reused the tiles I drew for a fox flux minigame in a similar style, except that you place a limited set of tiles in empty spaces and then let the game run by itself. Kind of like… Chip’s Challenge meets The Incredible Machine.

Recording of a minigame, showing a drone character interacting with moving floors and following instructions on the ground

(That arrow tile has since been updated to be more clear, but it means “when you hit something, turn around instead of stopping and ending the game.”)

I guess two little puzzle game engines isn’t too bad for not quite a month of work!

Lexy’s Labyrinth

Post Syndicated from Eevee original https://eev.ee/blog/2020/09/26/lexys-labyrinth/

Screenshot of a small tile-based puzzle with a number of different elements, taken from CCLP1

🔗 Lexy’s Labyrinth
🔗 Source code on GitHub
🔗 itch.io later

Here is Lexy’s Labyrinth, a web-based Chip’s Challenge emulator.

It’s easy to get into and mostly speaks for itself, so here is a story.


Once upon a time, there was a puzzle game called Chip’s Challenge. It was created in 1989 for the Atari Lynx, an early handheld that is probably best known for… uh… Chip’s Challenge. It stood out as a curious blend of Sokoban head-scratching with real-time action, and it was one of the first computer puzzle games that had a whole pile of different mechanics and relied on exploiting the interesting interactions between them[citation needed].

The game found wider recognition with its inclusion in Microsoft Entertainment Pack 4, and later the Best of Windows Entertainment Pack (charmingly abbreviated “BOWEP”).


That in itself is a curious story — numerous features of the Atari Lynx version were lost in translation, most notably that the Lynx version has the player and monsters slide smoothly between grid cells, whereas the Microsoft port has everything instantly snap from one cell to the next. Also conspicuous is the presence of several typos in level passwords, which are exactly consistent with a set of notes a player took about the Lynx game, but which would be impossible in a straight port — the Lynx level passwords weren’t manually set, but were generated on the fly by a PRNG.

Screenshot of the Microsoft edition of Chip's Challenge, showing the first level, courtesy of the BBC wiki

The most obvious explanation is that the developer responsible for the Microsoft port didn’t have access to the Lynx source code, and in fact, had never played the original game at all. That would explain nearly every major gameplay difference between the Lynx and Microsoft versions, which are all things you’d never notice if you only had static screenshots and maps to work from. Given that restriction, hey, not a bad job.


I played the BOWEP edition of Chip’s Challenge as a kid and was completely enamoured. I suppose what got me the most was the same thing that I found so compelling about Doom: the ability to modify your environment, whether by using blocks to clear water or toggling green blocks or generating new monsters from a clone machine. Being able to affect my environment in (more or less) free-form ways felt curiously powerful.

Well, let’s not think about that too hard. I’ll save it for my therapist.

Some years later I discovered an incredible tool called The Internet, and with it I learned of the impending Chip’s Challenge 2, a sequel with way more tiles and possibilities! Fantastic!

Unfortunately, there was a complication. Epyx, the original publisher of Chip’s Challenge, had gone bankrupt (somehow!) and had sold most of its assets, including the Chip’s Challenge rights, to a company called Bridgestone Media (now Alpha Omega Productions), a Christian propaganda distributor.

You read that correctly.

Bridgestone, a company that generally dealt in movies, had some very peculiar ideas about the video game industry. Apparently they expected the assets they’d acquired to magically make them filthy rich — you know, just like Jesus would want — despite having acquired them from a company that had just evaporated. As such, they told the original developer, Chuck Somerville, that he could only release Chip’s Challenge 2 if he paid them one million dollars upfront.

He did not have one million dollars, and so Chip’s Challenge 2 languished forever.

(At this point, in hindsight, I wonder why Chuck didn’t simply change the story and tileset and release the game under a different name. Apparently he did start on something like this some years later, in the form of an open clone from scratch called Puzzle Studio, but it was eventually abandoned in favor of Chuck’s Challenge 3D. But I still wonder: why start a brand new thing, rather than rebrand and release the existing thing?)

We did have some descriptions of new Chip’s Challenge 2 mechanics, and so at the ripe old age of 15, with no idea what I was doing, I decided I would simply write my own version of Chip’s Challenge 2.

In QBasic.

Also I didn’t really understand how to handle the passage of time, so the game was turn-based and had no monsters.

But, given all that, it wasn’t that bad. I found the source code a few years ago and put it on GitHub along with a sample level and a description of all the tiles you can use in the plaintext level format. I’ve got a prebuilt binary for DOS (usable in DosBox) too, if you like — just have a levels.txt in the same directory, and be sure it uses DOS line endings. I used to have one or two actual levels, but they have tragically been lost to the sands of time.

Screenshot of my QBasic implementation of Chip's Challenge, using all character-based graphics

That would’ve been 2002.


Thirteen years later, in April 2015, a miracle occurred and defeated the Christians. Chip’s Challenge 2 was released on Steam.

It was fine. I don’t know. Over a decade of anticipation gets your hopes up, maybe. It’s a perfectly good puzzle game, and I don’t want to dunk on it, but sometimes I interact with it and I feel all life drain from my body.

Screenshot of CC2, with an overlaid hint saying: "This is Melinda.  Being female, she does some things differently than Chip."
Screenshot of CC2, with an overlaid hint saying: "She doesn't slide when she steps on ice.  But she needs hiking boots to walk on dirt or gravel."

I don’t even know whether to talk about this completely unreadable way of showing hints or the utterly baffling justification of “being female” for these properties.

But it’s fine. The game was Windows-only, but it was old Windows-only, so Wine handled it perfectly well. I played through a few dozen levels. Passwords were gone, so you were free to skip over levels you just didn’t feel like playing.

And then they patched a level editor into the game, and it completely broke under Wine. Completely. Like, would not even run. It’s only in recent years that it even tries to run, and now it can’t draw the window and crashes if you attempt to do anything.

The funny thing is, apparently it doesn’t draw for some people on Windows, either. It doesn’t for me in a Windows VM. The official sanctioned solution is to… install… wined3d, a Windows port of the Wine implementation of Direct3D.

I don’t know. I don’t know! I don’t know what the hell anything. This situation is utterly baffling. What even are computers.


I gave up on the game until recently, when something reminded me of it and I tried it again in Wine. No luck, obviously. I spent half a day squabbling with bleeding-edge versions and Proton patches and all manner of other crap, then resorted to the Bit Busters Club Discord, but they couldn’t help me either.

And then something stirred, deep inside of me. This game wasn’t that complicated, right? I actually know how to make video games now. I even know how to make art, sort of. And sound. And music. And…


And here I am, a month later, having replicated Chip’s Challenge in a web browser, fueled entirely by some new emotion I’ve discovered that lies halfway between spite and exhaustion. My real goal was to clone Chip’s Challenge 2 so I can actually fucking play this game I bought, but it is of course a more complex game. Still, CC2 support is something like 60% done; most of what remains is wiring, tracks, and ghost/rover behavior.

CC1 support is more interesting, anyway — there are far more custom CC1 levels around, and Lexy’s Labyrinth exposes almost 600 of them a mere click away. Given that the original Microsoft port was 16-bit and is now difficult to run (and impossible to buy), and the official (free!) Steam release is fairly awkward and unmaintained (the dev mostly makes vague statements about “old code”), and even the favored emulator Tile World has the aesthetics and usability of a 1991 Unix application, I’m hoping this will make the Chip’s Challenge experience a little more accessible. It has a partially working level editor, too, which lets you share levels you make by simply passing around a URL, and I think that is fucking fantastic.

LL cannot currently load level packs from the Steam release, but it’s a high priority. In the meantime, if you really want to play the original levels (even though CCLP1 is far better in my experience), it’ll load CHIPS.DAT if you’ve got it lying around. Also, it works on phones!


Probably the most time-consuming parts of this project were the assets. I had to draw a whole tileset from scratch, including all of the CC2 tiles which you don’t even get to see yet (and a few of which aren’t actually done). That probably took a week, spread out over the course of the entire last month. Sound effects took several days, though they got much easier once I decided to give up on doing them by wiring LFOs together in SunVox and just use a bunch of BeepBox presets. I spent a couple days on my own music track, and half a dozen other kind souls chipped in their own music — thank you so much, everyone!

And thank you to the Bit Busters Club, whose incredibly detailed knowledge made it possible to match the behavior of a lot of obscure-but-important interactions. The Steam version of CC1 comes with solution replays, and LL can even play a significant number of them back without ever desyncing.

I’ve been ignoring pretty much everything else for a month to get this in a usable state, so I’d like to take a break from it for now, but I’d really like to get all of CC2 working when I can, and of course make the level editor fully functional. I love accessible modding tools, you don’t see many of them in games any more, and with any luck maybe it’ll inspire some other kid to get into game development later.


…okay, I haven’t been ignoring everything else. I also reused the tiles I drew for a fox flux minigame in a similar style, except that you place a limited set of tiles in empty spaces and then let the game run by itself. Kind of like… Chip’s Challenge meets The Incredible Machine.

Recording of a minigame, showing a drone character interacting with moving floors and following instructions on the ground

(That arrow tile has since been updated to be more clear, but it means “when you hit something, turn around instead of stopping and ending the game.”)

I guess two little puzzle game engines isn’t too bad for not quite a month of work!

fox flux, three years later

Post Syndicated from Eevee original https://eev.ee/dev/2020/08/04/fox-flux-three-years-later/

I’m working on a video game! Like, a serious one.

The past

I wrote the original game (very slightly NSFW) for my own “horny” game jam, Strawberry Jam (more likely to be NSFW), way back in February 2017.

You play as Lexy, my shameless Floraverse self-insert, who owns an enchanted collar that (among other things) makes her basically indestructible and allows her to easy to transform into… whatever, given some kind of sensible trigger. And then you do some puzzle-platforming to collect “strawberry hearts” and gain access to new areas, much of which (surprise!) involves getting turned into things.

For example, this chain-link fence blocks you:

Screenshot of the player being stuck on one side of a fence

But if you let that green blob in the grass turn you into slime, you can walk right through it.

Screenshot of the same area, but the player is now green slime and free to pass through the fence

There are also spikes, which you get stuck on if you land on them… but slime can walk right through them, glass can stand on top of them, and stone outright destroys them. And so on. As a jam game, it’s not very expansive, but many of the puzzle elements interact differently with many of the handful of Lexy variants, which provided enough potential to make eight levels.

Post-jam

The jam game was rough, but I really liked the concept and wanted to expand on it. I spent a good chunk of the summer of 2017 on it, but it was a struggle. I was still fairly new to pretty much every aspect of actually creating a game — I’d only been drawing for two years, I’d sometimes hit big gaps in the design with no idea how to fill them, and I wasn’t yet entirely comfortable with complex physics or shaders. The art in particular was a huge problem; it took me a long time to produce sprites that I was only passably happy with. My spouse Ash is an artist, and we’ve made several games together where they produced all the art, but this was my idea and I was determined to draw it myself.

Then 2018 hit, which was a whole entire mess, and I didn’t really touch fox flux at all for over a year. I made a couple of other games with Ash, some finished, some not, and kept drawing intermittently.

I returned to fox flux for the middle of 2019, and decided… I’m not sure what I decided, exactly. I guess I’d gotten better at all the things that had been difficult for me before, so I set about trying to improve every aspect of the game at once.

  • I realized the (many, many) improved sprites I’d drawn in 2017 were not actually very good, and drew a new Lexy design from scratch that absolutely blew me away… which meant throwing away all the existing art.

  • I’d come up with a few new things for Lexy to turn into, each of which altered her behavior pretty significantly, and her code was becoming a spaghetti disaster. So I spent some time completely refactoring actors into bags of components, which I was unsure about until very recently and which ended up breaking pretty much every single object in the game, sometimes in subtle ways.

  • I decided to add water, which unraveled into a whole pile of decisions and problems.

  • I tried to make consistent or interesting physics for pushing things (e.g. wooden crates), and that became a nightmare. I easily spent weeks on this, trapped in a cycle of finding some edge case that couldn’t be fixed without considerably expanding what I was simulating, struggling to do that expansion while keeping all the basic stuff working, and then finding a new and different edge case.

Did I mention that I tried to do all of these things at the same time, while also trying to nail down the design of a game that’s naturally prone to a combinatoric explosion of interactions?

At a certain point it just felt hopeless. I’d poured easily over a year into this game, and all I had to show for it was a jumbled pile of stuff that didn’t work, strewn about a couple test maps that didn’t even contain any puzzles.

The present

I don’t know what happened, exactly. I’d given up on the heavily-simulated push physics last year, at least, so that wasn’t so much of a concern any more. But I still had a mess. I’d long since written git status off as unusable.

Until this past month, when I sat down and just started powering through the mess. One by one, I fixed the serious breakages that the component refactor had caused. I dedicated a day or two just to figuring out water physics, put a little more thought into it, and ended up with something that looks and plays quite nicely. I finished redrawing basic Lexy, and even added frames I hadn’t had before.

I think the difference was… fear. I’d previously hesitated so much, both in the art and the gnarlier code. It was such a struggle to get something working at all that changing it in any way was terrifying — what if I broke it and couldn’t even get it back to how it’d been?

I don’t know how to describe exactly how this felt, and I also don’t know how to explain what changed. It was like a switch flipped. I think it started when I drew new dirt tiles, and it didn’t even take that long, and I loved them. I’ve always had a hard time drawing terrain, and for once I just sat down and did it and it came out well and it looked like mine, like my style, which was a thing I hadn’t even really grasped I have before. After that I just cranked out a mountain of new sprite art, faster and better than anything I’d done before. Like I’d been accumulating XP over the past few years and just now decided to spend it all on levelling up.

Over the past six weeks, I have:

  • Redesigned the terrain
  • Vastly improved the palette
  • Completely finished redrawing Lexy
  • Redesigned the HUD
  • Mocked up a new dialogue layout
  • Drawn a new font
  • Drawn and implemented new consistent level entrances
  • Animated a treasure chest opening cutscene
  • Animated getting a key
  • Added a completely new tally at the end of a level
  • Added transitions for entering and leaving levels
  • Added swimming behavior
  • Redrawn the old gecko as a much more visible bananalizard
  • Animated the hearts and several other pickups
  • Ported the original forest levels to use all the new stuff
  • I don’t even know there has been just so much

Just look at the style evolution! God damn.

Three versions of Lexy in dirt tiles; over time, the style becomes more colorful and relies on stronger shapes and silhouettes

Here’s that same level from above:

Slime Lexy once again passing freely through the fence, but using newer assets

A lot of the last few weeks went towards level transitions, which previously… kind of worked. They were always a hasty jam hack that I never liked; there was a quick screen fade when going through a door, there was barely any notion of being “in a level” vs not, and the game even counted the fucking hearts in a level on the fly the first time you entered it. It was all very silly.

But now (please pardon the occasional frame drops from my screen recorder):

GIF of Lexy entering a level with a transition, collecting candy, exiting with another transition, and seeing the level tally

I finally feel like I’m making some real progress. I finally feel like this could be something I take seriously, that it could be a real game, something more than half an hour long. At some point it just became an absolute joy to look at and run around in.

The idea

The basic concept is the same, but I want to add some structure to it. The jam game was four single-room levels you could tackle in any order without much guidance, then another set of the same. Which is fine, but doesn’t give me much wiggle room in the design.

In the full game, levels will contain not just hearts, but also a treasure (a la Wario Land 3), some amount of candy (usable at the shop to buy things of some description), and an explicit exit. The overworld will function a bit more like a world map, and though you’ll still need to collect N hearts to get to the next zone, there may sometimes be obstacles that can only be overcome by finding the right treasure in a level.

I also intend to give Lexy some active abilities, for example this blown kiss (recorded with older art) that can toggle pink objects between two states:

Lexy blows a kiss towards a pink brick wall, which changes it into a pink grating

I even have a plot in mind! The jam game had only a teeny tiny one.

The future

Ash is currently busy with their own game, so I think this is gonna be The Thing I Do for a while. To that end, I’m in the middle of setting up some infrastructure:

Also, I recently created a secret Discord channel on the same server, where I intend to do planning and design work that I’m not ready to make public yet! Spoilers will abound, but if you’re interested and okay with that, you can get in by pledging at least $4 on Patreon and letting me know to give you the role. (I don’t use Patreon’s native Discord integration because it does rude things like forcibly rejoin you to the server even if you manually leave.)

Specific priorities

I’d like to finish porting the old levels over to new artwork, the new level infrastructure, etc. It’d make for a nice little Patreon demo or something, it gives me a milestone with pretty clear goals, and it’ll leave me with at least a small palette of puzzle elements that I know work correctly.

I’d like to write about what I’m doing sometimes on this dang blog. I’ve found that structured writing is really, really, really hard when my head is a mess, and it has been extremely a mess for the last two and a half years (sorry), but jotting down what I’m already doing should be much easier than the more elaborate posts I’ve written, which need research and tooling and whatnot.

I have a good handful of puzzle elements — some of which even work — and a bunch of ideas for more, but I haven’t actually tried building levels since I made the original game! That’s kind of the important part, so I’d love to do some of it now that the dust is finally settling.

I still have some design decisions to make, though they’re getting trickier since I’ve already decided all the easy stuff. But I’ll save that for the generous folks who give me four dollars, I guess.

The elephant in the room

So. As I mentioned at the beginning, this game was originally made for a “horny” game jam. Given that it’s mostly platforming, you might be wondering why that is. I already feel like I’m crossing the streams somehow by even mentioning this on this blog, so I’ll try very hard not to get TMI here.

I have a foot in “TF” (transformation) kink circles, and one thing that’s always struck me about that subculture is how much of it is completely non-sexual. You can find no end of artwork of, say, someone being turned into one of those inflatable pooltoys — where both the artist and the audience are obviously having a good time with it — yet with no hint of sexual elements whatsoever. It’s a form of sexuality that doesn’t need to be sexual at all.

I started Strawberry Jam because I wanted to see some adult games that were more creative with their gameplay. Much of the genre consists of otherwise regular games that occasionally show you some explicit artwork, and while that’s a perfectly fine way to design a game, I felt that the medium surely had more potential. It turns out that a non-sexual fantasy kink works wonders as a gameplay element; rather than just giving you a picture, the game takes a concept and has you experience it yourself, even figure out by experimentation how it’s altered the way you interact with the world.

This puts me in a slightly awkward position. I do, genuinely and platonically, love these kinds of gameplay themes! I adore changes in how you perceive or interact with a world — the dark world in Metroid Prime 2, the time reversal in Braid, the “dimension” swapping in Quantum Conundrum, etc. I think this is a great concept that anyone can have a good time with, and I feel like this game is a love letter to the Wario Land series.

At the same time, I do also appreciate the kink inspiration. Even Lexy’s collar was originally conceived as a gimmick I could use for drawing adult artwork. The jam game contains a lot of suggestive dialogue, since Lexy herself also appreciates the kink aspect. And that was a lot of fun to write, and I’m sure it enhanced the experience for other folks with similar leanings.

But this is such a good concept that I want it to be playable as just a regular puzzle-platformer as well. I think it would have fairly broad appeal, and I don’t want to hamstring myself by totally fucking weirding people out when it dawns on them that “oh the dev is kinda Into This huh”. And yet I don’t want to completely sterilize the game, either, because… well, ultimately, it’s my game and I like the suggestive parts.

This is a tough line to draw, and I’m not yet sure how to do it. I’ve considered just making alternative dialogue that you can opt into when you start the game, but given that Lexy already speaks differently depending on what form she’s in, I have no idea how feasible that is.

I don’t know how to gauge this. I’ve always been up to my armpits in the side of the internet that just posts porn and talks about sexuality casually, whereas I’m dimly aware that most people see sexuality as this completely distinct part of life that you hide in a small box, far away from the eyes of polite society. But maybe I’m overestimating that? Does anyone actually care if the protagonist of a game comments “hey this is hot” about something weird but innocuous?

Or maybe that’s exactly where the line is. I remember Nier: Automata, a game that is all too happy to show off the protagonist’s immaculately-rendered ass, which is clearly meant for the enjoyment of both the creator and the players. But nobody comments on it within the game, which makes it seem incidental, somehow. I can’t explain why that is, and it feels slightly dishonest to me.

Am I overthinking this? If you’re not involved in any kind of kink circles and played the original jam game, I’m curious to hear how it read to you. Was it at all uncomfortable, like perhaps the game was expecting you to heavily empathize with a feeling you don’t share at all? Or does putting that feeling on a character, rather than aiming it at the human player, make it something you can easily shrug off? The full game will have more stuff going on, so there should be lots more dialogue that isn’t solely about Lexy’s feelings, if that helps.


Hm, I thought I would have more to say here! I have a lot of ideas, but only a handful of them are implemented yet, and I guess it’s hard to show what a game will be like before most of it works.

I hope this is enough to whet some appetites, at least! I haven’t been excited like this about anything in far too long.

fox flux, three years later

Post Syndicated from Eevee original https://eev.ee/blog/2020/08/04/fox-flux-three-years-later/

I’m working on a video game! Like, a serious one.

The past

I wrote the original game (very slightly NSFW) for my own “horny” game jam, Strawberry Jam (more likely to be NSFW), way back in February 2017.

You play as Lexy, my shameless Floraverse self-insert, who owns an enchanted collar that (among other things) makes her basically indestructible and allows her to easy to transform into… whatever, given some kind of sensible trigger. And then you do some puzzle-platforming to collect “strawberry hearts” and gain access to new areas, much of which (surprise!) involves getting turned into things.

For example, this chain-link fence blocks you:

Screenshot of the player being stuck on one side of a fence

But if you let that green blob in the grass turn you into slime, you can walk right through it.

Screenshot of the same area, but the player is now green slime and free to pass through the fence

There are also spikes, which you get stuck on if you land on them… but slime can walk right through them, glass can stand on top of them, and stone outright destroys them. And so on. As a jam game, it’s not very expansive, but many of the puzzle elements interact differently with many of the handful of Lexy variants, which provided enough potential to make eight levels.

Post-jam

The jam game was rough, but I really liked the concept and wanted to expand on it. I spent a good chunk of the summer of 2017 on it, but it was a struggle. I was still fairly new to pretty much every aspect of actually creating a game — I’d only been drawing for two years, I’d sometimes hit big gaps in the design with no idea how to fill them, and I wasn’t yet entirely comfortable with complex physics or shaders. The art in particular was a huge problem; it took me a long time to produce sprites that I was only passably happy with. My spouse Ash is an artist, and we’ve made several games together where they produced all the art, but this was my idea and I was determined to draw it myself.

Then 2018 hit, which was a whole entire mess, and I didn’t really touch fox flux at all for over a year. I made a couple of other games with Ash, some finished, some not, and kept drawing intermittently.

I returned to fox flux for the middle of 2019, and decided… I’m not sure what I decided, exactly. I guess I’d gotten better at all the things that had been difficult for me before, so I set about trying to improve every aspect of the game at once.

  • I realized the (many, many) improved sprites I’d drawn in 2017 were not actually very good, and drew a new Lexy design from scratch that absolutely blew me away… which meant throwing away all the existing art.

  • I’d come up with a few new things for Lexy to turn into, each of which altered her behavior pretty significantly, and her code was becoming a spaghetti disaster. So I spent some time completely refactoring actors into bags of components, which I was unsure about until very recently and which ended up breaking pretty much every single object in the game, sometimes in subtle ways.

  • I decided to add water, which unraveled into a whole pile of decisions and problems.

  • I tried to make consistent or interesting physics for pushing things (e.g. wooden crates), and that became a nightmare. I easily spent weeks on this, trapped in a cycle of finding some edge case that couldn’t be fixed without considerably expanding what I was simulating, struggling to do that expansion while keeping all the basic stuff working, and then finding a new and different edge case.

Did I mention that I tried to do all of these things at the same time, while also trying to nail down the design of a game that’s naturally prone to a combinatoric explosion of interactions?

At a certain point it just felt hopeless. I’d poured easily over a year into this game, and all I had to show for it was a jumbled pile of stuff that didn’t work, strewn about a couple test maps that didn’t even contain any puzzles.

The present

I don’t know what happened, exactly. I’d given up on the heavily-simulated push physics last year, at least, so that wasn’t so much of a concern any more. But I still had a mess. I’d long since written git status off as unusable.

Until this past month, when I sat down and just started powering through the mess. One by one, I fixed the serious breakages that the component refactor had caused. I dedicated a day or two just to figuring out water physics, put a little more thought into it, and ended up with something that looks and plays quite nicely. I finished redrawing basic Lexy, and even added frames I hadn’t had before.

I think the difference was… fear. I’d previously hesitated so much, both in the art and the gnarlier code. It was such a struggle to get something working at all that changing it in any way was terrifying — what if I broke it and couldn’t even get it back to how it’d been?

I don’t know how to describe exactly how this felt, and I also don’t know how to explain what changed. It was like a switch flipped. I think it started when I drew new dirt tiles, and it didn’t even take that long, and I loved them. I’ve always had a hard time drawing terrain, and for once I just sat down and did it and it came out well and it looked like mine, like my style, which was a thing I hadn’t even really grasped I have before. After that I just cranked out a mountain of new sprite art, faster and better than anything I’d done before. Like I’d been accumulating XP over the past few years and just now decided to spend it all on levelling up.

Over the past six weeks, I have:

  • Redesigned the terrain
  • Vastly improved the palette
  • Completely finished redrawing Lexy
  • Redesigned the HUD
  • Mocked up a new dialogue layout
  • Drawn a new font
  • Drawn and implemented new consistent level entrances
  • Animated a treasure chest opening cutscene
  • Animated getting a key
  • Added a completely new tally at the end of a level
  • Added transitions for entering and leaving levels
  • Added swimming behavior
  • Redrawn the old gecko as a much more visible bananalizard
  • Animated the hearts and several other pickups
  • Ported the original forest levels to use all the new stuff
  • I don’t even know there has been just so much

Just look at the style evolution! God damn.

Three versions of Lexy in dirt tiles; over time, the style becomes more colorful and relies on stronger shapes and silhouettes

Here’s that same level from above:

Slime Lexy once again passing freely through the fence, but using newer assets

A lot of the last few weeks went towards level transitions, which previously… kind of worked. They were always a hasty jam hack that I never liked; there was a quick screen fade when going through a door, there was barely any notion of being “in a level” vs not, and the game even counted the fucking hearts in a level on the fly the first time you entered it. It was all very silly.

But now (please pardon the occasional frame drops from my screen recorder):

GIF of Lexy entering a level with a transition, collecting candy, exiting with another transition, and seeing the level tally

I finally feel like I’m making some real progress. I finally feel like this could be something I take seriously, that it could be a real game, something more than half an hour long. At some point it just became an absolute joy to look at and run around in.

The idea

The basic concept is the same, but I want to add some structure to it. The jam game was four single-room levels you could tackle in any order without much guidance, then another set of the same. Which is fine, but doesn’t give me much wiggle room in the design.

In the full game, levels will contain not just hearts, but also a treasure (a la Wario Land 3), some amount of candy (usable at the shop to buy things of some description), and an explicit exit. The overworld will function a bit more like a world map, and though you’ll still need to collect N hearts to get to the next zone, there may sometimes be obstacles that can only be overcome by finding the right treasure in a level.

I also intend to give Lexy some active abilities, for example this blown kiss (recorded with older art) that can toggle pink objects between two states:

Lexy blows a kiss towards a pink brick wall, which changes it into a pink grating

I even have a plot in mind! The jam game had only a teeny tiny one.

The future

Ash is currently busy with their own game, so I think this is gonna be The Thing I Do for a while. To that end, I’m in the middle of setting up some infrastructure:

Also, I recently created a secret Discord channel on the same server, where I intend to do planning and design work that I’m not ready to make public yet! Spoilers will abound, but if you’re interested and okay with that, you can get in by pledging at least $4 on Patreon and letting me know to give you the role. (I don’t use Patreon’s native Discord integration because it does rude things like forcibly rejoin you to the server even if you manually leave.)

Specific priorities

I’d like to finish porting the old levels over to new artwork, the new level infrastructure, etc. It’d make for a nice little Patreon demo or something, it gives me a milestone with pretty clear goals, and it’ll leave me with at least a small palette of puzzle elements that I know work correctly.

I’d like to write about what I’m doing sometimes on this dang blog. I’ve found that structured writing is really, really, really hard when my head is a mess, and it has been extremely a mess for the last two and a half years (sorry), but jotting down what I’m already doing should be much easier than the more elaborate posts I’ve written, which need research and tooling and whatnot.

I have a good handful of puzzle elements — some of which even work — and a bunch of ideas for more, but I haven’t actually tried building levels since I made the original game! That’s kind of the important part, so I’d love to do some of it now that the dust is finally settling.

I still have some design decisions to make, though they’re getting trickier since I’ve already decided all the easy stuff. But I’ll save that for the generous folks who give me four dollars, I guess.

The elephant in the room

So. As I mentioned at the beginning, this game was originally made for a “horny” game jam. Given that it’s mostly platforming, you might be wondering why that is. I already feel like I’m crossing the streams somehow by even mentioning this on this blog, so I’ll try very hard not to get TMI here.

I have a foot in “TF” (transformation) kink circles, and one thing that’s always struck me about that subculture is how much of it is completely non-sexual. You can find no end of artwork of, say, someone being turned into one of those inflatable pooltoys — where both the artist and the audience are obviously having a good time with it — yet with no hint of sexual elements whatsoever. It’s a form of sexuality that doesn’t need to be sexual at all.

I started Strawberry Jam because I wanted to see some adult games that were more creative with their gameplay. Much of the genre consists of otherwise regular games that occasionally show you some explicit artwork, and while that’s a perfectly fine way to design a game, I felt that the medium surely had more potential. It turns out that a non-sexual fantasy kink works wonders as a gameplay element; rather than just giving you a picture, the game takes a concept and has you experience it yourself, even figure out by experimentation how it’s altered the way you interact with the world.

This puts me in a slightly awkward position. I do, genuinely and platonically, love these kinds of gameplay themes! I adore changes in how you perceive or interact with a world — the dark world in Metroid Prime 2, the time reversal in Braid, the “dimension” swapping in Quantum Conundrum, etc. I think this is a great concept that anyone can have a good time with, and I feel like this game is a love letter to the Wario Land series.

At the same time, I do also appreciate the kink inspiration. Even Lexy’s collar was originally conceived as a gimmick I could use for drawing adult artwork. The jam game contains a lot of suggestive dialogue, since Lexy herself also appreciates the kink aspect. And that was a lot of fun to write, and I’m sure it enhanced the experience for other folks with similar leanings.

But this is such a good concept that I want it to be playable as just a regular puzzle-platformer as well. I think it would have fairly broad appeal, and I don’t want to hamstring myself by totally fucking weirding people out when it dawns on them that “oh the dev is kinda Into This huh”. And yet I don’t want to completely sterilize the game, either, because… well, ultimately, it’s my game and I like the suggestive parts.

This is a tough line to draw, and I’m not yet sure how to do it. I’ve considered just making alternative dialogue that you can opt into when you start the game, but given that Lexy already speaks differently depending on what form she’s in, I have no idea how feasible that is.

I don’t know how to gauge this. I’ve always been up to my armpits in the side of the internet that just posts porn and talks about sexuality casually, whereas I’m dimly aware that most people see sexuality as this completely distinct part of life that you hide in a small box, far away from the eyes of polite society. But maybe I’m overestimating that? Does anyone actually care if the protagonist of a game comments “hey this is hot” about something weird but innocuous?

Or maybe that’s exactly where the line is. I remember Nier: Automata, a game that is all too happy to show off the protagonist’s immaculately-rendered ass, which is clearly meant for the enjoyment of both the creator and the players. But nobody comments on it within the game, which makes it seem incidental, somehow. I can’t explain why that is, and it feels slightly dishonest to me.

Am I overthinking this? If you’re not involved in any kind of kink circles and played the original jam game, I’m curious to hear how it read to you. Was it at all uncomfortable, like perhaps the game was expecting you to heavily empathize with a feeling you don’t share at all? Or does putting that feeling on a character, rather than aiming it at the human player, make it something you can easily shrug off? The full game will have more stuff going on, so there should be lots more dialogue that isn’t solely about Lexy’s feelings, if that helps.


Hm, I thought I would have more to say here! I have a lot of ideas, but only a handful of them are implemented yet, and I guess it’s hard to show what a game will be like before most of it works.

I hope this is enough to whet some appetites, at least! I haven’t been excited like this about anything in far too long.

Rowling is dangerously wrong

Post Syndicated from Eevee original https://eev.ee/blog/2020/06/11/rowling-is-dangerously-wrong/

I read J.K. Rowling’s essay.

I regret doing so.

Here are some thoughts. Trans readers, brace yourselves, especially if you didn’t read the original.

Some help came from Andrew James Carter’s response thread, which has many more citations but feels less compelling to a general audience to me.


This isn’t an easy piece to write, for reasons that will shortly become clear, but I know it’s time to explain myself on an issue surrounded by toxicity. I write this without any desire to add to that toxicity.

I admire that. I, too, would prefer not to add to the toxicity.

For people who don’t know: last December I tweeted my support for Maya Forstater, a tax specialist who’d lost her job for what were deemed ‘transphobic’ tweets. She took her case to an employment tribunal, asking the judge to rule on whether a philosophical belief that sex is determined by biology is protected in law. Judge Tayler ruled that it wasn’t.

We are off to a poor start. Framing an unrenewed contract as “losing her job” is dubious. And specifically, Judge Tayler ruled that “she will refer to a person by the sex she considered appropriate even if it violates their dignity and/or creates an intimidating, hostile, degrading, humiliating or offensive environment” — that is, she would be actively and knowingly rude towards people in the workplace, and that is not protected.

(Forstater later disingenuously claimed to have lost her job for “speaking up about women’s rights”. And I’m just now learning that she compared the use of correct pronouns to the use of rohypnol — the date rape drug — while this court case was pending. Charming.)

All the time I’ve been researching and learning, accusations and threats from trans activists have been bubbling in my Twitter timeline. This was initially triggered by a ‘like’. When I started taking an interest in gender identity and transgender matters, I began screenshotting comments that interested me, as a way of reminding myself what I might want to research later. On one occasion, I absent-mindedly ‘liked’ instead of screenshotting. That single ‘like’ was deemed evidence of wrongthink, and a persistent low level of harassment began.

This sounds like a simple misunderstanding which could have been resolved with a single explanatory tweet. Instead, your spokesperson referred to it as a “clumsy and middle-aged moment”. And now you categorize the tweet vaguely as something to research — suggesting to a casual reader that you had merely liked a link to a scholarly article, perhaps — when it was a mundane personal rant which referred to trans women as “men in dresses”.

I have a hypothesis about where the toxicity began — right there, when you clicked the heart underneath it. It’s something you know is mean and hurtful to the people it describes, and is intended to be so, and you not only defend it but cloak it in an obligatory 1984 reference. This is deceptive, mean-spirited, and shameful.

We are only on paragraph four.

Months later, I compounded my accidental ‘like’ crime by following Magdalen Burns on Twitter. Magdalen was an immensely brave young feminist and lesbian who was dying of an aggressive brain tumour. I followed her because I wanted to contact her directly, which I succeeded in doing. However, as Magdalen was a great believer in the importance of biological sex, and didn’t believe lesbians should be called bigots for not dating trans women with penises, dots were joined in the heads of twitter trans activists, and the level of social media abuse increased.

You are fucking blackface actors. You aren’t women. You’re men who get sexual kicks from being treated like women. fuck you and your dirty fucking perversions. our oppression isn’t a fetish you pathetic, sick, fuck.”

That’s what Magdalen Berns, whose name you misspelled, had to say about trans women. (Ironically, it’s not too far off from what folks used to say — and occasionally still do — about gay folks.) I’m going to hazard a guess that this was more of a concern than any discourse about who lesbians choose to date.

The funny thing is, while I’ve seen the “gender critical” crowd complain numerous times that trans women are somehow trying to force cis lesbians to have sex with them (by tweeting about it?), I’ve virtually never witnessed the phenomenon directly — and I am neck-deep in trans Twitter. Perhaps two or three times over the years, I’ve seen some discourse about “genital attraction” and whether it’s socially influenced, which I suppose is an interesting question. On one singular occasion, such a tweet came uncomfortably close to suggesting that people were obligated to correct for what’s presumed to be social influence in who they’re attracted to, and I swiftly pushed back against it.

But the way “gender critical” folks talk about this, you’d think it was the only topic trans women ever discuss! Meanwhile, do you know who most trans women I know are dating? Each other!

I mention all this only to explain that I knew perfectly well what was going to happen when I supported Maya. I must have been on my fourth or fifth cancellation by then.

I expected the threats of violence, to be told I was literally killing trans people with my hate, to be called cunt and bitch and, of course, for my books to be burned, although one particularly abusive man told me he’d composted them.

I am genuinely sorry that people are abusive on Twitter, but I don’t know how to avoid it when you have more followers than the populations of NYC and LA combined. It’s a much broader problem, though definitely exacerbated when you support someone who has been fighting for the right to be deliberately hostile.

I’m not sure what to make of the last part. Is composting a book worse than burning it? And are you hinting a comparison between burning one’s own personal property and the actions of Nazi Germany, or am I reading too much into this conspicuous phrasing? I hope the latter, because the former would be extremely tasteless, considering that part of what was burned was the research and library of a sex research institute which was founded by the man who coined the term “transsexualism” and had trans people as both staff and clients.

What I didn’t expect in the aftermath of my cancellation was the avalanche of emails and letters that came showering down upon me, the overwhelming majority of which were positive, grateful and supportive. They came from a cross-section of kind, empathetic and intelligent people, some of them working in fields dealing with gender dysphoria and trans people, who’re all deeply concerned about the way a socio-political concept is influencing politics, medical practice and safeguarding. They’re worried about the dangers to young people, gay people and about the erosion of women’s and girl’s [sic] rights. Above all, they’re worried about a climate of fear that serves nobody – least of all trans youth – well.

I note, conspicuously, that zero of them were from trans people, or you surely would’ve mentioned as much. You give trans youth a token mention at the end, but only as an object of external concern, not as people to be listened to and trusted about their own experiences. This is a theme that I see we’ll be revisiting.

I’d stepped back from Twitter for many months both before and after tweeting support for Maya, because I knew it was doing nothing good for my mental health. I only returned because I wanted to share a free children’s book during the pandemic. Immediately, activists who clearly believe themselves to be good, kind and progressive people swarmed back into my timeline, assuming a right to police my speech, accuse me of hatred, call me misogynistic slurs and, above all – as every woman involved in this debate will know – TERF.

I note for the audience that the “gender critical” crowd — you know, TERFs — love to use the term TRA (trans rights activist) to refer to pretty much any trans person who doesn’t buy what they’re selling. I don’t know if this is meant to be a dogwhistle, but it at least quacks like one.

More generally, “activists” is a favored scare word across the political spectrum, much like “ideology” — it conjures the image of someone who is angrily trying to push Politics on you, while neatly obscuring that the political view they’re trying to push is “please don’t be cruel to me or people like me”. Are you, Rowling, not an activist? What about the people you support, like Berns? You use “activist” ten times in this essay, and every single time to describe trans people.

It’s rhetorical sleight of hand. Trans people who want to live their lives without being called blackface actors are “activists”, while the people making those comments are merely expressing concerns. Telling people what they should be able to wear earns no mention in this essay at all, but replying on a public platform to tell you that you are being hurtful is “policing your speech”.

Do you know where I first learned about this trick? From people who opposed the gay rights movement. “Gay rights activist” was a phrase I saw bandied about a lot while I was growing up, as though wanting to be able to marry one’s partner instantly transformed a person into some sort of unreasonable lobbyist, while opposing it was just the normal and natural thing to do. Frequently they’d have one gay person who agreed with them to put on a pedestal, the proof that they didn’t actually hate gay people — at least not the ones who’d sit down and shut up and accept whatever scraps they were given.

If you didn’t already know – and why should you? – ‘TERF’ is an acronym coined by trans activists, which stands for Trans-Exclusionary Radical Feminist. In practice, a huge and diverse cross-section of women are currently being called TERFs and the vast majority have never been radical feminists. Examples of so-called TERFs range from the mother of a gay child who was afraid their child wanted to transition to escape homophobic bullying, to a hitherto totally unfeminist older lady who’s vowed never to visit Marks & Spencer again because they’re allowing any man who says they identify as a woman into the women’s changing rooms.

As any best-selling author would know, if a word is used incorrectly at least two times on Twitter, it loses all meaning.

From what I’ve observed, the vast majority of people referred to as TERFs are people who claim an interest in the well-being of women and lesbians, but exclude trans women from that (or outright classify them all as predators), treat trans men as confused women, speak over or outright ignore the people they claim to be defending, and spend an awful lot of time inventing or vastly exacerbating “concerns” about trans people so as to excuse spending an awful lot of the rest of their time saying incredibly nasty things.

Ironically, radical feminists aren’t even trans-exclusionary – they include trans men in their feminism, because they were born women.

This is trans-exclusionary. It’s feminism that ignores and talks over trans men, which is a strange thing for feminists to do to people they consider to be women.

But accusations of TERFery have been sufficient to intimidate many people, institutions and organisations I once admired, who’re cowering before the tactics of the playground. ‘They’ll call us transphobic!’ ‘They’ll say I hate trans people!’ What next, they’ll say you’ve got fleas?

Not wanting to come across as hating a group of people is generally considered polite. Imagine saying this about, I don’t know, lesbians.

Speaking as a biological woman, a lot of people in positions of power really need to grow a pair (which is doubtless literally possible, according to the kind of people who argue that clownfish prove humans aren’t a dimorphic species).

Is “courage is stored in the balls” feminist now?

But since you bring up dimorphism, here’s a fun anecdote that’s relevant to my field. It seems that one of the biggest factors a neural network (“AI”) uses to determine a person’s gender is… hair length! Which isn’t a dimorphic trait, at least not how you’d think. The sexes are not really all that distinct; much of it is decoration we put on ourselves to exacerbate the differences, for some reason.

For some more anecdotes, feel free to look for reports of cis lesbians being kicked out of public women’s restrooms for looking too masculine. Like this one, or this one, or this one, or this one. Whose activism do you suppose would exacerbate this?

Firstly, I have a charitable trust that focuses on alleviating social deprivation in Scotland, with a particular emphasis on women and children. Among other things, my trust supports projects for female prisoners and for survivors of domestic and sexual abuse. I also fund medical research into MS, a disease that behaves very differently in men and women. It’s been clear to me for a while that the new trans activism is having (or is likely to have, if all its demands are met) a significant impact on many of the causes I support, because it’s pushing to erode the legal definition of sex and replace it with gender.

What a perfect example. What does it mean for MS to behave very differently in men and women? “Man” versus “woman” isn’t a switch you flip; it’s a combination of dozens of factors. If the difference is caused by hormone levels — which looks plausible — then trans women on HRT will be affected similarly to cis women, because they have the same levels of estrogen! And by excluding them — by insisting we talk only about “biological” “men” and “women” rather than specific biological factors — you are miscategorizing them for no reason.

The second reason is that I’m an ex-teacher and the founder of a children’s charity, which gives me an interest in both education and safeguarding. Like many others, I have deep concerns about the effect the trans rights movement is having on both.

Ah, you mean Lumos, the charity you cofounded with Baroness Emma Nicholson, who just yesterday said that gay marriage is degrading women’s rights after attempting to repeal it in 2013? I have some deep concerns about the effect this person will have on the well-being of gay teens — and she’s not a mere “activist” or “movement”, but a lawmaker! Strange company you keep. And that’s not even getting into how she called it pedophilia for a trans charity’s website to have an escape button on it in case of abusive parents, a mere week and a half ago.

The third is that, as a much-banned author, I’m interested in freedom of speech and have publicly defended it, even unto Donald Trump.

Much-banned”? You wrote one of the best-selling books of all time and the best-selling series of all time. You have sold at least one book for every fourteen humans alive and made almost a dozen movie deals. When you tweet, it trends for days and makes national headlines. Your freedom of speech is not at risk here — and if it were, you could probably afford to inscribe whatever you wanted to say on the face of the moon.

The fourth is where things start to get truly personal. I’m concerned about the huge explosion in young women [sic] wishing to transition and also about the increasing numbers who seem to be detransitioning (returning to their original sex), because they regret taking steps that have, in some cases, altered their bodies irrevocably, and taken away their fertility. Some say they decided to transition after realising they were same-sex attracted, and that transitioning was partly driven by homophobia, either in society or in their families.

Yes, it’s truly tragic that homophobia is still rampant, such as in the baroness you cofounded a charity with. Especially in parents. Incidentally, the most common reason given for detransitioning — which is pressure from a parent (36%, see page 108); the next is harassment/discrimination (31%), followed by having trouble getting a job (29%). Most of the other reasons given were pressure from some other external source. Only 0.4% of the people in that survey reported detransitioning because they simply did not like transition. And, by the way, detransition (even temporarily) is several times more common in trans women than trans men.

If you really want to fight detransition, the most effective action you could take would be to delete this post. But you’re approaching this from the perspective that trans men are confused, just like swaths of homophobic parents have said of their gay children.

Most people probably aren’t aware – I certainly wasn’t, until I started researching this issue properly – that ten years ago, the majority of people wanting to transition to the opposite sex were male. That ratio has now reversed. The UK has experienced a 4400% increase in girls [sic] being referred for transitioning treatment. Autistic girls [sic] are hugely overrepresented in their numbers.

Of course they are. Trans people are disproportionately autistic, so this is to be expected. I’d think this would be cause for celebration — people are being treated who previously wouldn’t have been! That’s excellent progress.

But instead of celebrating it, you suggest here that autistic trans boys are being taken advantage of. No, worse; you suggest that autistic trans boys are incapable of making decisions about their own lives, and don’t even respect them enough to refer to them as they wish to be referred to. You speak over them, dismiss them as obviously wrong out of hand, and ignore how they wish to be referred to while pretending to care about their well-being. This is deeply condescending and appalling.

As an aside, it’s quite frustrating that you so frequently refuse to connect the dots — instead you leave a trail of breadcrumbs and let some haunting conclusion form in the reader’s head, while retaining plausible deniability for yourself because you never actually said the things you’re trying to imply. That leaves you free to claim that a response like this one, which spells out the winks and nods, is yet more dismissable harassment.

The same phenomenon has been seen in the US. In 2018, American physician and researcher Lisa Littman set out to explore it. In an interview, she said:

‘Parents online were describing a very unusual pattern of transgender-identification where multiple friends and even entire friend groups became transgender-identified at the same time. I would have been remiss had I not considered social contagion and peer influences as potential factors.’

Littman mentioned Tumblr, Reddit, Instagram and YouTube as contributing factors to Rapid Onset Gender Dysphoria, where she believes that in the realm of transgender identification ‘youth have created particularly insular echo chambers.’

Her paper caused a furore. She was accused of bias and of spreading misinformation about transgender people, subjected to a tsunami of abuse and a concerted campaign to discredit both her and her work. The journal took the paper offline and re-reviewed it before republishing it.

This is probably because “rapid-onset gender dysphoria” is not a real phenomenon. The critical flaw in the idea is so blatantly obvious that you’ve very nearly spelled it out yourself: parents described an “unusual” pattern of behavior. Not the children themselves, not psychologists, not therapists. Parents. Parents who are upset that their children are coming out as trans, who are searching for some external factor to blame so they can rest assured that their children have simply been taken advantage of by some nefarious force.

I remember this all quite well from the 90s, except then it was about homosexuality. (A pattern begins to emerge.) There were no signs!, cry parents who punished their children for ever showing any signs, thus swiftly teaching them to put on a good act. It must be the media. It must be the evil other gays somehow influencing my poor child, who otherwise would be straight, like I want them to be.

The only difference is that this time it’s been given an acronym to lend it some veneer of credibility. But it’s not a clinical diagnosis; it’s a study of the feelings of parents who were caught off guard and are searching for an explanation other than “my child is trans”. Even the paper itself has a preface saying the term “should not be used in a way to imply that it explains the experiences of all gender dysphoric youth”.

There’s no mystery to be solved here, anyway. Talk to a single queer person (who isn’t isolated due to factors beyond their control) and I’ll bet you they have disproportionately many queer friends. People who are alike tend to clump together, especially if they sense that society at large is uncomfortable with them. All that’s been observed here is that trans teenagers form friend groups, and when one of them comes out, the others feel confident enough to come out as well. And their parents don’t like it, because of a culture that includes essays like this from household names with massive platforms.

However, her career took a similar hit to that suffered by Maya Forstater. Lisa Littman had dared challenge one of the central tenets of trans activism, which is that a person’s gender identity is innate, like sexual orientation. Nobody, the activists insisted, could ever be persuaded into being trans.

I remember this from the 90s, too. I remember the argument having to be made that sexual orientation is fixed and absolute and predetermined — because, regardless of how true or universal that may or may not be, the alternative is to leave the door open for parents and communities to try to “fix” gay children and ostracize the gay adults who had “persuaded” them into being gay.

Here we go again, except the “fix” for trans youth is to merely tell them to knock it off because they’re mistaken and leave it at that.

The argument of many current trans activists is that if you don’t let a gender dysphoric teenager transition, they will kill themselves. In an article explaining why he resigned from the Tavistock (an NHS gender clinic in England) psychiatrist Marcus Evans stated that claims that children will kill themselves if not permitted to transition do not ‘align substantially with any robust data or studies in this area. Nor do they align with the cases I have encountered over decades as a psychotherapist.’

They won’t necessarily kill themselves, but you could throw a rock and hit a study telling you that trans folks have a shockingly high rate of suicide attempts, and the absolute number one factor that drops that rate precipitously is transition. Or you could talk to a trans person and see if they have a friend who attempted/committed suicide because they were unable to transition (yes). Or at the very least, maybe cite someone who didn’t resign.

What a shockingly insensitive thing to say.

The writings of young trans men reveal a group of notably sensitive and clever people. The more of their accounts of gender dysphoria I’ve read, with their insightful descriptions of anxiety, dissociation, eating disorders, self-harm and self-hatred, the more I’ve wondered whether, if I’d been born 30 years later, I too might have tried to transition. The allure of escaping womanhood would have been huge. I struggled with severe OCD as a teenager. If I’d found community and sympathy online that I couldn’t find in my immediate environment, I believe I could have been persuaded to turn myself into the son my father had openly said he’d have preferred.

You call them clever, but immediately turn around and suggest that they are somehow artificially trans, that they have been “persuaded” into it. Again, you express ostensible care but use it as a springboard to dismiss them and talk over them. And what of trans women, who are well aware of what womanhood entails but still prefer it? This is precisely what I mentioned as the common TERF rhetoric, and is why people are calling you one: you speak piteously of trans men while suggesting with every word that you know better than they do what’s good for them, while trans women are… well, who knows what that omission might imply?

When I read about the theory of gender identity, I remember how mentally sexless I felt in youth. I remember Colette’s description of herself as a ‘mental hermaphrodite’ and Simone de Beauvoir’s words: ‘It is perfectly natural for the future woman to feel indignant at the limitations posed upon her by her sex. The real question is not why she should reject them: the problem is rather to understand why she accepts them.’

As I didn’t have a realistic possibility of becoming a man back in the 1980s, it had to be books and music that got me through both my mental health issues and the sexualised scrutiny and judgement that sets so many girls to war against their bodies in their teens. Fortunately for me, I found my own sense of otherness, and my ambivalence about being a woman, reflected in the work of female writers and musicians who reassured me that, in spite of everything a sexist world tries to throw at the female-bodied, it’s fine not to feel pink, frilly and compliant inside your own head; it’s OK to feel confused, dark, both sexual and non-sexual, unsure of what or who you are.

At last, you spell it out. But trans men are not confused and don’t need you to save them.

I want to be very clear here: I know transition will be a solution for some gender dysphoric people, although I’m also aware through extensive research that studies have consistently shown that between 60-90% of gender dysphoric teens will grow out of their dysphoria.

Flat-out incorrect. I assume you’re referring to research that the bulk (“65 to 94 percent”) of dysphoric prepubescent children will “grow out of it” — but if it persists beyond puberty (i.e., into their teens), it’s most likely permanent.

Again and again I’ve been told to ‘just meet some trans people.’ I have: in addition to a few younger people, who were all adorable, I happen to know a self-described transsexual woman who’s older than I am and wonderful. Although she’s open about her past as a gay man, I’ve always found it hard to think of her as anything other than a woman, and I believe (and certainly hope) she’s completely happy to have transitioned.

Describing them as “adorable” does not fill me with confidence that you listened to anything they had to say, especially in light of your repeated attempts to cast trans boys as confused or misled.

I’m glad you have 1 trans friend, whose viewpoint or input you manage to not actually mention whatsoever before using her as a foothold to make another “concerned” point:

Being older, though, she went through a long and rigorous process of evaluation, psychotherapy and staged transformation. The current explosion of trans activism is urging a removal of almost all the robust systems through which candidates for sex reassignment were once required to pass.

If you would “just meet some trans people”, you would know that the long and rigorous process is torture. Quite regularly I see tweets — from folks in the UK especially — about having to wait for up to a year or more just to see a gender therapist once, after which they have to wait even longer to even begin hormones. In the US, I’ve read no end of anecdotes from people who have to perform the right “kind” of transness to convince a therapist to write them a referral letter, after who knows how many sessions. And this is, quite often, after years of internal debate and questioning. Years and years of their lives lost forever.

All of this is predicated, once again, on the idea that trans people just don’t know what’s good for themselves.

A man [sic] who intends to have no surgery and take no hormones may now secure himself [sic] a Gender Recognition Certificate and be a woman in the sight of the law. Many people aren’t aware of this.

She would need a formal diagnosis and to have lived as a woman for at least two years. At least as written, a cis man cannot simply show up and get an F stamped on his passport. I don’t even know what possible purpose that would serve.

We’re living through the most misogynistic period I’ve experienced. Back in the 80s, I imagined that my future daughters, should I have any, would have it far better than I ever did, but between the backlash against feminism and a porn-saturated online culture, I believe things have got significantly worse for girls. Never have I seen women denigrated and dehumanised to the extent they are now. From the leader of the free world’s long history of sexual assault accusations and his proud boast of ‘grabbing them by the pussy’, to the incel (‘involuntarily celibate’) movement that rages against women who won’t give them sex, to the trans activists who declare that TERFs need punching and re-educating, men across the political spectrum seem to agree: women are asking for trouble. Everywhere, women are being told to shut up and sit down, or else.

I cannot believe you are comparing sexual assault and incels — who have committed mass shootings! — to angry trans people tweeting anime screenshots captioned “shut up” at you. “TERF” doesn’t even imply a woman — the most infamous one by far is a man, Graham Lineham!

Meanwhile, you have — multiple times in this essay — suggested that trans boys are misled and the choices they’ve made for themselves are somehow mistakes. I know you consider them women, because your exact phrasing was to call them “girls [sic] being referred for transitioning treatment” and then reframe their choices as actually being about misogyny. What kind of feminism is it to decide you know better than people you think are women? Not even decide, but take for granted, speak about as though their agency never existed to be dismissed in the first place?

I’ve read all the arguments about femaleness not residing in the sexed body, and the assertions that biological women don’t have common experiences, and I find them, too, deeply misogynistic and regressive. It’s also clear that one of the objectives of denying the importance of sex is to erode what some seem to see as the cruelly segregationist idea of women having their own biological realities or – just as threatening – unifying realities that make them a cohesive political class. The hundreds of emails I’ve received in the last few days prove this erosion concerns many others just as much. It isn’t enough for women to be trans allies. Women must accept and admit that there is no material difference between trans women and themselves.

Who has said that cis women don’t have common biological experiences? The issue is that most trans men and some nonbinary folks also have those experiences (and some cis women don’t), so if you’re going to talk about them, why not talk about the experience instead of saying “women” and presuming that everyone will intuit which of a dozen possible facets of womanhood you’re referring to?

And if the experience in question is a social one, based on other people’s perception of you as a woman, then guess what: loads of trans women will also have had those experiences.

But, as many women have said before me, ‘woman’ is not a costume. ‘Woman’ is not an idea in a man’s head. ‘Woman’ is not a pink brain, a liking for Jimmy Choos or any of the other sexist ideas now somehow touted as progressive.

The women saying those things, anecdotally, appear to have significant overlap with women who criticize trans women for not “looking” female enough. Or who, sadly, misidentify cis women as trans women for not “looking” female enough. You know, that refined classical sexism.

If trans women wear dresses, they’re treating womanhood as a costume; if they don’t, they’re faking it.

Moreover, the ‘inclusive’ language that calls female people ‘menstruators’ and ‘people with vulvas’ strikes many women as dehumanising and demeaning. I understand why trans activists consider this language to be appropriate and kind, but for those of us who’ve had degrading slurs spat at us by violent men, it’s not neutral, it’s hostile and alienating.

Clearly you don’t understand, as no one is blanket referring to “female people” as “menstruators”. The current kerfuffle started because you commented on an article titled “Creating a more equal post-COVID-19 world for people who menstruate”. It used that phrasing because it was about menstruation (and was written by three women). The only person in this whole mess who has tried to reduce women to their body parts is you, in your initial tweet, insisting that menstruation is a uniquely defining feature of womanhood.

Moreover, the article is about addressing a women’s health and women’s rights issue, and it mentions women frequently, but your only response was to criticize the title for trying to include the very people — trans men — that you keep trampling in this essay. I find your choice of priorities increasingly alarming.

If you could come inside my head and understand what I feel when I read about a trans woman dying at the hands of a violent man, you’d find solidarity and kinship. I have a visceral sense of the terror in which those trans women will have spent their last seconds on earth, because I too have known moments of blind fear when I realised that the only thing keeping me alive was the shaky self-restraint of my attacker.

I believe the majority of trans-identified people not only pose zero threat to others, but are vulnerable for all the reasons I’ve outlined. Trans people need and deserve protection. Like women, they’re most likely to be killed by sexual partners. Trans women who work in the sex industry, particularly trans women of colour, are at particular risk. Like every other domestic abuse and sexual assault survivor I know, I feel nothing but empathy and solidarity with trans women who’ve been abused by men.

So I want trans women to be safe. At the same time, I do not want to make natal girls and women less safe. When you throw open the doors of bathrooms and changing rooms to any man who believes or feels he’s a woman – and, as I’ve said, gender confirmation certificates may now be granted without any need for surgery or hormones – then you open the door to any and all men who wish to come inside. That is the simple truth.

I’m sorry for what you went through, but these few paragraphs horrify me. You understand and describe in vivid detail what some of these women go through, how their lives end, how at risk they are, and then immediately segue into how those women should not be given shelter — hell, not even just shelter, but a place to pee — because someone else might hypothetically abuse it.

I must be missing something, because this has never made sense to me. People who commit sexual assault are not especially interested in following the rules, so how is adding another rule meant to dissuade them from this contrived scheme? If someone is around to police who goes into the bathroom, why could that same person not instead intervene if someone tries to cause harm?

Anyway, what do you propose instead? You never say, which seems deeply at odds with your desire for trans women to be safe. The only alternative I ever hear involves checking identification and chromosomal analysis and all kinds of other absurdity — which is clearly aimed at trans folks and not nefarious men. Are you fine with the status quo, which is that trans people already use whatever bathroom they find most appropriate? Or do you think your trans woman friend should be forced into the men’s room, surrounded by men? Without saying one way or the other, you’re actively encouraging fear and hostility towards people who just want to pee — and not just towards trans people, but towards anyone who doesn’t “look female enough”.

On Saturday morning, I read that the Scottish government is proceeding with its controversial gender recognition plans, which will in effect mean that all a man needs to ‘become a woman’ is to say he’s one. To use a very contemporary word, I was ‘triggered’. Ground down by the relentless attacks from trans activists on social media, when I was only there to give children feedback about pictures they’d drawn for my book under lockdown, I spent much of Saturday in a very dark place inside my head, as memories of a serious sexual assault I suffered in my twenties recurred on a loop. That assault happened at a time and in a space where I was vulnerable, and a man capitalised on an opportunity. I couldn’t shut out those memories and I was finding it hard to contain my anger and disappointment about the way I believe my government is playing fast and loose with womens and girls’ safety.

Why did you take it out on the very people you just said you also want to be safe? Why did you take it out on an article that had little to do with safety and was pushing for better health and privacy? You’ve already said you know exactly how your actions will be perceived, so the backlash this time cannot have come as a surprise.

There was so much opportunity here for talking about cultural expectations and gender roles, how those foster and overlook violence and aggression from boys from a young age, how a lot of societal structures still suggest that men are “owed” something by women, or how violence is more broadly glorified in Western culture. As a world-renowned author who’s done extensive feminist research, you could surely make an impact.

Instead, you decided to hurt people.

Late on Saturday evening, scrolling through children’s pictures before I went to bed, I forgot the first rule of Twitter – never, ever expect a nuanced conversation – and reacted to what I felt was degrading language about women. I spoke up about the importance of sex and have been paying the price ever since. I was transphobic, I was a cunt, a bitch, a TERF, I deserved cancelling, punching and death. You are Voldemort said one person, clearly feeling this was the only language I’d understand.

You offered absolutely no nuance yourself, and this essay has carefully weaved around it the whole time as well. You, a straight person, co-opted the gay community’s struggle so you could wield it as a club against trans people — after tossing them Dumbledore as a token afterthought — despite having ties yourself to an MP who has actively tried to erode gay rights.

But yes, let us talk about Harry Potter and how it reflects your values. Zero non-heterosexual characters mentioned within the canon. But more of interest: where are the women? The main character, a boy; his mentor and the primary authority figure, a man; the teacher he’s at odds with, a man; the rival and entourage, all boys; his best friend, a boy; the awkward coward who gets a late redemption arc, a boy; the primary antagonist, a man; the sympathetic adult confidant, a man; the rediscovered long-lost family member, a man; the endlessly regenerating Defense Against the Dark Arts teachers, all men except for the cartoon villain Umbridge. The Weasleys have seven children; six are boys. Two of the Hogwarts founders are men, and two women… ah, but the men are the founders of the two plot-important houses. Vernon is clearly the head of the Dursley family, and their only child is a boy. On it goes.

Girls can aspire to be the nerd no one likes (hey, that’s me!), the insane woman no one believes, the abusive monster, the nurse with no personality, or one of a handful of love interests. McGonagall is extremely cool and can turn into a cat, I grant you. And I think there was someone named Bellatrix? But wasn’t she a Death Eater?

I don’t claim to be an expert on your series; on the contrary, I read them casually when they came out and haven’t revisited them since. This is the cast that left an impression on me. I have published half-hour video games with more female characters than I can name off the top of my head from the entire Harry Potter canon. Where was your concern for uplifting girls throughout the decade you spent writing the most popular book series in the history of the human race? Where was your interest in the well-being of gay teens as you dedicated untold pages to descriptions of wizard football?

I hope that’s enough nuance.

It would be so much easier to tweet the approved hashtags – because of course trans rights are human rights and of course trans lives matter – scoop up the woke cookies and bask in a virtue-signalling afterglow. There’s joy, relief and safety in conformity. As Simone de Beauvoir also wrote, “… without a doubt it is more comfortable to endure blind bondage than to work for one’s liberation; the dead, too, are better suited to the earth than the living.”

Virtue signalling” is not in itself a bad thing; it is literally the indication to others of what our values are, so others know what we believe and how we are likely to treat them. Your essay still signals your virtues, as does mine.

Of course” trans rights are human rights? I cannot even tell if this is meant to be serious or sarcastic, with how much seething resentment you’ve wrapped it in. Do you also consider your supposed support of lesbians to be “conformity”, since that’s no longer an especially controversial stance?

This is all outright reactionary rhetoric and you know it. You are using the very same catchphrases that the incels you so revile use when justifying their hatred for women.

Huge numbers of women are justifiably terrified by the trans activists; I know this because so many have got in touch with me to tell their stories. They’re afraid of doxxing, of losing their jobs or their livelihoods, and of violence.

Who is doxxing people? I tried to look into this and instead found a list of TERF websites with a prominent warning that they track and doxx and harass trans people; the Rational Wiki asserting that TERFs engage in doxxing; and this second-hand account that an ex-TERF was “threatened with doxing” by her own allies and “kept in a perpetual state of fear”.

And who on earth is sinking to violence over this? I find e.g. the “photo with a gun pointed at the viewer” phenomenon pretty distasteful, but it doesn’t seem to be unique to this issue, it’s not an especially credible threat of violence, and it’s the closest to actual violence I’ve ever heard of here. Surely, if anyone had come to blows, we’d never hear the end of it?

I note that Forstater’s contract wasn’t renewed because, as best as we can tell, she made her coworkers uncomfortable and the work environment hostile. Meanwhile, trans people can be (and are) fired for simply existing. Citing this as a fear people have of trans people, as though they were some large shadowy conspiracy, feels fairly tasteless.

But endlessly unpleasant as its constant targeting of me has been, I refuse to bow down to a movement that I believe is doing demonstrable harm in seeking to erode ‘woman’ as a political and biological class and offering cover to predators like few before it. I stand alongside the brave women and men, gay, straight and trans, who’re standing up for freedom of speech and thought, and for the rights and safety of some of the most vulnerable in our society: young gay kids, fragile teenagers, and women who’re reliant on and wish to retain their single sex spaces. Polls show those women are in the vast majority, and exclude only those privileged or lucky enough never to have come up against male violence or sexual assault, and who’ve never troubled to educate themselves on how prevalent it is.

By “young gay kids” and “fragile teenagers”, are you once again obliquely referring to young trans people who you take to be merely confused? What of their freedom of thought, of their right to decide who they are for themselves without seeing you use them as ammunition against other people like them? What impact do you think that will have on them, exactly?

Falling back on “freedom of speech” to defend one’s own hurtful speech is another reactionary talking point; when you cannot defend your speech on its own merits, you can only defend that it is not literally illegal to say.

What polls are you finding? 26% is not a vast majority, and it’s troubling that you proactively dismiss the women who disagree with you as aloof and uninformed. What kind of feminism is that?

The one thing that gives me hope is that the women who can protest and organise, are doing so, and they have some truly decent men and trans people alongside them. Political parties seeking to appease the loudest voices in this debate are ignoring women’s concerns at their peril. In the UK, women are reaching out to each other across party lines, concerned about the erosion of their hard-won rights and widespread intimidation. None of the gender critical women I’ve talked to hates trans people; on the contrary. Many of them became interested in this issue in the first place out of concern for trans youth, and they’re hugely sympathetic towards trans adults who simply want to live their lives, but who’re facing a backlash for a brand of activism they don’t endorse. The supreme irony is that the attempt to silence women with the word ‘TERF’ may have pushed more young women towards radical feminism than the movement’s seen in decades.

Absolute bullshit. You’ve consistently brushed off or spoken for women and trans men who disagree with you in this post alone, but frame your own stance as though it were shared by all women. Two women you’ve mentioned by name and made a point of supporting — Maya Forstater and Magdalen Berns — have said some astonishingly cruel things about trans people as blanket remarks, so I can only interpret their “non-hate” in the same way as people repeatedly told my younger self that they loved me but I would burn for all eternity if I kissed both boys and girls. If their “concern” for trans youth is anything like yours, then they’re only interested in trying to berate trans youth into not wanting to be trans any more — yet again, no different from how homophobia played out.

And, hang on, they’re hugely sympathetic towards trans adults who’re facing backlash? You must be joking. They — and you — ARE the backlash! What good is sympathy from the very people who are deliberately hurting you?

The last thing I want to say is this. I haven’t written this essay in the hope that anybody will get out a violin for me, not even a teeny-weeny one. I’m extraordinarily fortunate; I’m a survivor, certainly not a victim. I’ve only mentioned my past because, like every other human being on this planet, I have a complex backstory, which shapes my fears, my interests and my opinions. I never forget that inner complexity when I’m creating a fictional character and I certainly never forget it when it comes to trans people.

You’ve done so multiple times in this essay alone, and your heroes do it on a pretty consistent basis. What an insult to everyone who read this.

All I’m asking – all I want – is for similar empathy, similar understanding, to be extended to the many millions of women whose sole crime is wanting their concerns to be heard without receiving threats and abuse.

In the entirety of this essay, you didn’t even mention a single concrete concern. You did some vague fearmongering about how a cis man could get a piece of paper saying he’s a woman, and that’s all. Meanwhile, you managed to repeatedly misgender and patronize trans boys; paint trans adults as a nefarious political movement trying to “persuade” children; cite multiple people who’ve been fiercely nasty towards trans people as a whole, while avoiding mentioning what they actually did so you could frame them as innocent victims; invoke multiple homophobic and reactionary tropes with a quick coat of paint slapped on top; present “parents who wish their children were cis” as though it were a diagnosed phenomenon; and generally checked off every possible TERF talking point while smiling kindly the whole time.

You’re saying things you know are actively hurtful in the name of preventing a hypothetical harm that is so nebulous you can’t even describe it.

This sucks.

Star Anise Chronicles: Oh No Wheres Twig??

Post Syndicated from Eevee original https://eev.ee/release/2020/05/10/star-anise-chronicles-oh-no-wheres-twig/

Title and logo for the game

🔗 Play it on itch.io
🔗 Play it on the PICO-8 BBS (where you can also download the cart and view the source code)

(I originally drafted this just after publishing the game, but then decided to start a whole series about its development and wasn’t sure what to do with this! But it’s solid and serves a different purpose, so here it is.)

It’s been a while, but I made another PICO-8 game! It’s a little platformer with light puzzling, where you help Star Anise find his best friend Branch Commander Twig. It’s only half an hour long at worst, and it’s even playable on a phone!

This is the one-and-a-halfth entry in the Star Anise Chronicles series, which after several false starts, finally kicked off over Christmas with a… uh… interactive fiction game. Expect the series to continue with even more whiplash-inducing theme shifts.

More technical considerations will go in the “gamedev from scratch” series, but read on for some overall thoughts on the design. Both contain spoilers, of course, so I do urge you to play the game first.


The first attempt at a Star Anise game was two years ago, in early 2018. The idea was to make a Metroidvania where Star Anise had a bunch of guns that shot cat-themed projectiles, obtained a couple other cat-themed powers, and made a total mess of a serious plot happening in the background while he ran around collecting garbage.

After finishing up the Steam release of Cherry Kisses last month, we decided that our next game should be that one, which would now be Star Anise 2 (since i’d already released a Star Anise 1 some months ago). We have, uh, already altered these plans, but that’s the background.

I don’t really know why I started on this game. I guess there’s some element of stress to working on a project with someone, even if that someone is Ash (my spouse), and especially if I’m supposed to be driving it forward. I have to tell someone what to do, and then if I don’t like the result I have to ask them to fix it, and a lot of tiny design questions are out of my control anyway, and all of this is happening on someone else’s schedule, and I have to convey all the project state that’s in my head in a complicated non-verbal form, and… all of those things are a constant low-level source of stress.

So I guess we’d just finished a game that I’d designed, and it was looking like we were about to start a sizable project where I was the design lead again, and I wanted to make something I could finish by myself as an interlude.

And so I sat down with a teeny tiny tool to make a teeny tiny version of what I expected would be our next game.

Design

The basics were obvious: run, jump, land. I gave Star Anise little landing particles early on — they’re in the bigger prototype, I love landing puffs in general, and having them be stars adds so much silly personality.

I knew I wanted to have multiple abilities you collect, since that’s the heart of Metroidventures. I briefly considered giving Star Anise a gun, as in the prototype, but gave up on that pretty early. I would’ve had to sprite a gun, a projectile, a projectile explosion, enemies, enemy attacks, enemy death frames…

Don’t get me wrong; I have no problem with drawing all of that. The concern was that PICO-8 has a very limited amount of space for sprites — in the configuration I was using, 128 sprites of 8×8 pixels each. Star Anise himself takes up 9, even with some clever reuse for his walking animation. The star puff takes 4. The common world tile, plus versions for edges and corners, takes up 9. That’s 22 sprites already, more than 17% of the space I have, for absolutely nothing besides jumping around on solid ground. I would have to keep it simple.

That led me to the first two powers, both borrowed from the prototype:

  • AOWR starts conversation with NPCs and opens doors. I can’t really take any creative credit here, since these are both things Anise attempts to do with aowrs in real life.

  • Papping activates levers and knocks over glasses of liquid. Anise only does one of those in real life. (In the prototype, this is a gun — which shoots pawprint-shaped projectiles — but I’d already been thinking about making it a “melee” ability first.)

I adore both of these abilities. I think they both turn some common UI tropes on their heads. NPCs, doors, and levers are all things you usually interact with by pressing some generic “interact” button, but hitting a lever (and meowing at a door) adds some physicality to the action — you’re actually doing something, not just making it go.

And pressing A to talk to an NPC doesn’t really make any sense at all! Consider: almost universally, even in games where the player character speaks, pressing A to start a conversation leads off with the NPC talking. So what the hell did you actually do? What does pressing A represent actually doing that results in someone else casually starting a conversation with you, seemingly unprompted? I have no idea! It’s nonsense! But Anise meows at me all the time and I always respond to him, which is perfectly sensible.

The third power, telepawt, is a little newer. We’d conceived a cat teleporting power pretty recently, but it was more involved and required some big environmental props. I realized pretty quickly that I couldn’t possibly do much of interest on the tiny PICO-8 screen (16 × 16 tiles), but I do like teleporting abilities! I briefly considered ripping off Axiom Verge, but I’ve already done that in fox flux, and the physics are a little involved… and then, lo, inspiration! Combine the two ideas: teleport great distances, but in a controlled and predictable way, by teleporting to the point on the opposite side of the screen. It felt like a very 8-bit kind of power, and I could already imagine a few ways to hide stuff with it, so off I went.

And that seemed like a reasonable progression. A way to talk (and progress through doors), a way to interact with objects, and a way to move around. I decided about halfway through development to make jumping a faux powerup as well; it stretches out the progression a bit more by making you walk past potential jumps and then come back to them later, which is important when I don’t have much map space to work with.

I’d originally planned for items to be separate from abilities, but ran into a couple problems, the worst of which was that I really didn’t have much screen space for sprinkling more items around. I ended up turning items into abilities in their own right, which I think was an improvement overall; now you can crinkle the plastic bag wherever you want, for example.

The game deliberately doesn’t try to explain itself; PICO-8 only has six buttons, and four of them are a d-pad, so I figured button-mashing (as in ye olde NES days) would get everyone through. Still, several players were confused about how to jump (and possibly gave up before even acquiring jump?), and one didn’t realize you could switch abilities, despite the up/down arrowheads on the ability box. Not sure what to learn from this.

The map

I struggled a bit with the map. PICO-8 has a built-in map editor with enough space for 32 screen-sized rooms (arranged in an 8 × 4 grid), which it turns out is not very many. I also very much did not want the game space to be confined to exactly that size of rectangle, so I knew I’d have to do some funky stuff with room connections. (Armed with that power, I ended up making loops and other kinds of non-Euclidean geometry, but hey that’s plenty appropriate for an imaginary moon.)

The bigger problem was designing the rooms outside of the PICO-8 map editor. I tried sketching in Krita, and then on paper, but kept running into the same two problems: it was tedious to rearrange rooms, and I didn’t have a good sense of how much space was available per room.

I found a novel solution: I wrote a Python script to export the map to a PNG, opened it in Aseprite, and edited it there — with each pixel representing a tile and the grid size set to 16. Now I knew exactly how much space I had, and rearranging rooms was easy: double-clicking a cell selects it, and holding Alt while dragging a selection snaps it to the grid. Here’s the beginning part of the game, screenshotted directly from Aseprite at 400% zoom:

A very pixellated map, with bright pink lines to indicate odd connections

When it came time to pack it all back into a rectangle, I copied the whole map, rearranged the rooms, and numbered them all so I could keep track of connections. Surprisingly, it wasn’t that bad a workflow.

The non-Euclidean map connections came in handy for packing secrets in more efficiently; most of the secret stars are off-screen, making them harder to find, but I couldn’t really afford to have a dedicated treasure room for every single one. So I crammed two treasures into the same room a few times, even though the two routes you’d take to get there are generally nowhere near each other.

Doors helped stretch the map out, too. It’s probably obvious if you think about it in the slightest, but doors don’t lead to different rooms; they reuse the same room. But some tiles only appear in the overworld, some tiles only appear in cave world, and actors (besides doors) don’t spawn in caves. That seemingly small difference was enough to make rooms vastly different in the two worlds; the most extreme case is a “crossroads” room, which you traverse vertically in the overworld but horizontally in cave world. (Honestly, I wish I’d done a bit more of this, but it works best in rooms that only have two overworld exits, and there ended up not being too many of those. Also, caves are restricted to basically just platforming, so there’s only so much variety I can squeeze out of them.)

Designing caves was a little trickier than you might think, since the PICO-8 map has no layers! If something needed to occupy a tile in the overworld, then I could not put something in the same place in cave world. Along with the design nightmare that is telepawt, this gave me a couple headaches.

I do like the cave concept a lot, though. I love parallel versions of places in games, and I have an unfinished PICO-8 game that’s centered around that idea taken to extremes. It’s also kind of a nod to my LÖVE games, all the way back to Neon Phase, where going indoors didn’t load another map — rooms were just another layer.

Aesthetics

Originally, PICO-8 had a fixed palette of 16 colors. You could do palette swaps of various sorts, but you can’t actually change any of the colors.

But since I last used it, PICO-8 gained a “secret palette” — an extra 16 colors that you can request. You can’t have more than 16 colors on the screen at a time, but you can replace one of the existing colors with a “secret” color. There’s also an obscure way to tell PICO-8 to preserve the screen palette when the game finishes, which means I could effectively change the palette in the sprite editor. Hooray!

I didn’t want to completely change the palette, so I tried to keep the alterations minor. For the most part, I gave up reds and pinks for a better spread of greens, purples, and yellows. Here’s the core PICO-8 palette, the secret PICO-8 palette, and the game’s palette, respectively:

A very bright palette, a softer and warmer version of the same colors, and a mix of them

I think I did a decent job of preserving the overall color aesthetic while softening the harsh contrasts of the original palette, and the cool colors really helped the mood.

Note that I changed the background color (color 0 isn’t drawn when it appears in a sprite) to navy and promoted black to a foreground color, which helped black stand out more when used as an outline or whatever. Probably the best example of this is in the logo, traced from the vector logo I made for the first Star Anise game.

Hmm, what else. The tiles themselves felt almost forced, if that makes sense? Like I could only draw them one way. PICO-8 tiles are a rinky-dink 8 pixels, and boy that is not much to work with. If I had a lot of sprite space, I could make bigger metatiles, but… I don’t, so I couldn’t. I tried a lot of variations of tiles, and what I ended up with were pretty much the only things that worked.

I love how the emoting came out. I knew I didn’t have nearly enough room for facial expressions for everyone, but I wanted to give them some kind of visual way to express mood, and the tiny overlays kinda fell naturally out of that. I think they add a ton of personality, especially in how everyone uses them differently.

I’m pretty happy with the sound design, as well. I’m an extremely amateur composer, and I wrote 90% of the music in a few hours on the start of the last day, but I actually like how it came out and I like going back to listen to it. The sound effects are, with some mild exceptions, pretty much excellent — the aowr is incredible, it has fooled other folks in the house more than once, and I knew I had it right when I had a blast just running around mashing the meow button.

I’m also happy with the dialogue, and hope it conveys the lunekos’ personalities in just these few interactions.

While writing the ending, I had to stop in mid-draft to go cry. Then I cried again when I finished it a few days later. I’ll miss you forever, Branch Commander Twig.

If you did, thanks for playing.