Monday, May 12, 2025

Web: Packaging assets to a binary the web way

We have a game in html with a bunch of images and sound effects. Instead of having a bunch of requests, we want to package all the asset files into a single binary, download it and extract the files. Something like tar/zip but... been there done that.

So lets follow the ancient philosophy of a header and payload. To be more exact: magic bytes, version, header length, (for each file) path size, path, file size and all the file contents concatenated in the end.

Lets use 4 byte integers for all to simplify life, and we have the ArrayBuffers and DataView ready to implement a C struct like parser.

Ok lets start with the magic bytes.... but wait a second this is the web, is packing bytes really the thing that we need? I mean just downloading the file will take couple of orders of magnitude of time more than parsing it. So lets do the exact opposite of packing bytes: lets do JSON!

Lets put all the header data in a JSON object and then we have: magic bytes, header size, JSON dump, file contents. Yeah... but it could be nice to just have the JSON object and then the file contents.

What is the most used operation in the world of js: split once. All we need is a delimiter, what is never used in a JSON object: all the non printable characters, lets take the first the null byte (0x00).

So we have it: JSON header object, byte 0x00, file contents.

Which if you think about its agnostic to the actual content, you can put whatever you like in the header and whatever you like in the binary part.

I shall name it JHBF (json header binary file).



done_

Saturday, May 10, 2025

Javascript: Unexprected Symbol.iterator

Lets validate some data, and lets do some smart checks with a unknown random schema. Lets same why wnat to check internal id references, and of course internal ids wil be in iternal things, lets assume arrays for now:

for (collection of Object.values(data)) {
  for (i of collection) {
    for (field of Object.values(i)) {
      for (item of field) {
        // check item.id
      }
    }
  }
}

But someone decided to wrap arrays into classes because, lets be honest, pure json inside js never stays pure. So lets check the iterator symbol magic:

for (field of Object.values(i)) {
  if (!field[Symbol.iterator]) continue;
  for (item of field) {
    // check item.id
  }
}

Perferct, but wait... why the item takes values of single letter strings. Oh wait, dont tell me that this is a thing:

"test"[Symbol.iterator]

Yes it is, so lets add it to the condition:

typeof field === "string" || !field[Symbol.iterator]



done_

Wednesday, April 16, 2025

Techniques: Dev inplace replacement code

You have your utils.js with the classic document.querySelector shortcut:

function q(selector) {
    return document.querySelector(selector);
}

Lets say that the "assertion" is that this should be only called when we know the selector will always match a single element (for the other cases we simply call other functions)

We leave this "efficient" version, and we replicate the an error checking version of it in a new file utils.dev.js:

function q(selector) {
    const res = document.querySelectorAll(selector);
    if (res.length == 1) return res[0];
    throw `Found ${res.length} matches for '${selector}'`;
}

And then in the "build system" we specify one of the files based on the release mode.



done_

Monday, April 7, 2025

Web: Bundle and deploy with php and make

 We want to put all the things into a single index.html and then uploaded. We just:

index.html: index.php $(shell find src -type f)
    php index.php > index.html

upload: index.html
    cp index.html /run/user/1000/gvfs/ftps:host=[website]/project/
    touch upload

We dont have php in the server, we just use php to bundle all the html, js and css files into one file using php statements like this:

    <style>
    <?php foreach (glob("src/*.css") as $i) include $i ?>
    </style>

And then we let make file generate the index.hml and we upload to our server with a cp (linux things) when changes have been made



done_