An opaque byte payload. Every byte-producing API returns one; every byte-consuming API accepts one. Decoders raise on failure. A decoder that suspends returns its result ready to use; the others return an asset handle at once, which :ready() awaits.
Read file-backed bytes into memory now, then return the same handle for chaining. In-memory bytes return at once; decoding bytes read this way does not read the file again. Raises if the read fails.
Parse the bytes as KDL into a table. Each node becomes the key named after it, and sibling nodes that share a name become an array of their values, in order. A node with no values and no children reads as true; one with a single value, positional or a property, reads as that value. A node with several positional values and nothing else reads as an array of them. Any other node reads as a table holding its positional values at 1, 2 and so on, its properties under their names, and its children by these same rules. Type annotations, comments, ordering and layout do not carry over. Raises on parse failure or non-UTF-8 input.
Example
local text = [[title "Notes"tags "birds" "trees"fullscreenwindow width=800 { font size=14; }plugin "maps"plugin "notes"]]local cfg = datumhue.bytes(text):kdl()
print(cfg.title, cfg.tags[2], cfg.fullscreen) --> Notes trees trueprint(cfg.window.width, cfg.window.font) --> 800 14print(cfg.plugin[1], cfg.plugin[2]) --> maps notes
Decompress zlib-format bytes. Raises when they are damaged, cut short or fail their checksum, or would unpack to more than max_size bytes.
Example
local packed = datumhue.bytes.zlib("hello, hello, hello")
print(packed:zlib():text()) --> hello, hello, hello-- A cap refuses data that would grow too large.local ok = pcall(function()
return packed:zlib({ max_size = 5 })
end)
print(ok) --> false
Decode the bytes as base64 in either alphabet, padded or not, skipping ASCII whitespace. Raises on any other character, or when the text stops partway through a byte.
Compile the bytes as a fragment shader (WGSL, or WESL extended syntax) defining fn dh_fragment(uv: vec2<f32>) -> vec4<f32>. The source may read dh.time, dh.resolution, and dh.mouse (set for each primitive the shader draws), the declared u.<name> uniforms, and the dh_channel0..3 textures. Raises with the failing source line on a compile error. The returned shader applies anywhere a preset does; on a 3D mesh uv is the mesh's texture coordinate, and the mesh shows the returned color as it is, unlit, or, as the shader of material.standard, as a base color the scene lights. Limits per shader: 64 KiB source, 16 uniforms, 4 channels, 127 nested blocks and 255 chained operators and brackets; up to 32 live custom shaders per app.
Table of name = initial declarations the source reads as u.<name>. A number declares an f32, a vec2/vec3 its vector type, a color a vec4<f32>. Capacity 16. A value that is not a table declares none.
channels
table
every channel samples white
Array of up to 4 texture sources (pixel canvas, draw canvas, or scene) bound as dh_channel0..3; unset channels sample white. A value that is not a table binds none.
Parse the bytes as a one-chapter book: Markdown prose with elements in kdl fences, or a KDL page (chosen by content). Bytes have no directory to load from, so scripts never run, an image shows its alt text in italics, as [image: alt text], one with no alt text is left out, and include raises. A page from outside the app, such as a package's readme, should be loaded with templates off. Raises on parse or validation errors.
Example
count = 3local page = "# Notes\n\nThere are {{ count }} notes.\n"-- The page is the app's own text, so its templates may run.local book = datumhue.bytes(page):book({ templates = true })
print(book.title, book.pages) --> Notes 1
Run the page's {{ }} templates and its if and for elements as Lua in the app's globals, on every render. With templates off, {{ }} in prose shows as written, and an if, a for or a property that holds a template raises at load.
Decode the bytes as an image in whichever format they hold (PNG, JPEG, WebP, etc.). Raises if the format is unsupported or the bytes cannot be decoded.
Decode the bytes as a KTX2 cubemap (6 faces) for use as a skybox or environment map. Raises if the bytes are not a KTX2 cubemap; to build one from a vertically-stacked 2D image use image_asset:to_cubemap() instead.
Decode the bytes as WAV or Ogg Vorbis audio, in the background: :ready() waits for it, and a clip longer than 10 seconds is ready once its start is, the rest decoding as it plays. In-memory bytes that are neither raise here; a file that is neither, or audio that does not decode, leaves the asset's .state failed, and playing it raises.
A wavetable from the bytes: 2..4096 bytes, each an unsigned level 0..255 held for an equal share of the cycle, the mean removed, played as steps with no interpolation. Any other length raises.
Example
-- Each byte is one level of the cycle, from 0 (lowest) to 255.local steps = datumhue.bytes(string.char(0, 255, 160, 96, 255, 64))
local wave = steps:wavetable()
datumhue.audio.synth({ waveform = wave, frequency = 110 })
Decode the bytes as a font face (TrueType or OpenType). Set it as a text surface's font, as datumhue.font.default, or a fallback via datumhue.font.fallback. Raises at decode if the bytes are not a TrueType/OpenType font (WOFF/WOFF2 are not supported); the returned face is ready at once.
Decode the bytes as a 3D scene (glTF). A scene's buffers and textures load from the files beside it, so the bytes must come from a file or directory grant — decode via file:read():scene() or dir:read(rel):scene(). Bytes lifted from a string raise.
Parse the bytes as a Fluent (.ftl) localization catalog for one locale (declared by its -datumhue-locale term). Returns an Ftl to set as datumhue.i18n.locale. Raises on a missing/invalid locale term or a Fluent syntax error.