Skip to content

Resources, images & sound

Name the thing you made. Let the runner decide how this machine should carry it.

A picture is not a pointer. A sound is not a device register. In D/BASIC, media begins as a logical resource identity inside the application package. The runner resolves that identity to bytes it has validated, chooses the richest representation it can honestly present, and keeps the loaded form close to the renderer or audio device.

That is how the same poster can be true colour in a browser, indexed colour on a classic composed head, and legible monochrome on a one-bit display—without three editions of the program.

Resources are package members

A resource name such as asset://dwrite/cover-1 identifies a package member. It is deliberately not:

  • a path on the developer's laptop;
  • a borrowed address in process memory;
  • a browser URL fetched behind the user's back; or
  • a native image, font, or sound object smuggled into D/BASIC state.

The package binds the logical name to exact bytes, media metadata, a content digest, and any alternate representations. The runner validates that binding before the program can use it.

Here is a document-owned image reference using the standard D/Works media model:

IMPORT dworks.document_media

DIM Cover AS WorksDocumentImage
Cover = NEW WorksDocumentImage("image.cover.1", "Embedded image", "asset://dwrite/cover-1")
Cover.SetDocumentBounds 24, 32, 128, 72

PRINT Cover.Caption
PRINT Cover.AssetReference
END

StableId belongs to the document. AssetReference belongs to the package/resource boundary. Keeping those identities separate lets a document move or resize an image without pretending that a host path is document data.

The load-once rule

LOADRESOURCE is the runner operation beneath an owning D/Works media adapter. The adapter supplies the logical name; the runner associates an opaque lease with that adapter's app-owned identity. D/BASIC code never has to declare, copy, inspect, serialize, or persist the lease itself—and neither a TYPE nor a CLASS field can hide one.

Keep the source-facing adapter object, such as WorksDocumentImage, alive for as long as the media is useful. Its first load resolves the asset; later paints reuse it; assigning the last owning reference to NOTHING or closing the application releases the host state. Do not construct a fresh adapter on every DRAW turn. On a D/OS machine with a pool or cart-side compositor, the important result is that a loaded asset does not cross the bus again; later frames carry a compact resource-and-geometry request.

The failure cases are named:

Situation Result
logical name is absent NotFound
package bytes or digest are wrong Integrity
no representation can preserve the contract Unsupported
the resource store cannot be read Io

Required resources are preflighted before visible output. A program does not draw half a screen and discover that its other half never existed.

Images: one identity, several honest forms

A package may carry multiple variants of one logical image:

Representation What it carries Natural home
Mono1 one bit per pixel monochrome and memory-tight heads
Indexed4 packed 4-bit pixels plus a 16-entry RGB565 palette palette-oriented classic heads
Rgb565 direct 16-bit colour compact colour compositors
Rgb565A1 RGB565 plus one-bit transparency sprites and shaped artwork

The runner chooses the richest compatible form in the order Rgb565A1Rgb565Indexed4Mono1. Every variant keeps the same logical geometry. If the route supports scaling, the default is aspect-fit inside the requested rectangle; if it does not, the runner centers the intrinsic image at 1:1 and clips honestly.

Colour lowering is presentation, not application logic. A monochrome route may use deterministic luma and pattern cues; an indexed route may choose its declared palette mapping. It may not reinterpret which image was requested.

Packaged images versus caller pixels

These are related but different jobs:

  • a packaged resource is resolved once by logical identity and stays pool/renderer-side; and
  • GFX.BLIT_RESOURCE draws a bounded raster supplied in a D/BASIC array for generated pixels, small masks, and conformance work.

The raw form names every fact needed to interpret the carrier:

DIM Checker%(0 TO 7)

Checker%(0) = 170
Checker%(1) = 85
Checker%(2) = 170
Checker%(3) = 85
Checker%(4) = 170
Checker%(5) = 85
Checker%(6) = 170
Checker%(7) = 85

' Pixels, x, y, width, height, format, stride, foreground, background
INTENT GFX.BLIT_RESOURCE(Checker%(), 24, 24, 8, 8, 0, 1, -1, 0)
END

