Back to Outbreak: Soycoon City
SOURCE / PINNED RELEASE

Made of little things.

Outbreak: Soycoon City

Release
db7750b1d009…
Author-recorded commit
3ee3f5fd27a6…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b87c04571a9

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

scripts/check-audio.mjs
import assert from 'node:assert/strict';
import { readFile, readdir } from 'node:fs/promises';
import { createHash } from 'node:crypto';
const manifest=JSON.parse(await readFile('sounds/runtime.json','utf8'));
const planned=JSON.parse(await readFile('sounds/demo.json','utf8'));
const hash=bytes=>createHash('sha256').update(bytes).digest('hex');
assert.equal(manifest.schema,'soyindent.runtime-audio');assert.equal(manifest.version,1);assert.equal(manifest.status,'playable-audition');
const paths=new Set();let total=0;
for(const cue of manifest.sounds){
  const target=planned.sounds.find(s=>s.id===cue.id);assert(target);assert.equal(cue.loop,target.loop);assert.deepEqual(cue.mix,target.mix);
  for(const file of cue.files){
    assert.match(file.path,/^src\/audio\/runtime\/[a-z_]+-v\d\d\.mp3$/);assert(!paths.has(file.path));paths.add(file.path);
    const bytes=await readFile(file.path);assert.equal(hash(bytes),file.sha256);assert.equal(bytes.length,file.size);
    const provenance=file.provenance;assert(provenance);assert(manifest.sources.includes(provenance.manifest));
    const batch=JSON.parse(await readFile(provenance.manifest,'utf8'));assert.equal(batch.status,'mp3-only');
    const candidate=batch.cues.find(c=>c.catalogueId===cue.id)?.files.find(f=>f.providerResultNumber===provenance.providerResultNumber);
    assert(candidate);assert.equal(candidate.path,file.path);assert.equal(candidate.sha256,file.sha256);assert.equal(candidate.bytes,file.size);
    assert.equal(candidate.downloadProvenance.sha256,provenance.downloadSha256);assert.equal(candidate.reviewProvenance.sha256,provenance.reviewSha256);
    assert.equal(file.mime,'audio/mpeg');assert(file.durationSeconds>0);assert(file.gainDb<=36);total+=bytes.length;
  }
}
assert.equal(paths.size,33);assert.equal(manifest.sounds.length,11);assert(total<1024*1024);
for(const id of ['shotgun_fire','shotgun_pump']){
  const cue=manifest.sounds.find(sound=>sound.id===id);assert(cue,`${id} must be playable`);
  assert(cue.files.every(file=>file.provenance.manifest==='sounds/shotgun-revision/manifest.json'),`${id} must use the new batch`);
}
assert.deepEqual(new Set((await readdir('src/audio/runtime')).map(f=>'src/audio/runtime/'+f)),paths);
console.log(`PASS ${paths.size} MP3 clips, ${total.toLocaleString()} bytes, runtime hashes and retained provenance`);