Topics

UTTORI ASM ยท IN DEVELOPMENT

Standalone asset conversion

Convert supplied PNG, WAVE, and data bytes to exact native outputs or explicit lossy BRR audio.

@uttori/asm-assets converts supplied bytes without an assembler, ROM, or filesystem. It works in Node and browser workers through the same synchronous registry API. The optional ./node entry point adds file reads and coordinated replacements.

import { AssetRegistry, convertAsset } from "@uttori/asm-assets";
import { pngImporter, withImageEncoders } from "@uttori/asm-assets/image";
import { snesNativeEncoders } from "@uttori/asm-assets/snes";

const registry = new AssetRegistry().registerImporter(pngImporter);
for (const encoder of withImageEncoders(snesNativeEncoders)) registry.registerEncoder(encoder);
const result = convertAsset(registry, {
  source: { bytes: pngBytes, mediaType: "image/png" },
  format: "snes.tile.4bpp",
  options: { layout: { tileOrder: "row-major" } },
});
const tiles = result.outputs.tiles.bytes;

PNG conversion returns named tiles, palette, tilemap, and raw RGBA preview outputs. Indexed PNGs keep their palette and index identity; truecolor/grayscale inputs need an exact external palette or palette: "auto". Colors, alpha, dimensions, and layouts outside the selected native format are rejected. Native output reconstructs the imported pixel values and index information, not the original PNG container bytes.

Register waveImporter and withAudioEncoder from ./audio for mono PCM8/PCM16 WAVE-to-snes.brr. The result records sample rate, counts, loop and error measurements with lossy-audio fidelity, and includes decoded reviewWav bytes. It never promises PCM equality. Lossless byte transforms, including game compressors, must still decode to their exact input.

Indexed authoring helpers in ./image preserve palette index identity rather than matching colors. extractIndexedRegion(), renderIndexedPlacements() and expandIndexedGrid() handle explicit rectangles, flips and index mappings. rewriteIndexedPng() preserves palette slots and no-op bytes; palette-only edits preserve compressed IDAT data. Imports reject animated/16-bit PNG and are bounded to 16 MiB input, one megapixel, 5 MiB inflated scanlines and 16,384 chunks.

./aseprite, ./interchange, ./raster-interchange, ./indexed-ownership, ./animation-evidence and ./limits provide bounded saved-file presentation, native-owner reconciliation and measured previews. Aseprite structure conversion uses asynchronous browser compression streams. Saved Aseprite/PNG editing describes export, review and application authority; presentation geometry and native animation timing remain read-only.

applyAssetFileChanges() from ./node validates exact before/after snapshots, stages replacements and rolls back an ordinary publication failure without overwriting later edits. It is not crash-atomic and does not allocate ROM space. Source-project hosts add journaled recovery and complete dependency checks around saved asset application.

The package README lists limits, layouts, and standalone examples. See source inclusion and plugin registration.