That example uses format 0 (Mono1) and one byte of stride. The unfortunate historical word “resource” in BLIT_RESOURCE does not make the caller array a package asset. Use the package loader when the same art will appear again.

Fonts are resources with semantic jobs

D/BASIC text chooses a font role, not a host font filename:

Role Meaning
0 UI
1 UI Small
2 Native Mono
3 UI Chrome

A rich runner can upgrade those roles to real browser or desktop outlines, rasterized at the display's density. A constrained runner can lower them to its hinted resident face. The advance, line box, clip, and coverage contract remain stable, so changing the rasterizer cannot move a text-field caret or alter hit testing.

The browser playground demonstrates this rule: it substitutes browser fonts at high resolution, preserves Native Mono's exact 4-pixel advance, and fits editable UI Chrome glyphs to the text field's declared 6-pixel cell grid. The canonical UI Chrome raster itself is proportional; the editable control's cell grid is the reason its browser lowering must keep caret and pointer geometry together.

Sound has two useful levels

Tones: say what should be heard

Tone events are tiny and wonderfully portable. A note names a logical voice, frequency in hertz, volume from 0 to 255, waveform, and duration in scheduler ticks:

APP "CHIME"
  LABEL "Door Chime"
  NEEDS SOUND
END APP

' Voice 0, A4, medium-loud, sine, thirty ticks.
INTENT AUDIO.NOTE_ON(0, 440, 192, 3, 30)
END

Waveforms are 0 Square, 1 Triangle, 2 Sawtooth, 3 Sine, and 4 Noise. A zero duration sustains the voice until NOTE_OFF, another note replaces it, or the application exits. A runner exposes up to four app-scoped logical voices and never lets one application silence another's.

The tone family is:

Intent Purpose
AUDIO.QUERY_CAPS discover voices, waveforms, rates, latency, and feature limits
AUDIO.NOTE_ON begin or atomically replace one voice
AUDIO.NOTE_OFF stop one voice
AUDIO.PROGRAM choose a semantic voice program
AUDIO.VOLUME change an app-scoped voice level
AUDIO.SILENCE stop all sound owned by this application

PCM: stream with a clock

PCM is for recorded effects, speech, and music. Its lifecycle is intentionally explicit:

QUERY_CAPS → PCM_OPEN at an exact advertised rate → WRITE / prefill → START → STOP → CLOSE

PCM_OPEN takes hertz, not a sound-chip divisor. The route either honors that exact advertised rate or refuses; it never silently retunes the clip. PCM_WRITE may accept only part of a carrier, so producers retain the remainder and yield. PCM_STOP is idempotent and drops queued frames; PCM_CLOSE releases the stream. PCM_STATS reports starvation and staged-versus-read counters so a glitch is observable rather than folklore.

The feature query keeps capabilities independent: semantic tones, native-chip tones, bounded PCM, full-rate PCM, mixing, simultaneous tones and PCM, a media clock, and capture. Code must not infer one from another.

How runners adapt media

Runner Honest upgrade or lowering
browser decode validated image/audio bytes, use high-density outline fonts, present through canvas and browser audio policy
Windows / Linux / macOS use native decoders, font rasterizers, mixers, and GPU-backed presentation while retaining logical metrics
rich D/OS route keep assets pool/compositor-side and issue compact draw or playback requests
constrained D/OS route select a declared low-bit-depth image, resident font, waveform, or bounded PCM rate

Capability adaptation can improve fidelity and capacity. It cannot borrow ambient files, substitute a different logical asset, silently change a required sample rate, or claim completion before presentation/playback admission.

A practical media checklist

  1. Give every durable asset a stable logical identity.
  2. Package alternate representations under that identity.
  3. Declare NEEDS GFX or NEEDS SOUND when the application cannot function without it.
  4. Query optional audio features instead of guessing from the platform name.
  5. Load reusable assets outside DRAW and reuse them.
  6. Keep document metadata—caption, alt text, crop, placement—separate from decoded bytes.
  7. Close streams and release owning adapters on every normal, cancelled, and refused path.

Next: Gaming & GX →