Jailbreaking your 3DS is not synonymous with piracy, no matter how popular it may be to do so for that end. Here's a non-exhaustive sampling of some cool things you can do with your fancy little 3D clamshell computer.
(you've got a Retrode, right?)
(these will work on legitimate copies of games; the patching is done at runtime, i.e. by redirecting I/O to the patched assets)
and once you're done, head to this section on my website to see more things you can do with them. for the 3ds's case:
Why are they always going to the archive.org archive of the taken-down github repository and downloading the latest release?
Why are they always checking out books from their local library or the internet archive library, downloading the acsm file, and then doing
cd Downloads
chmod +x ./knock-1.3.1-x86_64-linux
./knock-1.3.1-x86_64-linux whatever_cool_book.acsm
and then immediately returning the eBook to the library so other library patrons can enjoy the eBook????
Why are the hottest girls even hypothetically then loading the DRM-stripped ePub into their Nintendo DS emulator with their favorite homebrew ePub reader because there are no good ePub readers on linux??????? ;-;
And then why are the nerdiest among them always downloading the archived source code and building it from source with nix???
I just really don't get women anymore
(thanks to my co-author on this post @spiders)
This was originally a Twitter thread, but Twitter threads are no substitute for actual essays, so I'm putting it all here for posterity, with a little extra editing, a few additional notes, and a lot less exclamation points.
I can't for the life of me even remember what this was subtweeting at this point, but it doesn't matter, it could apply to a billion things from the past year and you'll probably see it come up again next week: "A problem that comes up when you're developing a game based off a specific reference point or genre is that it can be hard to talk about the work in a way that both communicates your respect for it, while also expressing that your love is a well-thought out and critical one." I mean, it's sort of obvious stuff for actual criticism, everyone knows that, but I think it's especially hard for game designers because they forget that people outside of GDC lectures expect the marketing voice from them, not the critical one. Not that everyone is coming from a place of good faith, but I think it's generally the most common—when people make things inspired by others, it's usually because they wanted to share the joy they felt while playing it. But it's understandable how in this context, the impulse "well, I wouldn't to include elements into my game that I haven't thought through just because another game has them" can come across as being smugly above it.
Personally this is why I decided instead to make my own game be inspired by Final Fantasy XIII, which is perfect and has no flaws, thus eliding the problem entirely.
I mean, this sounds like a joke, but it's genuinely not. I want to make a game inspired by a particular JRPG because I loved it, and therefore want to show WHY I loved it. Get in the Car, Loser! is basically a persuasive essay on why I think FFXIII rules. That means figuring out what decisions are part of what I loved, which ones aren't, and what context informed both! My goal is to make that love as accessible as possible, and to work with my own strengths, of course. A lot of the time I'm thinking along the lines of "how do I convey the feeling I got, within my own toolset?" But you gotta first understand why they made the decisions they did in order to even start.
An example: the stagger meter is the core of both FFXIII and GITCL's battle system! It sits in the corner, and once it's been filled, it gives you a temporary damage multiplier to your attacks until it finishes ticking down.
But what’s the FEELING of stagger, and what purpose does it actually serve?
I haven't seen any design interviews about the stagger system in FFXIII, but the Final Fantasy 7 Remake has a similar system, and co-director Naoki Hamaguchi has discussed his vision with that game's version of it. FF7R’s stagger system is extremely different from FFXIII’s and is less emphasized (it’s incredibly short, only Tifa can manipulate the multiplier) but here’s how he describes it in an interview with Unrealengine.com, so you can see what some of his goals were—specifically, making battles feel less homogeneous.
Hamaguchi: Simple mechanics would allow for many people to jump in and would facilitate ease of gameplay, but on the flip side, if it’s too simple, considering just how often you go into combat, it inevitably would become repetitive, and players could tire of it easily. So, we carefully selected and implemented elements that would provide depth, without being too complex based on two major pillars: action and strategy.
The Stagger system, for example, was implemented to avoid repetitive gameplay, where the player would spam high-damage commands when trying to defeat an enemy. You might want to rush your enemy with commands that would Stagger them quicker; or if the enemy’s health is low, it may be better to attack them with high-damage commands, rather than aiming to Stagger them; or you might want to hit them with commands that would halt them in their tracks in preparation to stagger them – many different options could potentially stem from the commands you choose, and we’ve designed it so that those would link to the element of strategy.
In fact, this has always been a goal of Final Fantasy’s battles. When Active Time Battle—a system that rewards you for knowing your gameplan ahead of time—was invented for FF4, they expected players to be overwhelmed and just reflexively mash. So the very first boss fight teaches you to vary your plan, by having a counter-attack state. If you mash Fight when the Mist Dragon is in mist form, you'll get hit hard!
Here’s the page from Final Fantasy IV's original pitch doc (recreated in Final Fantasy Ultimania Archive Volume 2) explaining a little more about what the idea behind ATB was. It seems obvious and intuitive now, and FFIV feels kinda simple overall after years of playing games iterating on ATB, but the shift from turn-based to active time clearly had huge design implications.
- New Battle Scene System: Active Time Battle (ATB)
ATB is a new battle format eliminating turns and using the natural flow of time.
In traditional command-based RPGs, the party inputs commands according to party order, and battle begins once all inputs are complete. With ATB, commands are input in order of character speed, and characters will begin to execute actions as soon as the player moves on to input the next command.
Of course, this system applies to monsters as well. Enemies will not wait for the player's command inputs, and will press the attack regardless. But do not think of this as a real time strategy game. In real-time games speed is the key, but with FFIV's ATB system, enemy movements and adapting to changes are the keys to victory.
In battles with special enemies, you must grasp the flow of time. For example, in battles with monsters that change shape, you cannot win by attacking again and again. Instead you must calculate the timing of your attacks in order to inflict damage. If a monster has erected a barrier, you must focus on defense and powering up rather than attacking. Once the barrier goes down, take the offensive and attack all at once. You must always choose the commands that best suit the situation.
Fighting while understanding the concept of time will be to your advantage. For enemies like the Bomb that self-destructs when damaged, there is now a gap between the time it takes damage and the time it explodes. By casting magic that slows its movements, you can attack again before it explodes and defeat it without taking damage.
Let's explain how magic works. All magic will incorporate the concept of time. As such, magic is not cast immediately upon input, but only after the character has completed the incantation needed to cast it. Said time will vary depending on the magic being cast. (Incidentally, characters will display a chant animation during the casting of magic.) The magic selection includes time spells to slow enemy attack cycles (Slow), to speed up ally attack cycles (Haste), or to halt enemy movement for a set time (Stop). Even supplemental magic that only changed the number of hits in previous titles will now become useful magic under the ATB system.
When you encounter several different types of monsters, the order in which you defeat them influences the battle's difficulty. This is only possible with the ATB system. For example, say you encounter two types of monsters: Type A and Type B. Type A will cast Haste on Type B, so ignoring A will only make B stronger. Players will become desperate to defeat A. We've seen scenarios like this in other FF games, but things get trickier with ATB. There may be cases where players decide that defeating A will stop B from powering up, so they change up the attack pattern they've been using. In doing so, they will take an unexpected amount of damage. This is why considering attack patterns with respect to enemy combinations is a vital part of fighting under ATB.
Through ATB, you proceed by changing up your style of fighting, making it a system that rewards experimentation. This is different from the past, where relying on the strongest weapons and most powerful magic would ensure a win.
Thank you for reading our simple explanation of the Active Time Battle system.
Wow! This is an amazing document, isn't it? They've completely outlined the core of what makes ATB interesting with absolute clarity, basically the vision was perfectly formed from the start—it took them years upon years of iterating on the system starting from FFIV to make it feel complex and satisfying and fun, but literally all the building blocks were there from the start. This one simple concept leads to such a rich space that you can build on it for years.
By the time they got to FFXIII, ATB was still at the core, but with some extra ideas built on top of it that emphasize some of these goals, and deemphasize others. That's iteration! So let's bring this back to stagger specifically.
In FFXIII, the stagger amount (represented as a %) constantly ticks down unless you maintain it with damage. Since its ATB system deemphasizes timing and is instead all about queueing long attack strings at once while your AI companions fight in the background, it’s easy to have a steady flow of damage to keep the bar consistently going up.
But GITCL has characters attack instantly when you press a button, followed by a cooldown timer, so damage is more “lumpy.” So stagger length, and how much the bar is increased by, has to be tuned to allow for smaller numbers of bigger attacks.
Because of that lumpiness, it wouldn't make sense to be a DPS check like it is in FFXIII. And if it's not about DPS, it meant we could make the Sword of Fate super ability sometimes even insta-stagger, because big bursts aren't out of place. To compensate for this and to emphasize the timing element, once an enemy is staggered, you need to take advantage fast, or it'll have been wasted.
As a result, even though the numbers are radically different, it still leads to the same feeling: having to think reactively, and building your gameplans around relying on the big damage you get during the stagger! And if I’ve pulled it off, it'll be just as satisfying, I hope!
That was the original thread. But I think there's a pretty obvious follow-up question that requires digging deeper: why did FFXIII make that change in emphasis in the first place? The FFIV design doc's description of ATB is all about precise timing, but long attack strings are surely contrary to the idea of "understanding the flow of time," right? What made them decide to change emphasis like this? Well, here's how Battle Planning Director Yuji Abe described what they call the "Command Synergy Battle" system.
When Final Fantasy XIII entered development, the console-generation of the PlayStation was new and fresh. We tried to work with the power of the new technology and the pure, classic style was not possible. We wanted a system that lived up to the graphics and smooth animation of the characters. A static battle-system like the ATB was not the best solution, but we tried it at the beginning.
If that's your goal, long strings of attacks make a lot of sense. You pick tactics, and watch your characters carry them out. The focus is on the cool animations possible on next generation hardware, so you want to show a lot of those animations in a row without the player getting distracted by inputs.
In contrast, GITCL doesn't keep this element and hews a little closer to traditional ATB. Here's what our battle UI looks like—you'll note that at the top of the screen, each character has exactly one action assigned to a unique button for them, and you have to switch which action is available all at once. This is pretty different from how you select discrete paradigms, then just hit "auto" in the menu in between Paradigm Shifts.
Long attack strings work really well in FFXIII, because they can make a LOT of different animations that are characteristic of each party member, vary them up, have the camera move to show things from different angles, and even build long unique special attacks for every single character. They're right, smooth animation is their strong suit!
But GITCL is a 2D game, so camera control is out. Our animations are really good, but we also have a very small budget, so we need to really make what limited ones we have count. Long strings would therefore look repetitive, so clearly, we need to prefer shorter attack strings so that stands out less.
What does "shorter strings" actually mean, though? Well, if an attack string is very short, they could even be on a single button press. Valkyrie Profile was an obvious inspiration, which assigns each face button to a character. Pressing a button means you get action instantly—it's satisfying!
That instant response hopefully means you feel a little less distance from each character—this is something FFXIII's designers worried about too. Here's Yuji Abe again in an interview with IGN, discussing changes being made between FFXIII and Lightning Returns, discussing the concept of that "distance."
From the perspective of having a system where the player has a specific intention of what they want to achieve in battle and controlling multiple characters in real-time in order to control the outcome of the encounter I think that using this system was essentially the correct choice.
However, on the other hand I feel that by relying on setting AIs and switching between different pre-set combinations it creates a distance and makes it much less accessible for everyone to get into the system. Another point that I feel might be a weakness of this system is that it dilutes the feeling of immersion by not having one specific character for the player to inhabit, something that many players want from RPGs.
Personally, I love the core of Paradigm Shift and the feeling it provides, but I can't deny that the distancing effect he describes is very real. And while I love the approach they ultimately ended up taking in Lightning Returns, where combat sets are tied to specific outfits that you change on the fly—it's not something that would make sense for our type of game.
So I tried to come at it from another angle to come up a system that might instead provide both these feelings at the same time. From there, the concept of boards emerged. If it's one button per ability, then how do get the feeling of "change tactics by changing character classes" that Paradigm Shift gives you? Well, character classes are really just different abilities, right? So you change ability sets.
So this ends up looking very different (short strings, lots of jumping in and out), has a very different interaction (immediate response on button press, lumpy damage)... but hopefully ends up giving a similar sort of FEELING to a good strategic use of Paradigm Shifts.
If this sounds interesting to you, Get in the Car, Loser! is currently available on Steam and Itch. And if you have played it already, well, Final Fantasy XIII is also on Steam and hopefully my game has served as a successfully argument in favour of how great that one is. I wouldn't have made my own game inspired by it if I wasn't thinking about it constantly!
Hi, I'm Stryxnine. I'm an esports broadcast producer and audio producer. In this chost I'll be explaining the key ways to immediately improve the audio on your livestreams.
Glad you asked! The biggest reason is because advertisements are fucking loud. Unfortunately, with advertisers constantly in a loudness war with each other, we have to care about our audio levels so when ads pop up for our viewers they don't scare the everloving piss out of them with the immediate difference in volume. Beyond that, we wanna make sure we can be heard over the game and the music playing in the background.
It's pretty easy, but it's also a bit of a process!
Let's start with the basics: the audio meter.
The audio meter (shown on the image above from OBS) tells us the volume of our source audio. Many people may believe having your audio in the red means you're clipping, but that isn't the case; it just means you're close to clipping. As a result, many streamers put their audio below the yellow line; this isn't good, because that means those pesky Twitch ads are gonna shatter your poor viewers eardrums. At maximum, we want our loudest sounds tickling the red zone. If we fill out the entire red zone, that is when we're clipping.
In the image above, you can see some suggested ranges for different types of audio. If you like to play music in a separate app for your stream like Spotify or iTunes, you want that source to be playing between -35 and -25 decibels. Your Game audio (or desktop audio) should be around -25 to -18 decibels. Finally, your microphone audio (and the audio of VoIP apps like Discord or Teamspeak if you stream with friends) should be occasionally touching but not going too far into the red zone.
We aren't quite done yet! We have our audio levels set, but we wanna be extra sure we don't clip our audio, and we wanna be sure our viewers can hear us over the game and music whether we're whispering or talking or shouting! With our audio levels set, we're ready to add some audio filters.
First we'll click on the cog wheel under our microphone audio source, then click Filters. This will open our lord and savior, the Filters editor!
This baby is gonna help us make sure we don't clip, but we can also add some other filters that will improve the quality of our audio. The Noise Gate works pretty similarly to Discord's Voice Activity input mode, where the audio of your microphone will be sent to your friends if the volume reaches past a certain level. The only difference here is that we have a lot more control over how the noise gate functions on OBS. To add a noise gate, click the plus button on the bottom left of the window and select the Noise Gate filter. The order of our filters is important. OBS will adjust the audio signal in a path from the filter at the top, to the filter at the bottom. if we put a noise gate at the bottom of the filter chain, it might not work as effectively as it should!
With the noise gate filter added, you will see Close and Open Threshold sliders, as well as text boxes for Attack, Hold and Release times. Move the Filters window so you can see the audio source you're filtering (so in this case, our microphone audio). Talk into the microphone in the same position and at the same volume as you would during the stream, then stop talking. Be sure to take note of the numbers below the audio meter as you do this. Different microphones will have different audio levels, so the numbers in your noise gate might not match mine!
Generally, you will wanna set the open threshold high enough that it won't be accidentally activated, but low enough that you don't have to yell for the audio to start coming through to the stream. For your close threshold, it's pretty safe to set it about three decibels below the open threshold. The attack time is how fast the filter will allow all of the audio from your microphone through, so it's a pretty good idea to keep this setting pretty quick. 5ms is a great all-around setting for the attack time.
The Hold time will determine how long the filter will keep allowing audio through after the close threshold is triggered. We'll want this set fairly high - around 400 to 500ms - to make sure the filter isn't cutting our voice off while we're still talking.
The Release time can be adjusted to taste, but it's a good idea to keep it fairly slow so your microphone audio will gently drop until the noise gate fully closes and it won't cut the tail end of your voice off when you're done talking. A good range is about 450 to 650ms.
Yeah, it can be pretty confusing if you're not familiar with any of this! If you ever get confused you can DM me on Discord at HOOTwheelz#0666 and I can help ya figure it out!
Glad you asked. Compressors are kind of a difficult filter to learn how to use, so I'll skip over that for now and move on to the Limiter filter.
This one's pretty simple; all you can adjust are the Threshold and Release. Set your threshold to -5 dB, and your release to 50ms. If any sound goes through your microphone at a volume that exceeds that threshold, the Limiter will act like a wall to keep the audio from clipping. Like I said, pretty simple!
Fuck. So, a compressor acts kind of like a Limiter, but it has a lot more settings to control.
Like, a lot more. So, let's break it down. Add a compressor filter, then click the Up arrow to put the compressor between the noise gate and the limiter in the filter chain.
The Threshold is the volume where the compressor will start working. Once the threshold is triggered, the volume that goes beyond it will get compressed based on the Ratio slider. Generally, 3:1 to 4.5:1 is a good ratio setting. Attack should be set to 5ms, and release can be set from 50ms to 70ms.
The threshold is gonna be a bit of a pain in the ass to set, though. You wanna set it low enough that it actually compresses your audio signal to keep your loudest on-mic moments from scaring the shit out of your viewers, but not so low that it crushes the shit out of your voice and makes your oscillating fan sound like it's right next to your microphone. Depending on your audio rig, you'll likely have a threshold set between -30 and -22. It's gonna take some trial and error to figure out what works best for your rig, but thankfully you can use OBS's recording function to record a snippet of yourself talking at a whisper, at normal volume, then shouting. Then listen back to the recording and adjust the threshold to taste.
If you think you sound too much like a radio show host, set your threshold higher. If you think the difference in volume between whispering, talking and shouting is a bit too much, lower the threshold.
Finally, adjust your Output Gain slider and watch your audio meter. You'll want to adjust the audio slider until your voice is once again tickling the red zone.
Don't worry about it... unless you want to.
Yeah! You've done some pretty basic, but still very important audio production! Congrats!
If you need any help with anything (or if you want me to give you a full audio production overhaul with all the Really Smart Things I Know) hit me up on Discord at HOOTwheelz#0666.
Hope this helps!
I actually just made another post (on May 29th at 7:30am because I'm a freak). That post goes into more complex audio production techniques like Ducking/Sidechaining and Equalization. Do you like the idea of making your video game audio or music get quieter while you talk, or changing the tone of your voice to make it sound smoother and removing explosive bassy noises when you pronounce a hard consonant as in the words Tail, Crush or Pound? Then my Advanced Audio Tips can help you out!
To be very clear: The advanced audio tips aren't necessary to have good audio quality on a livestream, and it won't necessarily lead to more viewers. The tips I've provided here are already more than enough to put you on par with a majority of other livestreamers. Many livestreamers are successful without anything more than the basic mixing you've accomplished here. However, if you really want to go the extra mile and make your audio really stand out in the crowd, the advanced tips might help you get that extra 5% you're looking for. Just keep in mind: you can be successful with basic mixing skills, and you really don't need that next step. If you're seeking to get competitive against the tippy-top level of streaming though, the advanced tips can give you an advantage.
If you're into indie game development, there's quite a few game developers you can follow here on Cohost. Here's a few examples, you can click on their name to go straight to their page.
@Paci, the developer of Tower of Spirit
@ItsMeLilyV, the developer of BOSSGAME: The Final Boss Is My Heart
@daikon-games, the developer of Chico and the Magic Orchards
@UnlimitedTrees, the developer of UNITRES Dreams and TREES' ADVENTURE
@marlowedobbe, the artist on Floppy Knights and Dicey Dungeons
@damonreece, a writer on Necrobarista and Grim Tranquility
@MOKKA, the developer of Virtue's Heaven and GB Rober
@npckc, the developer of A YEAR OF SPRINGS
@brodnork, the developer of Frogsong
@millardcrow, the developer of GHOST ECONOMY and THE NEXT GREAT DEITY
@binary, the developer of APOCALYPSE FRAME and Total///Effect
@PIZZAPRANKS, the curator of indie game compilation Indiepocalypse
@tayl1r, the developer of SOKOBOT and Touhou Library Survivors
@littlerat, the developer of Marcus Comes Out Online and Peyton's Post-Op Visits
@SuperBiasedGary, the developer of it started with hairs and Pen to Paper
@bugbearstew, an artist who works on Yolk Heroes: A Long Tamago and Rogue Labyrinth
@tofurocks, the developer of Lotus: The Self-Made Witch and How We Show Love
You can also head over to this post to find a bunch of other game devs introducing themselves in the comments section! Feel free to introduce yourself there as well. Every month, I pick a few to do interviews with here on my page.
You can find more devs by also checking out the #devlog tag, the #gamedev tag, the #indie games tag, and more!
Find some people whose posts you like, and have fun! Remember: nobody is ever alerted if you unfollow them, so curate your timeline however you like.
Are YOU a CSS BABY who has been keeping up with this series so far?
Are your friends doing stupid css tricks and leaving you feeling left out?
Do you wish Eevee
Eevee would help you out?
great news it's time to Put Stuff On The God Dang Screen
in our previous installment i told you about changing the size of a box... but it still gets placed with flow layout, which means put in the jenga stack of block boxes.
but that will only get you so far.
css has several whatchamacallits for letting you arrange boxes in more interesting ways, but they generally get more complex as you go, so we're kinda gonna start with the more straightforward stuff and work our way up. as luck would have it, this is also the order this stuff was added to css, so it's like a historical jaunt through how horrible it was to be a web developer in 2004
there's a css property called position
and hmm that sounds like a pretty good place to start. this sets the type of positioning the element uses, and as of this writing, there are five of them:
this is what everything has by default. it's what we've been using all along. it's kind of a weird name but you can think of it as "normal". nothing to see here
this one is a little weird, and 99.9% of the time it's only used for a side effect, which we'll get to in a moment
but what it does is place the box normally, and then let you adjust where the box actually displays. so it's a bit like using transform: translate();
. except it's, um, older.
you can adjust the positioning with the four "edge" properties: top
, bottom
, left
, and right
. they're all lengths, relative to the box's original position, and where positive values mean "inwards" — so a positive left
will shift the box to the right, whereas a positive right
will shift the box to the left.
so you might do bottom: 0.5em;
or bottom: -0.5em;
or bottom: 50%;
.
hmm. that last one didn't seem to do anything. that's interesting. i wonder why that i—
ahem. other deets of note here:
the "edge" properties do nothing on a static
element. they're just completely ignored.
depending on how the text wrapping shakes out, you might notice that relative positioning works on inline elements, even when they're wrapped! the whole wrapped box gets shifted. sort of like wrapped boxes can also have wrapped borders.
there's a newish property called inset
that lets you set all four of these properties at once, using the same kinds of "four edge" syntax as e.g. margins and borders. it's not very useful here, since inset: 4px;
would move the box four pixels in every direction which puts it right back where it started, but that's a fantastic segue into...
here's our first Cool Tool. in fact i believe a series of escalating demonstrations is in order.
<div style="border: 1px dashed black; height: 10em; padding: 0.5em 0.75em;">
here's a box with a line of text in it.
<div style="position: absolute; background: #eee; padding: 0.25em 0.5em;">
and here is a div that appears, physically, <em>between</em> those two sentences. go on, check with inspect element
</div>
nothing weird here
</div>
wooooaaahhhhh. so what happened here?
the lil guy in your browser got to that div and saw it was a block, so they stacked it underneath the previous line of text, as normal. however, since it's absolutely positioned, it has no effect on how anything else gets laid out. once the lil guy got past the div, they forgot all about it, and they placed the second line of text right next to the first line, just like any two inline bits next to each other.
(note that the box is also weirdly wide. there's a good reason for that. hold your horses)
anyway, you can see more concretely how this works if i make the text long enough to wrap, and put an opacity
on the div:
ah! the text overlaps. and this is a common risk with absolute positioning, precisely because it gets pulled out of normal flow. it really does not care what else is going on outside of it.
so far this doesn't look very useful, unless you want to make overlapping text for some reason. but i can put inset
or those four edge properties on an absolute element too. let's try bottom: 0.5em
...
oh no, where did it go?? (see if you can find it)
see, there's a special rule for positioning absolute elements: if you give them a position, it's not taken relative to the parent, like with position: relative;
. it's relative to the nearest positioned ancestor. that means you go up through its parent and its parent's parent and so on, and you look for the first ancestor that is not position: static;
, and that is the box whose edges are used as the baseline.
since the containing box above (the one with the dashed border) doesn't have a position
property, it defaults to static
, and it's not eligible. so the browser keeps searching outwards, and it will find... the element containing this entire post. and now you should be able to find the missing element.
and, surprise: this is what position: relative;
is used for, 99.9% of the time! it's slapped on some parent element in order to say: hey, i've got an absolute box or two inside me somewhere, and i want it to position itself relative to me. here's what happens if i slap position: relative;
on the container and change nothing else:
hey hey! there it is. welcome back, little guy.
you may also notice that it's no longer weirdly wide! that's because, in the absence of any other properties telling it where the right edge should be, it acts like it has right: 0;
. that puts the right edge flush with the edge of the nearest positioned ancestor — which previously was the post body, but now is the dashed container.
of course this is still a little ugly and i cannot resist fixing it by specifying more edges with inset: auto 0.5em 0.5em;
, which you may recall is equivalent to top: auto; left: 0.5em; right: 0.5em; bottom: 0.5em;
.
<div style="position: relative; border: 1px dashed black; height: 10em; padding: 0.5em 0.75em;">
here's a box with a line of text in it.
<div style="position: absolute; inset: auto 0.5em 0.5em; background: #eee; padding: 0.25em 0.5em;">
and here is a div that appears, physically, <em>between</em> those two sentences. go on, check with inspect element
</div>
nothing weird here
</div>
note a cool, but slightly subtle property of absolute positioning here: i only gave a bottom
and not a top
, and the element is only as tall as it needs to be. (of course, if the rest of the text were long enough, it would still overlap. absolute positioning requires some careful consideration of how big you expect things to be.)
the general idea is that there are now three properties in each direction that are all vying for attention: top
+ height
+ bottom
, and left
+ width
+ right
. the idea is that you can give whatever subset of these you want, and the rest will be determined automatically. (i am not sure what happens if you give all three in a conflicting way but it's probably not helpful.) for example, you can give a width and one edge, and leave the other edge automatic:
that's right baby: percentages do work on absolute elements, both in theory and practice. an absolute box has no impact on how its parents are drawn, so there's nothing complicated about using percentages here; the browser just figures out the size of the parents, then bases the size of the absolute box on that.
but wait! there's other position
s!
i'm actually not allowed to show you this one because @staff specifically strips it out of posts. but it's like position: absolute;
, except instead of the edge properties being relative to any particular parent, they are always relative to the viewport. so this is how you'd make one of those header bars that sticks to the top of the screen no matter how where you scroll.
i'm sure you can imagine why this is no longer allowed on cohost
this is the most recent addition by far, and it is actually pretty cool. it's uhhh kind of weird to describe, like a hybrid of relative and absolute and fixed positioning but for scrolling areas— okay look lemme just show you
ohhh daaaannnggg this box is gonna have a lot of text i bet
like i can't even imagine how far down it might go
luckily there's a scrollbar
oh wait i didn't explain how to make scrolling areas yet
well we'll get to that in a minute i guess
but it's kind of important for this property so i'm cheating and skipping ahead
Deal W It :sunglasses:
yeah see so it's kind of like position: fixed;
in that it stays in one position without caring about where you scroll to...
but it's also like position: relative;
because it is part of regular layout, it just gets displaced.
and the funky part is that it only gets displaced once it would be scrolled out of view, in a direction given by which edge properties you set. i gave that one top: 0;
, so it "sticks" to the top edge of the scrolling region, once you scroll below its normal position.
i actually don't know the precise rules, but several times now i've slapped position: sticky; top: 0;
on something and it's just worked exactly how i wanted. it's kind of great. you can even put it on like table rows, to keep the table header visible as you scroll down! and it won't "stick" beyond the top of its parent, so if you scroll entirely past the table, it goes away. i love it. it seems so niche but when you want it, you really want it
right, so, how did I even make a box with a scrollbar?? that's pretty easy actually: there's a property called overflow
that says what to do when there's too much stuff in a box.
i forced this to happen above: all the dashed containers have height: 10em;
, but i put in a bunch of paragraphs that would end up being way more than 10em tall. but it can also happen naturally, such as by having an unexpectedly long word appear in a small area.
yeah, like that. cohost actually fixes that particular problem with a newer property, so i had to unfix it to make that happen
anyway on to the properties
this is the big one, the one that lets you have scrollbars. basically you can set it to
visible
: the default behavior, where stuff overflows and you can see it and that's that
hidden
: anything that escapes its box is just cut off and not drawn
auto
: if something would overflow this box, slap a scrollbar on
scroll
: there are always scrollbars, which are disabled unless necessary. this is usually ugly but it has historically been used to avoid having quantum scrollbars possibly eat part of the box's inner dimensions. of course now it seems like browsers use those mobile-like overlay scrollbars exclusively, so, this doesn't really matter any more
there's also a clip
value, which seems to be like hidden
except you can specify exactly where the line is where stuff gets sliced off. i don't know why you would care so much about that but you can do it apparently.
this is pretty straightforward and you will rarely ever do anything other than overflow: hidden;
(spite) or overflow: auto;
(scrollbars)
you can also specify different behavior horizontally vs vertically, by either giving two values or setting overflow-x
and overflow-y
separately, but like, why, man
this is the guy that forces words to break if necessary to avoid overflow: overflow-wrap: break-word;
. it's already on cohost posts by default so you basically don't have to care about it unless you're writing a css guide and need to turn it off to show why someone might want to turn it on. (turn it off by setting it back to normal
.)
this one's kind of cool. well. it's cool that browsers can do it, and it's better than not doing it in some cases, but the results can be unfortunate. lemme just—
perhaps you can see what i mean. it's very aesthetically satisfying that the text no longer escapes the box, but, uhh... now you can't... see... what it says.
so you might want to make the text available some other way if you're gonna do this. i guess the common case is for a title in a grid of thumbnails or something, where you can also put a tooltip with the full title.
anyway the property is text-overflow: ellipsis;
. you can also give a string to specify what to use for the cutoff instead of an ellipsis, but this won't work in legacy browsers like chrome. haha, zing.
note that this only works if you also use overflow: hidden;
— this puts an ellipsis where the text cuts off, so if it doesn't actually cut off, nothing happens.
this controls how text breaks on whitespace:
white-space: nowrap;
will never break and will effectively put your text as a single line, unless you use <br>
explicitly
white-space: pre;
acts like the <pre>
("preformatted") tag and preserves whitespace exactly as it's written in the HTML. (normally, line breaks and excess spaces in HTML are collapsed to a single space.) it will also never break.
white-space: pre-wrap;
is like pre
, but it will break lines if necessary. this is a cool middle ground that i use sometimes
there's a couple others but these are the main ones. in particular, nowrap
pairs well with text-overflow
.
boy, that got a bit dry for a while there! let's do something with a big colorful box.
we now know more than enough to pick apart my newest iteration of <aside>
:
there's not a lot to it. the border and box-shadow you already know about. (the shaded bit on the left is just a second inset box shadow.)
the interesting part is the emoji peeking out of the box, but that's pretty easy. the box itself has position: relative;
, of course. then the emoji has
display: block;
position: absolute;
transform: rotate(-15deg);
width: 4em;
margin: 0;
left: -2.5em;
top: 1em;
and i don't think any of this will be very surprising. (the margin: 0;
is to override cohost's default CSS, which expects an image to be a block on its own with margins above and below.) it overlaps the edge of the box because i said left: -2.5em
, which puts its left edge 2.5em outside the reference box... but the emoji itself is 4em wide, so it sticks partway in.
the text along the top works the same way, although i gave it a few stacked text-shadow
s so it's still readable with the border running through it.
i mean that's basically it. you already know everything else from previous installments! wow, look at the big brain on you already
before we leave positioning behind, there's one subtle trick i want to call out. recall my very first example:
the absolute box has no edge properties here. without them, its top left corner goes exactly where it would have gone, if it weren't absolutely positioned.
and if you only set the horizontal edges or only set the vertical edges, the other edge will remain in this "default" position!
every so often, you might find a compelling reason to use this. for example, this absolutely-positioned dingbat will stay horizontally aligned with its "original" position in the text, because i never told it to move vertically:
it only comes up once in a while, but when it does, it feels galaxy brain to be able to do this. another handy use is for stuff that only shows on hover... but we can't do that on cohost.
also, i did move the dingbat vertically a bit up there, but i didn't use top
. instead i used margin-top
, because margins on an absolute box will shift it around independently of its inset
. you can use this to, say, center an absolute element on the border of its container. although nowadays you can often just use calc()
the same way.
and now, you know most of how the row of navigation buttons on these posts works. the giant numbers are just absolute positioning. the "your here" label uses absolute positioning to keep the label the same width as its relative parent (which is the default!) but move it outside.
actually putting that stuff in a row takes a bit more effort still. wait til part 4.
now that we have touched upon the fact that absolute boxes can overlap stuff, a question arises. if two things overlap — something it seems we might even want to do on purpose at times — then which goes on top?
luckily, the default behavior is pretty straightforward. a later sibling appears above an earlier sibling. all children appear above their parent. that's it.
(well, almost. all positioned boxes also appear above all non-positioned boxes. that's pretty sensible; if you slap position: absolute;
on something then you probably want it above normal text.)
let me, uhh, see if i can rig a 3d diagram of this
that's not very 3d. i'm super good at css i'm sure i can—
yeah. okay. beautiful.
(i used negative margins here to overlap these, which might be instructive to inspect with devtools.)
i think that makes sense. stuff that comes later goes on top. it's like the little guy in your browser puts each box on the screen in the order they appear, so every time they see a new box, they just put it on top of all the other boxes.
alright so what if i want 1a to be on top, but i have compelling reasons to not rearrange the elements? enter z-index
.
z-index
takes something out of the usual order and puts it on its own numbered layer, where the default layer is number 0. so by giving box 1a z-index: 1;
, i've raised it above everything else on layer 0.
within a layer, i'm pretty sure the usual ordering applies. so if i also put z-index: 1;
on box 2, it would once again appear above 1a. (use devtools and try it!)
you can also use negative layers, which can be used to put a box underneath its own parent. this is usually done for goofy visual effects involving the parent's background.
also, this only works on positioned boxes, i.e. not position: static;
. but once again, position: relative;
can come to the rescue and enable z-index
without actually moving the box around.
cool. easy, right?
it is a little complicated. but good news: it is no longer as complicated as it once was.
the problem that arises, which i think is a pretty reasonable problem, is this: what happens when a box with a z-index
has children?
like, imagine my rainbow assortment of elements above. i used z-index: 1;
to move one of them to the foreground. sure. but what happens if i want to put the whole collection inside some other element?
and what if the element i want to put them inside already has z-index: 5;
?
whoops. now by saying z-index: 1;
, it seems like i'm asking box 1a to draw behind everything else. but... everything else was layer 0. right? what?
that behavior wouldn't make any goddamn sense at all, so the wizards at CSS Inc. had the foresight to solve this problem by having the layers be nestable.
what actually happens is that putting z-index
on a box creates a thing called a "stacking context". the phrase strikes dread into the hearts of many CSS users for reasons i will get to shortly, but it really means two things:
everything on the inside gets layered on its own, and then all that stuff acts like a single layer on the outside. as a result, nothing on the outside can be layered between two boxes on the inside.
the layer numbering on the inside is completely independent of any layer numbering on the outside.
you can see this in the diagram, where i've given everyone a z-index.
boxes 1a and 1b have the same z-index, so they stack in the default order.
box 2 is above box 1, because it has a higher z-index.
boxes 1a and 1b do NOT stack above box 2a, despite having a higher z-index, because they're insulated within the stacking context created by box 1.
compare with what happens if i remove the z-index from boxes 1 and 2:
box 1 no longer creates a stacking context, so it and its children are free to interleave with other boxes.
this was a headache for a long time, because the set of properties that create a stacking context was kind of a mess of special cases that no one could remember. so it was hard to make a new stacking context when that was specifically what you wanted, and it was much harder to understand at a glance which elements were creating stacking contexts.
and this is something you only care about once in a blue moon so it tended to fall out of your head anyway.
luckily, they finally made a property that just creates a stacking context and nothing else: isolation: isolate;
. it's like making a new layer group.
hope all of that makes sense lol
because boxes are layered individually, it's impossible to make something like this:
hmmm! i sure wonder how i did that, then.
moving right along—
here's a cool tip: dont use floats!
there is some history here.
floats were designed for doing like a magazine "floated image" sort of thing. in fact they were based on the original html 2.0 or something <IMG ALIGN=RIGHT> attribute. a lot about html is designed from a sort of "magazine article" perspective, and i think the whole subject makes more sense if you think about it like that. so then when they designed CSS, which was meant to get "style" out of HTML, it sort of inherited this capability as the float
property.
and that's fine because if you really do just want a little magazine inset with text wrapping around it, it does exactly that. the problem is that circa 2000 we didn't really have a lot of layout tools in CSS, but some madmen discovered you could slap float
on anything, and off we went. entire websites were built out of them, out of floating boxes that weren't really floating around anything. some websites, if you resized them just right, the entire website would drop below the sidebar. it was a fucking nightmare.
worst of all was when you tried to use it for smaller pieces of a page, like putting an avatar on the side of a comment. because now you had the problem that if the float was taller than the rest of the box, it would just stick out the bottom and possibly fuck up text in the next box down. and to fix this you would have to do some unholy thing like
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
and that's assuming it actually worked in your target browsers; sometimes it wouldn't and you'd need more nonsense for that.
nowadays you can just do display: flow-root;
or use the newfangled contain
property to enforce that floats can't escape a box, but frankly it's easier to just not use them unless you're pretty dang sure they won't do any damage.
it's float: left;
or float: right;
, and you can also put clear: both;
(or just left/right) on an element to make it drop below any neighboring floats, which is how the "clearfix" thing works.
but unless the exact specific thing you're doing is to wrap the lines of a paragraph snugly around an inset box, don't use floats. thanks
this one sure did get kinda long boy howdy! positioning is complicated. we haven't even gotten to the new shiny stuff yet! this is all baseline 2001 web development. you had to make an entire website out of only the stuff here. good luck
anyway time for something new and fun: the <details>
element. this is an html5 addition that lets you have a collapsible section. it is the reason i get mad every time i find a fucking FAQ page that only shows the questions because it uses javascript to show the answers. come on. we've got this built in now. also why would you hide the answers by default? this would work fine without god damn javascript if you j
right right okay sure. here it is, with no CSS whatsoever, except a border for clarity:
No one. Pineapples are not native to the ocean floor.
<details style="border: 1px solid gold;">
<summary>Who lives in a pineapple under the sea?</summary>
<p>No one. Pineapples are not native to the ocean floor.</p>
</details>
you can click on the line with the chevron (the <summary>
) to toggle the visibility of its contents. you can also do <details open>
to have it start out opened already.
and that's it, that's the whole thing.
that's cool and all. but it's of particular interest on cohost because it allows us to engage in some manner of shenanigans.
consider the following, which you may click at your leisure.
<details style="position: relative; font-size: 4em; width: 1em; margin: 0 auto; cursor: pointer;">
<summary style="list-style: none;">
<img src="https://lxhom.github.io/mutant-html/assets/svg/smile.svg#generated_with_https://mutant.us.to/" alt="smiling smiley" title="smiling smiley" style="width: 1em; margin: 0; display: block;">
</summary>
<img src="https://lxhom.github.io/mutant-html/assets/svg/angry_steam.svg#generated_with_https://mutant.us.to/" alt="angry_steam" title="angry_steam" style="width: 1em; margin: 0; display: block; position: absolute; top: 0; pointer-events: none;">
</details>
this could be better but i want you to get the idea. here's what is happening.
the details
element has relative positioning and a fixed size. it also has cursor: pointer;
to give people with mice a hint that you can click it.
the summary
element contains a single image. it has list-style: none;
to hide the chevron. (note that this doesn't work in safari. there's a trick to use font-size: 0;
to make the chevron 0 pixels tall, then change the font size back for the actual text, but it complicates things too much for this example.)
the only other child is another image, with position: absolute; top: 0;
. when the details
element is opened, this image now appears overlaid atop the original image.
the second image also has pointer-events: none;
, a funny property that makes it completely invisible to the mouse (as well as touchscreen stuff). so if you try to click it, the click goes through it to whatever's underneath... which is the summary
element. and clicking that makes the second image disappear again.
this perhaps seems a bit simple and clumsy, but it's the secret behind every single clickable css crime you've seen on cohost. anything you can click is a summary
element, and the rest is doing nonsense with toggling visible contents to get the desired effect.
my minesweeper, for example? every cell is a details
, where the part you click is a summary
. the visible contents are whatever part of the grid clicking that cell ought to reveal, absolutely positioned in the right place. it's absurd and it means a lot of duplication, and i had to write a horrible python script to generate it for me, but it works!
going into great detail about how to add some more polish, or do other things that seem impossible even after i've already done them, is probably far beyond the scope of this series. but maybe i'll write up something separate about how my crimes work one day.
well, okay. one more little example to get your gears turning. you can make something that disappears entirely on click:
<details open style="position: relative; cursor: pointer;">
<summary style="list-style: none; position: absolute; inset: 0;"></summary>
<img src="https://lxhom.github.io/mutant-html/assets/svg/cross.svg#generated_with_https://mutant.us.to/" alt="cross" title="cross" style="width: 4em; margin: 0 auto;"/>
</details>
this time, the details
is already open
. the summary
is empty, but it's absolutely positioned with inset: 0;
— which will make it exactly the same size as its (still relative) parent. and then the rest of the contents are the X image.
the summary
is layered on top even though it's earlier, because it's positioned and the X isn't — but the summary
is empty, so it's just a big transparent click zone. and then when you click on it, the X vanishes, the details
collapses to zero height, and the summary
shrinks to match, so the whole thing effectively disappears.
you could even control the size of the summary
to make something that only vanishes when you click a particular area. hmmmm.
that's all she wrote! for now. sorry this took so long; it's kinda dry in places and i've been endlessly busy. hopefully flex/grid will be a bit more fun to explore.
go forth and make some nonsense. be sure to tag it #css crimes
so i see it.
thanks for readin', hope it helps!
oops gotta leave some space for that lost little guy down here
A while ago I tweeted this about Max Payne 2's really nice shadow. This was 2003, remember.
Max Payne in 2 only ever casts one shadow, so it just moves around based on - I guess? - averaging the relevant lights. It's a nice shadow though. A lot of UE3 games did this too, I think including Batman AA?
Luckily, a couple of Remedy folks who worked on the game saw it!
Petri Häkkinen:
Hey, that looks familiar! I wrote the shadow rendering code for Max Payne 2. :) It’s basically a CPU decal with 2 shadow maps, hard and soft, blended together. Direction & intensity is sampled from the radiosity lightmaps. @jaakkolehtinen
wrote the GI system.
Jaakko Lehtinen:
It’s a shame we never talked about this, or the (what I still think is cool) distributed radiosity solver that scales well with scene complexity by breaking things down with portals and mediating radiance between “rooms” with 4D light fields in a 2-level iterative manner. It’s based on a 1st order SH irradiance volume, which is equivalent to an ambient term (DC) and two directional lights, positive & negative, from opposite directions (linear terms). Shadow direction and strength come from the latter: in a uniformly lit spot, the shadow fades away.
EDIT: After I posted this very post you're reading, someone else chimed in!
Peter Hajba:
So, what Jaakko was saying there was that the shadow (light) direction is baked into every point in the rooms where the light is rendered on, so you didn't need to cast any rays to cast the shadow, just look up the direction value from the spot Max Payne was standing on.
Radiosity rendering is pretty neat. Basically it goes onto each point on a surface, looks around to see if there are any lights visible, and then decides if that spot is lit. That's the first pass. Then in the second pass the renderer also sees the lit surfaces with color.
So if there are strongly coloured surfaces, the light applied to each point gets coloured by that. Then you run a third pass and the light bounces a third time, and more, until you have beautiful baked lighting.
We had a little distributed render farm at the Remedy office. Whenever we let our work computers idle, they would start calculating Radiosity lighting on the Max Payne levels.
Thanks Remedy gang!
(this is not vagueposting about any current discourse or aimed at any specific story. I'm making up examples and not mentioning individual authors for a reason)
When assessing how successfully a subject is handled in fiction, whether the story approaches it literally or metaphorically is important. The creator is responsible for signaling this in some way; it'd be pretty disingenuous to write a straightforward heroic arc for a character depicted as an actual historical Nazi and then claim after the fact that it was a symbolic representation of some internal struggle, for example.
On the other end, everyone has seen the reviews/critiques that are like, "How Mystica Starlight Magical Adventures Fails to Grapple with the Real Horrors of War" as though abstraction is a fatal flaw and not a necessary tool when using recognizable conflict as a catalyst for characters' personal growth. It does actually trivialize real horrors to give them a protagonist, but stories transform the unfathomable into the personal. It is more respectful to draw clear lines between the play-pretend you are making up for your own entertainment and others' and things real people have suffered, even if your characters are experiencing realistic emotional fallout.
Some young creators very clearly feel that their fantasy stories need to be allegories for struggles against real-world injustice or else they're being irresponsible, and they end up portraying the most confused, reductive politics imaginable because the premise they find interesting is, "What if there was a really cool girl and she did really cool magic." This is a very sensible premise to spend your creative energy exploring during your brief time on Earth, regardless of whether it addresses the machinery of real-world oppression and the necessity of killing fascists.
I'm not going to say there's no way to gracefully and appropriately combine the two, but your debut novel probably won't be it. It shouldn't have to be. I have seen a few of these that are such products of their time that at worst, future audiences will read them as wildly insensitive "Mary Sue kills Hitler" ego trips despite the total sincerity with which they were written. At best, several of the key points will only make sense if you remember which Twitter discourse they were targeting.
Marginalized writers especially seem to be expected to write the definitive guidebook to revolutionary politics and deliver a stinging rebuke against injustice, but with vampires. They are under pressure to come out of the gate effortlessly weaving literalism into a framework designed for abstraction, and then they can have a little fae ballroom drama and enemies-to-lovers bickering as a treat.
Readers traditionally go to fantasy expecting to see some kind of dream logic or very personal shames and fears painted as larger-than-life archetypal figures. Because that's one of the ways humans process those things safely; that we can pile any kind of fake constructs into a fake arena and make them do fake things that we can banish from existence in the end by saying, "But it didn't really happen" is one of the most powerful tools we have to navigate self-awareness.
Not to beat a dead horse bloody, but Steven Universe addresses concepts like conflict resolution and complex interpersonal dynamics to an age group that experiences recess friendship breakups as epic tragedy and apocalyptic betrayal. Naturally the thematic backdrop of war is resolved by the aggressors learning not to be spiteful jerks rather than being executed for their crimes.
This is probably inevitable at a time when so many people have seen the impact of rampant propaganda with their own eyes, but some people have concluded that nobody can be trusted to interpret a story's meaning on their own. So it follows that if your metaphorical narrative--in which your evil ruler represents a common human failing, or an act of terrible cruelty represents a self-inflicted emotional wound--shouldn't be read literally, then it's irresponsible to write it. Because someone could read it literally, and they might come away from it with the wrong sympathies.
If you believe the purpose of fiction is to make persuasive statements about how real people should act and feel in the equivalent of real situations, then fantasy--or any kind of ambiguous, open-ended storytelling--is inherently suspect. I think media created to accommodate that during this period will seem judgmental, thoughtless, and even regressive in a few years, and I am sympathetic toward the young creators who followed the guideposts they were given at the time. I'm pretty sure most of us write this stuff at some point; most of us do not see it published to high expectations and wild contemporary acclaim.
I don't want to shoot the dog, but I do want to shoot the idea of having a dog in the game to pet.
I know, I know, it's pretty mean of me to pull out a gun and unload a full clip into a completely adorable and wonderfully intentioned little trend even if it IS a little bit annoying, and it's certainly kind of an overreaction, but while I've got this gun out and you're listening would you mind if I made a particular hyperspecific point? I take issue with the idea of putting a dog in the game to pet because I think that's missing the point: if you have a dog in a game, you should be able to pet it.
Do you understand the distinction? The only reason for asking "Can You Pet The Dog?" is because the dog, when present, doesn't give the player any way to interact other than what the player normally has, usually gun. Gun is not the ideal way to interact with dog, and developers tend to forget pet but remember gun because petting a dog doesn't do anything. For player's that's exactly the whole point, that there is no point, and that's kind of mindblowing to me. Like, I spend all day every day trying to make a big digital stage and trick people into believing it's real, and they laugh at your antialiasing and say you need to upgrade your version of the Unreal Engine, and then they'll go on to ask why they can't pet a dog. Isn't that funny? They think they see all the fakeness and seams but at the end of the day the human brain is not immune to seeing a picture of a dog and going " doggie :)"
My best friend and streaming partner Fern loves Bloodborne and Souls games more than anything, and one of her favorite things about these games is the ability to wave and gesture at people. They put emotes in those games because of multiplayer, but you can do them whenever you want. Wave to the Silver Knight shooting arrows at the pillar right in front of you. Wave to the boss through the fog door. Wave to the fire keeper—wait she waved back!
You can't "pet the dog" in Bloodborne (dogs in these games are made of knives, unsafe to pet) but you can "pet the dog" (the doll giggles when you act goofy, like a teenager trying to get a girl to notice her). This fake, inanimate world responds back to the player's attempt to communicate with it, even when there is absolutely no mechanical reason to do, an act of communication between player and world that is delighting in and of itself.
This is the spirit, rather than letter, of petting the dog. It's not about a literal dog that you literally pet. You can find a way to put a dog in the game and you can figure out a way to pet it, but it's not very impressive. What I would like to see is identifying what in the game the player wishes they could interact with, simply for its own sake, just because they believe in the game, believe in it more than you who made it does, and want the game to speak back in a way that validates that belief. That is a much harder dog to pet. But isn't the whole point a lot of work for no real point?
Speaking of, while I've got this gun, I feel the exact same way about fishing minigames. A calming and idle pastime in the middle of a very different kind of game is a great idea, but I think you should pick one that suits what your game is about. Yes, Cruelty Squad does have fishing in it, but the real fishing in Cruelty Squad is the stock market. Think about that while I lower my gun and give you a chance to flee.
Something that has been on my mind lately is the "migration" of files from the Discord CDN. The jumping ship from one transient service to what is just as likely to be another transient service.
The only services I've seen that can actually lay claim to being reliable for longterm hosting are those that host nothing but images. ImgBB's been around the block for a bit, ImgBox claims to have been here for 7 years, and I suppose you could point to Imgur shambling along in its zombified state, ignoring as chunks fall off.
For general file hosting though, it's either services that'll snap shut on your hand and eat your link with no warning (looking at you, Dropbox / Google Drive), don't allow hotlinking, or Catbox and Filegarden. Celestia bless those last two, but I can't help but fear we're a few bad months away from them running out of money and the cycle repeating.
There is another option here. But it requires just a little bit of elbow grease. And maybe some cash. A measly amount for something good, though, I promise.
Sign up for an account at Backblaze B2. They market themselves with "the first 10GB are free," but I find this needlessly simplified. What they truly mean is "the first 10GB of storage is completely free, and also free 1GB of downloads people make."
They do not currently ask you for a credit card when signing up, so that you know they are not waiting to pounce you with a fee the moment you hit that ten gigabyte mark. This makes things simple.
Once you are signed up, click the "create a bucket" button. There will be a link asking you to verify your email on the popup labeled "verify now." Do this now, to save yourself confusion, and then revisit the "create a bucket" page.
Give your bucket a name (it is like a username, it must be that no-one else has used it,) and select "public" next to Files in Bucket are — since you are doing this for the purpose of sharing files with others. Do not touch any of the other options, and head straight to the second "Create a Bucket" button.
Congratulations! You see that "Upload/Download" button next to your new bucket? You can stop reading this guide and just use that. Clicking on it brings you to a list view, and from there you can quite simply upload a file using the "upload" button, click on it in the list view, and then copy that Friendly URL where-ever you want.
However, there's a few things I'd recommend you do purely to make life easier on yourself.
First, if you need to access these files from JavaScript (if that sounds like gibberish to you, ignore this) click on CORS Rules and set it to "Share everything in this bucket with all HTTPS origins."
Secondly, we should set up a way to upload to this without the list view web UI nonsense. Go to "Application Keys" from the main management area, scroll down, and click "Add a New Application Key." Name your key, set it to use your bucket, and ignore all the other settings once more.
Keep the info it shows you in a notepad for just a moment.
I'm going to assume you're a Windows user right now. Install ShareX. Once you have finished installing ShareX, from the window it pops up or rightclicking on it's taskbar icon, select "Destinations -> Destination Settings."
Scroll down in the window it opens until you find "Backblaze B2." Set all the things it asks for based on everything you previously filled out (including bucket name.) Upload path is merely "where in the bucket ShareX places things", choose whatever folder scheme you want. Go back to the "Destinations" menu that you got to the settings from, and set every option to Backblaze B2. It's under the "File Uploader" submenu for images and text.
You can now upload files from your clipboard, from screenshots, and even just by right clicking on them! I invite you to explore the options ShareX offers.
On other platforms, use Transmit (paid, Mac) or rclone (free, everything else). I unfortunately do not have advice for setting these up.
If you're satisfied with this and don't think you'll be uploading any big files or files that get requested a ton of times, like if you're sharing them with just a few people, you can stop here.
...Still with me? Hm.
I'm about to start holding your hand a little less, as once you put in some money, a variety of possibilities open up, all of which I cannot predict you choosing. But I will try to lead you.
Buy a domain name. This site has a good list of where to find cheap ones. Make sure to look at the renewal price and not just go off of the initial buying price.
If you simply must have the cheapest possible domain, try buying one that is all numbers on .xyz, like "10042069.xyz." These all numeric domains cost around $1 and do not have a renewal surcharge, and the only downside is that they look soooo fucking suspicious. Like, I know it's cheap, but you're gonna scare people. Please just accept the possibility of paying like, $10 a year instead of $1 a year. It's yearly, you'll be fine, I promise.
Now, once you have signed up with your registrar of choice, sign up for a free account with Cloudflare1. You'll need to scroll down a bit on the plans page when signing up to see the "free" option, because of malevolent forces we refer to these days as "metrics boosting."
Now, point your domain name at Cloudflare. If you add a domain from their Dashboard, it should mostly walk you through what to do, as long as you can find where to change nameservers on your domain registrar's page.
You can now simply follow this guide instead. Sorry, sorry, I know, but it covers basically everything you need to do.
This entirely removes the download fees and instead allows you to only worry about storage space. I believe you can start deleting stuff if that becomes a problem.
So, you're all set!
...hm, still here?
If you're not scared of paying more money for hosting and weaving your own path, you can use a different service like Linode Object Storage (referral link, gives you $100 for 60 days to mess around with, if you use it it'd make me happy) or DigitalOcean Spaces (not a referral link) to host your files. These'll likely have better uptime, and you'll be able to host more data.
Both start at $5 a month, both grant you 250 GB free in storage for that cost, as well as 1TB of bandwidth used. The only difference in price is that DigitalOcean costs twice as much if you cross the terabyte threshold.
Hopefully this has been enlightening or something I don't know I just kind of put hoof to keyboard and went off.
If you liked it, since you're at the "paying money for services" section, I would like to meekly request you help me with my power bills and groceries either through cashapp or paypal.
I promise I know. You don't have to tell me.
My timeloop RPG In Stars and Time is done! Which means I can clear all my ISAT gamedev related bookmarks. But I figured I would show them here, in case they can be useful to someone. These range from "useful to write a story/characters/world" to "these are SUPER rpgmaker focused and will help with the terrible math that comes with making a game".
This is what I used to make my RPG game, but it could be useful for writers, game devs of all genres, DMs, artists, what have you. YIPPEE
Behind The Name - Why don't you have this bookmarked already. Search for names and their meanings from all over the world!
Medieval Names Archive - Medieval names. Useful. For ME
City and Town Name Generator - Create "fake" names for cities, generated from datasets from any country you desire! I used those for the couple city names in ISAT. I say "fake" in quotes because some of them do end up being actual city names, especially for french generated ones. Don't forget to double check you're not 1. just taking a real city name or 2. using a word that's like, Very Bad, especially if you don't know the country you're taking inspiration from! Don't want to end up with Poopaville, USA
Onym - A website full of websites that are full of words. And by that I mean dictionaries, thesauruses, translators, glossaries, ways to mix up words, and way more. HIGHLY recommend checking this website out!!!
Moby Thesaurus - My thesaurus of choice!
Rhyme Zone - Find words that rhyme with others. Perfect for poets, lyricists, punmasters.
In Different Languages - Search for a word, have it translated in MANY different languages in one page.
Creative Market - Shop for all kinds of assets, from fonts to mockups to templates to brushes to WHATEVER YOU WANT
Velvetyne - Cool and weird fonts
Chevy Ray's Pixel Fonts - They're good fonts.
Contrast Checker - Stop making your text white when your background is lime green no one can read that shit babe!!!!!!
Interface In Game - Screenshots of UI (User Interfaces) from SO MANY GAMES. Shows you everything and you can just look at what every single menu in a game looks like. You can also sort them by game genre! GREAT reference!
Game UI Database - Same as above!
Zapsplat, Freesound - There are many sound effect websites out there but those are the ones I saved. Royalty free!
Shapeforms - Paid packs for music and sounds and stuff.
CloudConvert - Convert files into other files. MAKE THAT .AVI A .MOV
EZGifs - Make those gifs bigger. Smaller. Optimize them. Take a video and make it a gif. The Sky Is The Limit
Press Kitty - Did not end up needing this- this will help with creating a press kit! Useful for ANY indie dev. Yes, even if you're making a tiny game, you should have a press kit. You never know!!!
presskit() - Same as above, but a different one.
Itch.io Page Image Guide and Templates - Make your project pages on itch.io look nice.
MOOMANiBE's IGF post - If you're making indie games, you might wanna try and submit your game to the Independent Game Festival at some point. Here are some tips on how, and why you should.
An insightful thread where game developers discuss hidden mechanics designed to make games feel more interesting - Title says it all. Check those comments too.
Yanfly "Let's Make a Game" Comics - INCREDIBLY useful tips on how to make RPGs, going from dungeons to towns to enemy stats!!!!
Attack Patterns - A nice post on enemy attack patterns, and what attacks you should give your enemies to make them challenging (but not TOO challenging!) A very good starting point.
How To Balance An RPG - Twitter thread on how to balance player stats VS enemy stats.
Nobody Cares About It But It’s The Only Thing That Matters: Pacing And Level Design In JRPGs - a Good Post.
Feniks Renpy Tutorials - They're good tutorials.
I played over 100 visual novels in one month and here’s my advice to devs. - General VN advice. Also highly recommend this whole blog for help on marketing your games.
I hope that was useful! If it was. Maybe. You'd like to buy me a coffee. Or maybe you could check out my comics and games. Or just my new critically acclaimed game In Stars and Time. If you want. Ok bye