Back to Supersonic RC Revive
SOURCE / PINNED RELEASE

Made of little things.

Supersonic RC Revive

Release
1ba42f1ca1d6…
Author-recorded commit
baecad10b1cd…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-143146b0d6f

Archive hash verified: 90d22b206672eba4…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

soy-assets.js
// Generated by soyLI. Edit napplet.assets.json through soyli assets or the manager.

const assets = {"game-pack": {hash: "9b828ff319aca0630b52864141cf9c3f7a332c78e6db9d4e2cb3e19371de0f39"}};
const blobs = new Map();
const urls = new Map();
function assetEntry(id) {
  const entry = Object.hasOwn(assets, id) ? assets[id] : undefined;
  if (!entry) throw new Error('Unknown asset: ' + id);
  return entry;
}
function embeddedBlob(entry) {
  const comma = entry.url.indexOf(',');
  if (!entry.url.startsWith('data:') || comma < 0)
    throw new Error('Embedded asset is not a data URL. Rebuild with the single-file plugin.');
  const data = entry.url.slice(comma + 1);
  let bytes;
  if (/;base64$/i.test(entry.url.slice(0, comma))) {
    bytes = Uint8Array.from(atob(decodeURIComponent(data)), char => char.charCodeAt(0));
  } else {
    bytes = new TextEncoder().encode(data);
    let length = 0;
    for (let offset = 0; offset < bytes.length; offset++) {
      if (bytes[offset] === 37) {
        const hex = String.fromCharCode(bytes[offset + 1], bytes[offset + 2]);
        if (!/^[a-f0-9]{2}$/i.test(hex)) throw new Error('Invalid embedded asset data URL.');
        bytes[length++] = parseInt(hex, 16);
        offset += 2;
      } else bytes[length++] = bytes[offset];
    }
    bytes = bytes.subarray(0, length);
  }
  return new Blob([bytes], { type: entry.mime });
}
/** @param {string} id */
export async function assetBlob(id) {
  const entry = assetEntry(id);
  if (!blobs.has(id)) {
    const pending = Promise.resolve().then(() => entry.url
      ? embeddedBlob(entry)
      : window.napplet.resource.bytes('blossom:sha256:' + entry.hash));
    blobs.set(id, pending);
    pending.catch(() => { if (blobs.get(id) === pending) blobs.delete(id); });
  }
  return blobs.get(id);
}
/** @param {string} id */
export async function assetUrl(id) {
  const entry = assetEntry(id);
  if (entry.url) return entry.url;
  if (!urls.has(id)) {
    const pending = assetBlob(id).then(blob => URL.createObjectURL(blob));
    urls.set(id, pending);
    pending.catch(() => { if (urls.get(id) === pending) urls.delete(id); });
  }
  return urls.get(id);
}
export function releaseAssetUrls() {
  for (const value of urls.values()) value.then(url => URL.revokeObjectURL(url)).catch(() => {});
  urls.clear();
  blobs.clear();
}