/Programming


Learn to develop things, get out of debt, find answers and take part in coding and programming challenges.


Members: 12
Join


Moderated by: mozzapp
up
1
up
pierre44 1794253398 [Programming] 0 comments
Last spring I shipped a landing page that weighed 1.87MB. One page. A headline, a signup form, three screenshots I hadn't compressed properly, and a JavaScript bundle that, when I finally opened the network tab and looked at it the way a stranger would, turned out to be bigger than most of the games I grew up loving. On a throttled connection it took 4.2 seconds before anything useful appeared. I had told myself it was fine. It was not fine. I felt embarrassed, which doesn't happen to me as often as it should. The number 64KB is 65,536 bytes. I first met it as the RAM of a Commodore 64, which is a coincidence only in the sense that every nostalgic programmer's life is full of coincidences like that. But the figure outlived the machine. Somewhere in the demoscene it became a category, the 64k intro, where the whole executable, graphics and music and everything, has to fit under that ceiling. Not 64KB of assets plus an engine. 64KB total. When I say that to younger developers, they nod politely and then ask what the catch is, because in their world nothing is ever just what it says. There isn't a catch. That's the whole point, and it took me an embarrassingly long time to understand why that matters. Start with Elite, because everyone starts with Elite and they're right to. On the BBC Micro it ran in roughly 32KB of RAM, and that memory had to hold the code, the screen, and the working state of a game with eight galaxies and 256 planets per galaxy. Nobody typed those planets in. Braben and Bell generated them from a seed, running a simple sequence to produce names, economies, governments and positions on demand. The universe didn't exist anywhere on the disk. It existed as a procedure that you could re-run and get exactly the same answer every time. I find that more beautiful than any modern open world, honestly, and I say that as someone who has sunk an unhealthy number of hours into a few of those. They actually wanted far more galaxies, if I remember the story right, and cut it back because it felt like too much, which tells you something about taste under pressure that I'll come back to. Maybe. Then there's Super Mario Bros, which on the NES cartridge was about 40KB, split between program code and graphics. The clouds and the bushes use the same tiles, just painted with a different palette. The hills are built from a handful of pieces. Level 1-1 teaches you the entire grammar of the game without a word of text: the first Goomba is placed so that you will almost certainly walk into it and die, and by dying you learn. That's not a design flourish added on top of the limit. It's what a limit produces when talented people are forced to ask what each byte is for. Every tile had to justify itself, so every tile ended up doing two jobs. I typed in a listing from a magazine once, as a kid, and lost an entire weekend hunting a single transposed digit in a DATA statement. I never did learn what the program was supposed to do. Anyway. The 64k intro scene is where this gets properly strange. In 2000 a group called Farbrausch released fr-08, the .the .product, a real-time 3D demo with music, running from an executable of 64KB. Textures were not images. They were sequences of operations: noise, blur, colour adjustments, combined and applied at startup. The music was not a recording but a software synthesizer plus note data, so a few minutes of audio cost a tiny fraction of what an MP3 would. Meshes were built from primitives and modifiers. Then the whole thing was run through a specialized executable packer, and the people who write those packers, Crinkler on the 4KB end and kkrunchy for the larger ones, treat compression as a craft in itself, reordering code so the compressor's model of the data predicts better. That detail still floors me a little. They shape the program to be compressible. What they're doing, in every case, is storing the recipe instead of the meal. And I think that sentence is the most transferable idea in the whole genre, so I'll leave it there for a second. Now the awkward part, which people tend to skip because it spoils the romance. .kkrieger, the first-person shooter from the same family of people, was 96KB, so technically not even a 64k release, and it was famous for a reason that isn't entirely flattering. When you launched it, it spent a long stretch generating its textures and models before you could play, and it wanted a decent amount of RAM to hold the results. The size was real. The cost was moved, not deleted. They bought bytes with seconds and megabytes. I don't say this to diminish it, because the trade was deliberate and the result was astonishing for 2004, but I do say it because I've watched developers read about this stuff and conclude that constraint is free magic. It isn't. A constraint is a decision about where to put the pain. That's the first lesson I'd actually trust. Whatever you're not paying for in one currency, you're paying in another, and the people who ship well under limits are the ones who picked the currency on purpose. Which brings me to the web, and to the part where I get a bit uncharitable. There's a game jam called js13k where you build a browser game that fits in 13 kilobytes zipped. I've watched people make genuinely fun things inside it: platformers, little roguelikes, a few things with real atmosphere. The entries tend to share a look. Few dependencies, because there's no room for any. Lots of code that does one thing well and gets reused. Procedural sound through the Web Audio API instead of audio files. Tiny sprites drawn with canvas calls, or packed into a few strings. Meanwhile, on a project I inherited late last year, I ran a quick count of what was sitting inside node_modules for what was essentially a dashboard with a form and four charts. 1,143 packages. I stopped scrolling around the point where I found three different date libraries, and I'm fairly sure none of the three was there on purpose. Nobody chose that. That's what gets me. No single person sat down and decided the app should carry that much weight. It accumulated through a thousand small, reasonable-looking decisions, each of which cost someone else something invisible. The person who added the second date library saved an hour and never saw the bill, because the bill goes to a user on a mid-range phone four countries away. In the 64KB world there's an owner for every byte. In ours there isn't, and I think that's the structural failure underneath all the talk about bloat. We keep treating it as a discipline problem, as though developers just need to care more. They don't need to care more. They need to be able to see the cost at the moment they make the decision, and be the one who pays it a little. I used to think performance budgets were theater. A number in a config file that somebody sets in a meeting and everybody ignores by the third sprint. Then a team I worked with wired a limit of 170KB of JavaScript into CI, so that a pull request failed if it pushed the bundle over, and for about two weeks everyone hated it. People argued. People found clever ways around it. And then, slowly, the arguing turned into a different kind of question: do we actually need this library, or only one function of it? A few weeks later nobody mentioned the budget anymore, because it had stopped being a rule and become the water they swam in. So I was wrong, or at least half wrong. A budget that fails the build is not theater. A budget that lives in a document is. Still, I don't want to oversell it. There's a real counterargument and I've never been fully able to dismiss it. Hardware is cheap, developer time is not, and nobody should be hand-writing assembly for a CRUD admin panel because a demoscener once made a cathedral out of 64KB. That's true. Mostly. The 64KB crowd are making art under self-imposed rules, and the economics of a normal product are entirely different. A bank's internal tool does not need to fit on a floppy. But I notice that this argument is usually deployed by people whose own phone is two years old and whose connection is good. The user who pays by the megabyte, or who is on a congested mobile network at six in the evening, doesn't experience the framework's convenience. They experience the wait. And the developer-time saving is real once, at build time, while the cost is paid again by every visitor, forever. When I do the arithmetic honestly, the trade rarely favors us as much as we assume. I'm aware that I'm being unfair to the other side here. I don't feel particularly guilty about it. What I'd take from the intros, more than the sizes, is the habit of treating data as something you derive rather than something you store. On the web this shows up in dull, practical ways. An SVG icon is a recipe, a PNG of the same icon is a meal. A CSS gradient replaces a background image that someone exported at 340KB. A handful of variable-font axes can stand in for six separate font files. Generating a color palette from one base value in code, instead of listing forty hex codes by hand, is the same idea at a smaller scale, and it has the side effect of making the design consistent, because the relationships between the colors are now explicit instead of accidental. I found a font file once, a woff that weighed 380KB, loading on a site for exactly one decorative heading that was about thirty characters long. The person who added it was gone. The heading was still there. The font was still there. I removed it and nobody noticed, which is perhaps the saddest sentence in web development. Debugging under these limits is another thing that doesn't get discussed. When you have 32KB or 64KB, there's no room for elaborate logging, no framework error overlays, no tooling that tells you what you did wrong in friendly language. You reason. You hold the program in your head, because it fits there, and when something breaks you already have a suspicion about where, because you know every part of it. I'm not romantic enough to claim that's better than a good debugger. It isn't. But it builds a certain sense of the machine that modern stacks make optional, and then, because it's optional, we skip it, and then we're surprised that nobody on the team can say why the app takes 900 milliseconds to become interactive. On a 6502, a subroutine call costs 6 cycles and the return costs another 6, and people writing tight code in the eighties knew that number in their bones and made decisions around it, sometimes ugly ones. I can't tell you the equivalent cost of a typical React re-render in a given component tree without profiling, and neither can most people I've worked with. I'm not proud of that. I'm also not sure it's possible to hold that much in your head anymore, and maybe that's the real difference. The old machines were small enough to be known. Ours aren't, so we compensate with tools and with trust, and trust is where things leak. There's a taste argument buried in all this too, and I keep circling it without landing. The Elite story, the cut from many galaxies down to eight, suggests that limits don't just constrain the design, they edit it. Somebody had to decide what mattered. In a world without limits, nobody ever has to make that call, so features pile up, and a product ends up as the sum of every meeting where nobody wanted to say no. I've been in those meetings. I've been the person who didn't want to say no. The 64KB mindset, whatever else it is, forces somebody to say no, and says it early, when it's cheap. I'm not claiming everything should be rebuilt small. That would be a sermon, and I distrust sermons, mostly because I've given a few and watched nothing change. What I'd claim is narrower. Pick a number before you start. Make it fail the build. Look at what you're about to import and ask what it costs, and who pays. When you read about a procedural universe or a texture made from noise functions, don't file it under nostalgia, because it's a technique that's still entirely available, and almost nobody uses it for anything ordinary. I went back and fixed that landing page, by the way. Compressed the screenshots, dropped two libraries I'd added out of habit, replaced one chart widget with about forty lines of my own code. It came down to 214KB, and first content showed up in under a second on the same throttled connection. Conversions barely moved. A small bump, within the noise, not the triumphant graph I'd imagined while I was working on it. That annoyed me more than I expected, and I still haven't entirely decided what it means. Maybe the fix was right and the metric was wrong. Maybe I did it for me, and for the version of me who once spent a weekend chasing a transposed digit in a magazine listing. Either way I'd do it again. The page is just better to know.

A social news and discussion community