Use the shortest path that matches the asset
- Drop the source.BIN, PSG and other arbitrary files enter as continuous bytes. BMP, PNG and SC5–SC8 files enter as native image pixels.
- Check the interpretation.For images, verify Screen mode, packed bytes per line and line count. For raw BIN input, geometry must exactly match the data size.
- Select compressors.Recommended runs the active formats. Select all also measures the slower v4.3 historical comparison.
- Run and choose a result.Every candidate is browser-decrunched and compared byte-for-byte before it is offered.
- Download data and code.Choose RAM, RAM-tail, buffered VRAM, linear VRAM or direct VRAM, then use the matching generated or reference source.
Drop it on the compressor. The page automatically switches to decrunch mode and verifies the recovered bytes locally.
The file type and the data model are separate choices
Continuous data treats every byte as part of one stream. Use it for code, maps, text, sound, Screens 1–4 data and any image whose rows should be joined without a rectangle rule. Image modes preserve row geometry so v5.5 can test whole-line offsets and the generated decoder can write an exact rectangle.
128 bytes256-pixel images128 bytes512-pixel images256 bytes512-pixel images256 bytes256-pixel imagesNative BMP/PNG import removes the file header, palette records and row padding, then converts pixels to the selected MSX packing. A valid seven-byte BSAVE header in SC5–SC8 is detected and removed. Changing Screen 5/7 after importing an image does not silently change the imported packed width.
Smallest verified file wins—within the selected routes
Includes the CBS header
The displayed and downloaded size is the complete packed file, not payload only.
Round-trip proof
The JavaScript decoder reconstructs the source and compares every byte before a result can win.
Same image payload
For a paired image result, only destination bits change. Recompression is not required.
Measured baseline
The proven older aligned-cost engine remains available for comparison and legacy integration.
The three-byte v5 header plus token and EOS bits can exceed a very small uncompressed file. The result table reports the real total.
One byte selects format, variant and destination
Linear files use bytes 1–2 for the complete packed-file length in little-endian order. Image destinations 3 and 5 instead use byte 1 for packed NX and byte 2 for NY; zero represents 256. CBS v4.3 is separate and keeps its established 24-byte CB5 container.
00h / 80hv5.2 compact pairRAMTwo CBS offset representations01h / 81hv5.2 compact pairRAM-tailSame payload, safe relocation route40h / 48hv5.3 / v5.4RAMCombined state-flow decoder41h / 49hv5.3 / v5.4RAM-tailMeasured in-place tail route42h / 4Ahv5.3 / v5.4Linear VRAMTiles, fonts and screen streams43h / 4Bhv5.3 / v5.4 imageBuffered VRAMRAM stage, then HMMC45h / 4Dhv5.3 / v5.4 imageDirect VRAMCPU, HMMM and HMMV backendC3h / C5hv5.5 line-awareBuffer / directIdentical payload after byte 0The selected/generated decoder supplies the reader for RAM, plain ROM or one cartridge mapper. This keeps every data file smaller and avoids carrying unused mapper choices in a game.
Literals establish bytes; matches repeat history
A v5.3/v5.4 stream begins with an interlaced-gamma literal length, followed by those literal bytes. After a literal, one control bit selects a previous-offset match (0) or a new offset (1). After a match, 0 returns to literals and 1 selects another new offset. A previous-offset match saves the complete offset code.
gamma length + raw bytes
gamma match length; reuse the saved negative distance
distance representation + first match-length control bit
Interlaced gamma value
value = 1
while GET_BIT() == 0:
value = (value << 1) | GET_BIT()
return valueThe general distance stores a complemented negative offset. For a positive look-back distance d:
high = floor((d - 1) / 128) + 1
low = (d - 1) % 128
packedLow = (127 - low) << 1 | firstLengthControlBitv5.3 reserves general offset-high 256 as EOS. v5.4 adds one selector before every new distance: 0 codes near distance 1–15, while 1 uses the complete general representation. v5.5 uses its selector for a whole-line distance or the general compact representation.
Sixty bytes become eleven
The verified v5.4 result for ABC repeated twenty times is:
48 0B 00 71 41 42 43 50 3A AA AC48headerv5.4 adaptive-near, linear RAM destination
0B 00packed length11 bytes total, little endian
logical token 1literal 3raw bytes 41h 42h 43h = “ABC”
logical token 2new distance 3copy 57 bytes from the already reconstructed ABC sequence
finishEOSthe impossible general offset-high value ends the stream
Control bits, literal bytes and offset data share the payload, so the remaining hex bytes do not each correspond to one complete token. The logical sequence is the reliable way to read it.
The low three bits say what the decoder must do
Linear RAM
Normal forward reconstruction.
RAM-tail
Relocate packed bytes to the destination tail, then expand.
Linear VRAM
Continuous VDP memory using the current Screen physical width.
Buffered image
Expand into RAM, then upload an exact NX × NY rectangle.
Hybrid
Reserved for a proven row/chunk backend.
Direct image
Reconstruct with CPU writes and VDP commands.
Mapped RAM
Planned MSX Memory Mapper destination.
Normal output or measured destination-tail reuse
The combined v5.3/v5.4 RAM decoder accepts the complete three-byte header at HL:
LD HL,PACKED_DATA
LD DE,OUTPUT_BUFFER
CALL CBS_V5354_RAM_TO_RAMv5.2 uses CBS_V52_RAM_TO_RAM. CBS v4.3 has its own compatible source because its container and token grammar predate v5.
Generic RAM-tail entry
LD HL,PACKED_DATA
LD DE,OUTPUT_BLOCK
LD BC,UNPACKED_SIZE
CALL CBS_V5354_RAM_TAILThe generated per-file wrapper stores the unpacked size as CBS_FILE_RAM_TAIL, so a game normally supplies only HL and DE. The routine copies the packed file backward with LDDR to the end of the destination block, then performs the usual forward expansion.
The compressor checks every write position against unread packed input. An unsafe file is never offered as a tail build. This is the corrected replacement for the old four-byte-margin assumption.
This is useful when a title screen can temporarily reuse map RAM, or when packed bytes are copied to the end of a buffer before the original content is needed. The compact decoders intentionally do not carry corrupt-stream bounds checks; use them for trusted game-built assets.
One public interface, several delivery backends
The generated image binary exposes three stable entry points:
E000hCBS_INIT_MSXDetect and patch the real MSX VDP ports.
E003hCBS_INIT_SCREENSupply Screen mode 5, 6, 7 or 8.
E006hCBS_DECRUNCHDecode the selected buffer, linear or direct route.
CALL CBS_INIT_MSX
LD A,7
CALL CBS_INIT_SCREEN
LD HL,PACKED_IMAGE
LD DE,(PACKED_X << 8) | Y
LD A,VRAM_PAGE << 2
CALL CBS_DECRUNCHFor image routes, D is the packed X byte and E is Y, making DE = XY. A bits 3–2 select the VRAM page. HL points to the three-byte CBS header. IX is required only by the buffered route and points to its RAM stage.
RAM stage + HMMC
Expand the complete image in RAM, then upload the exact packed width × height rectangle. The exact byte count ends HMMC naturally.
v5.3/v5.4/v5.5 direct VRAM
Literals use the CPU VRAM port, matches of one to eight bytes use a dedicated RAM buffer, longer matches use HMMM, and long offset-one runs use HMMV.
Tiles and fonts
Write a continuous stream while respecting the physical Screen line width; no NX × NY rectangle is required.
Wait only when needed
VDP-to-VDP commands must finish before the next command. CPU data may be sent through the normal VRAM port while a different command area is active.
Which delivery route should I use?
directbuffereddirectmixedGenerate the mixed decoder for the game's one cartridge mapper, then choose Buffer or Direct independently for every image. Use the standalone direct decoder when the project never needs destination 3; it avoids carrying the buffered backend.
Initialize the VDP interface once
After copying the decoder into writable RAM, call CBS_INIT_MSX once before displaying the first image. It reads the BIOS VDP data-port values from 0006h and 0007h, then patches every immediate CPU-transfer, status and indirect-command port operand. The same decoder therefore works when a machine's VDP ports differ from the standard 98h–9Bh addresses.
The direct backend uses a dedicated eight-byte RAM buffer for non-overlapping matches of one to eight bytes. Larger matches use HMMM, while long offset-one runs may use HMMV. This buffer is decoder working memory; it does not require another initialization. Call CBS_INIT_SCREEN initially and again whenever the Screen mode changes.
Direct matches are divided at destination-row boundaries, source-row boundaries and overlap limits. The one-to-eight-byte scratch threshold and the 64-byte fast-fill threshold belong to the decoder, not the packed format, so they can be tuned without recompressing the image. A size-focused build restricted to the standard VDP ports may hard-code them and omit CBS_INIT_MSX; the supplied source retains portable initialization.
One mapped decoder handles buffered and direct images
The Screen 5–8 generator compiles exactly one reader for ASCII8, ASCII16, ASCII16-X, Konami or Konami SCC. The game supplies HL as the exact address in the mapper window and BC as the initial bank. The reader detects the active window, patches its fast path and advances banks whenever HL reaches the boundary.
A file may cross consecutive ROM banks. The generated reader makes that transition while the token decoder continues normally.
The website demonstration keeps page 0 for startup and code, starts packed assets on page 1 by default, runs the decoder at E000h and mapper control at F500h, and leaves 8000h–DFFFh as a 24 KB buffer. Its multi-screen ROM and export table are visualization tools; the CLI intentionally generates only one-image test ROMs. In a mixed ROM, destination 3 expands into the shared 8000h–DFFFh stage and uploads with HMMC; destination 5 reconstructs directly in VRAM. The same E000h/E003h/E006h decoder entries dispatch both routes. For a fair visual comparison, the demo controller sets the border and backdrop to the darkest available palette colour and clears the complete Screen 5–8 VRAM page with HMMV before each image. It waits for the command to finish while restoring status register 0 between CE checks, allowing normal MSX interrupts, and holds the completed black clear for one video frame before starting the decoder. Buffered output appears only after RAM expansion; direct output can be watched as it is reconstructed in VRAM. The harness also disables sprites after each Screen-mode initialization. This prevents stale sprite attributes from appearing over test images and leaves more VDP time available to the decoder.
Cartridge ROM mapper input is implemented for buffered and direct Screen 5–8 output. Output into selected MSX Memory Mapper RAM segments is still planned.
The website engine without the browser UI
Requirements: Python 3.10+, Node.js 22+, and Pillow only when importing BMP/PNG.
# Recommended continuous-data compressors
python cbs_cruncher.py game.bin
# Include every comparison, including v4.3
python cbs_cruncher.py game.bin --compressors all
# Build a measured RAM-tail result
python cbs_cruncher.py game.bin --ram-tail
# Screen 7 image and a one-image test ROM
python cbs_cruncher.py picture.png --mode 7 --rom
# Linear Screen 5 VRAM data
python cbs_cruncher.py tiles.bin --linear-vram-screen 5 --rom
# Decrunch an existing CB5 file
python cbs_cruncher.py packed.cb5 --decompressRun python cbs_cruncher.py --help for the exact mapper, geometry, search-window and output switches in the current package.
Most failures are geometry, route or host limits
For raw BIN input, packed bytes per line × line count must equal the file length. A seven-byte SC5–SC8 BSAVE header is removed only when valid.
Large image searches are expensive. Use the recommended 2 KB window first; the progress bar shows the current engine and measured work.
Use the local WebMSX button. CBS Cruncher opens a dedicated player tab and transfers the full ROM through browser memory, so 128 KB cartridges do not enter the address bar and are never uploaded. The player selects Japanese MSX2 NTSC and applies the chosen mapper format automatically.
The exact overlap trial found that unread packed bytes would be overwritten. Use normal RAM output or a different destination block.
Use imported palette data where available and test with the Japanese MSX2 NTSC machine; regional default palettes can differ.
The small game decrunchers trust their input and omit defensive bounds checks. Verify files with the browser or CLI before placing them in ROM.
Finish missing delivery paths only when they solve a real asset
- MSX Memory Mapper RAM output.Define the destination-6 contract, selected segment/window parameters and safe crossing between RAM segments.
- Cartridge-ROM to ordinary RAM.The mixed Screen 5–8 reader is complete; a future compact-data route may reuse it for code, maps or other linear RAM destinations.
- Optional hybrid image path.Destination 4 remains reserved for row/chunk history or another mixed strategy only if measured game data justifies its code.
- More game validation.Continue code-size and speed tuning against real maps, tiles, fonts and Screen 5–8 assets without changing verified payloads unnecessarily.
CBS v5 keeps spare destination and variant values so experiments do not force another container redesign. Only implemented routes are shown as downloadable winners.
Use the smallest source set your game needs
← Return to the compressor or review the dated project history.