Skip to content

Intents & services

Portable programs ask for outcomes, not devices.

A D/BASIC application never needs to know which video chip, GPU, operating system, bank switch, sound device, or browser API sits underneath it. It says what the program means. The runner adapts that meaning to the system in front of it.

That is the why behind Intents.

The old portability trap

Classic BASIC made it delightfully easy to reach the machine:

' The historical pattern—not portable D/BASIC
POKE SomeVideoAddress, SomeMagicValue

That immediacy was exciting, but the address was the machine. Move the program and its meaning disappeared.

D/BASIC moves the boundary up one level:

INTENT GFX.FILL_RECT(12, 12, 80, 24, Color%)

This says “fill this rectangle.” It does not say which core executes the fill, how pixels are stored, whether a GPU draws it, or how a monochrome head represents the color.

The adaptive runner

The runner has three jobs:

  1. Admit the exact operation and version before trusting the image.
  2. Choose a route appropriate to this host.
  3. Preserve the semantic contract while upgrading or lowering the implementation.
D/BASIC meaning → registered call → capability admission → host route → native presentation

Upgrade on a richer system

A browser or modern desktop can improve presentation without changing the program:

  • map a canonical text role to a real browser or desktop font and rasterize it at display resolution;
  • expand color onto a deep-color GPU surface;
  • batch a pure math tree into one coprocessor or vector operation;
  • keep clipping and geometry in logical D/BASIC coordinates while drawing into a high-density backing surface;
  • use hardware composition for frame presentation.

This is why the playground's D/Works text can use Atkinson Hyperlegible and JetBrains Mono instead of magnifying a tiny bitmap font. The source still emits the same text Intent and the same logical geometry.

Lower on a constrained system

A small D/OS target can keep the same meaning with a different route:

  • quantize or dither color for the head's actual palette;
  • draw a text role with the target's metrics-compatible resident face;
  • execute a bulk operation in bounded slices so the machine remains responsive;
  • expand one portable math batch into ordered scalar MATH rows when no batch accelerator is present;
  • compose a frame through the required local head instead of a desktop GPU.

“Lower” does not mean “do something vaguely similar.” The runner must preserve ordering, bounds, clipping, object state, result shape, and the operation's atomicity. If it cannot keep the contract, it refuses.

One source, honest differences

Concern Program owns Runner may adapt
drawing logical coordinates, clip, color role, text, ordering raster method, font rasterizer, color representation, composition path
math type, expression order, rounding contract local scalar work, batch, coprocessor crossing
arrays type, rank, bounds, atomic operation vector route, chunking, storage tier
windows application model and lifecycle native window, browser surface, D/OS composed surface
unavailable work requested meaning a named refusal—never counterfeit success

Two outward-call spellings

INTENT DOMAIN.OP(...)

An Intent names a versioned semantic operation in a domain:

INTENT GFX.BEGIN_FRAME()
INTENT GFX.FILL_RECT(0, 0, Width%, Height%, Background%)
INTENT GFX.DRAW_TEXT(12, 12, "READY", Font%, Foreground%, Background%)
INTENT GFX.PRESENT()

The compiler resolves the domain, operation name, argument count, and argument types from the generated registry. Names are case-insensitive; numeric domain and opcode values do not appear in source.

SERVICE ROW(...)

A Service is a synchronous runtime/operating-system request with a globally named row:

SERVICE SET_TITLE("D/BASIC Notes")
SERVICE INVALIDATE()

Use Services for the small local contract around the program—window title, invalidation, console primitives, time, and process context. Use Intents for versioned capability families such as graphics, compute, data, pasteboard, and drag sessions.

Prefer the friendly projection

You normally write PRINT, TIMER, SQR, or a typed D/Works data wrapper instead of calling their low-level Service or Intent rows yourself. The generic syntax is the escape hatch that makes every registered row reachable without adding a new keyword.

A complete portable frame

DIM SHARED Width AS INTEGER
DIM SHARED Height AS INTEGER

WINDOW SUB OPEN()
  Width = 320
  Height = 192
  SERVICE SET_TITLE("Intent postcard")
  SERVICE INVALIDATE()
END SUB

WINDOW SUB DRAW()
  INTENT GFX.BEGIN_FRAME()
  INTENT GFX.FILL_RECT(0, 0, Width, Height, 2081)
  INTENT GFX.SET_CLIP(8, 8, Width - 16, Height - 16)
  INTENT GFX.DRAW_TEXT(12, 14, "ONE PROGRAM. MANY HEADS.", 3, -1, 2081)
  INTENT GFX.RESET_CLIP()
  INTENT GFX.PRESENT()
END SUB

WINDOW SUB RESIZE(W AS INTEGER, H AS INTEGER)
  Width = W
  Height = H
  SERVICE INVALIDATE()
END SUB

WINDOW SUB CLOSE()
END SUB

The resize handler receives the runner's new logical canvas. The application reflows its layout and requests a frame; it does not assume that a bigger desktop window is merely a stretched 320 × 192 bitmap.

Frame discipline

The usual GFX frame is:

  1. BEGIN_FRAME
  2. zero or more drawing calls
  3. PRESENT

Clips are explicit and nest in application logic, not hidden canvas state. PRESENT completes the semantic frame; an accelerated queue merely accepting work is not the same thing as presentation.

SERVICE INVALIDATE() asks the host to schedule WINDOW SUB DRAW(). It does not paint immediately. This keeps event handling and drawing separate and lets the host coalesce work.

Registered GFX vocabulary

Signature notation below uses I = INTEGER, L = LONG, S = STRING, and A = whole-array carrier.

Intent Arguments Purpose
GFX.QUERY_VIEWPORT A query the current logical viewport carrier
GFX.BEGIN_FRAME begin one semantic frame
GFX.PRESENT present/commit the frame
GFX.SET_CLIP I, I, I, I set x, y, width, height clip
GFX.RESET_CLIP restore the full clip
GFX.FILL_RECT I, I, I, I, I fill a rectangle with a canonical color value
GFX.DRAW_TEXT I, I, S, I, I, I draw text at x, y with font and color roles
GFX.BLIT_RESOURCE A, I × 8 draw a bounded caller-array raster; not a packaged asset lookup
GFX.BEGIN_SURFACE_MOVE I, I, A begin a semantic surface move
GFX.MOVE_SURFACE I, I update the move position
GFX.END_SURFACE_MOVE complete the move
GFX.PRESENTATION_HINT I, I, I, A publish semantic presentation metadata
GFX.COPY_RECT I × 6 copy sx, sy, w, h to dx, dy
GFX.POLYLINE A, I, I, I draw a packed line record
GFX.DRAW_TEXT_STYLED I, I, S, I, I, I, I draw text with a registered style role

Use SET_CLIP around text and widget content that must not spill into neighboring surfaces. A rich host may render a smoother font, but it must still honor the clip.

Intent domains

Domain The question it answers
CORE What can this host do, and how do I fence or cancel work?
GFX What should appear on this surface?
AUDIO What should be heard?
COMPUTE What bounded bulk computation should be performed?
AI What assistive proposal or analysis is requested?
UI What higher-level user-interface meaning is being expressed?
SERVICE What transferable OS interaction—pasteboard, schema, drag—should occur?
MATH What canonical arithmetic, conversion, formatting, or array job is required?
FILE What operation should occur on bytes at a named mount and path?
DATA What database identity, query, revision, or durable artifact operation should occur?

The registry has a fixed domain identity and generated row signatures. A new row changes the catalog, not the parser grammar.

See Resources, Images & Sound for packaged raster variants, font roles, tones, and PCM lifecycles. Networking uses the same semantic boundary through owning dworks.network adapters over SERVICE.NETWORK_* rows; see Networking.

Core and compute rows

Intent Signature Meaning
CORE.NOP () a semantic no-op
CORE.QUERY_CAPABILITIES (A) fill a bounded capability carrier
CORE.CANCEL (L) cancel a ticketed operation
CORE.FENCE () order prior work before later work
CORE.QUERY_CLOCK (A) fill a canonical clock carrier
COMPUTE.VECTOR_I16 (I, L, A, A, A) bounded 16-bit vector computation
COMPUTE.SHA256 (I, A, A) hash an exact carrier prefix into a digest carrier

Typed libraries such as dworks.sha256 hide carrier bookkeeping:

IMPORT dworks.sha256
CALL WorksSha256(Bytes%(), ByteLength&, Digest%())

Math is also an adaptive Intent family

The familiar expression remains the source interface:

Distance# = SQR(X# * X# + Y# * Y#)

The compiler recognizes a pure homogeneous tree and may package it as a portable MATH.EVAL program. A capable runner evaluates it in one crossing. A simpler runner expands it into the same ordered MATH.MUL, MATH.ADD, and MATH.SQR meanings. Calls, conversions, comparisons, RND, TIMER, and other observable sequence points split a batch.

The registered MATH vocabulary covers:

  • scalar ADD, SUB, MUL, DIV, NEG, ABS, SGN, CMP, and POW;
  • SQR, LOG, EXP, SIN, COS, TAN, and ATN;
  • canonical RND and SEED;
  • numeric FORMAT, PARSE, and CONVERT;
  • ARRAY_MAP and ARRAY_REDUCE; and
  • QUERY_CAPS and batched EVAL.

This is a performance model a 6502 and a desktop can share: remove crossings when possible, retain semantic order always.

Files, databases, pasteboard, and drag use typed carriers

These families exchange bounded integer-array records. Hand-packing them is legal but rarely wise. D/Works libraries provide named types and procedures around the wire shape.

FILE workflows

The FILE family is filesystem manipulation: QUERY_MOUNT, LIST, STAT, OPEN, READ, WRITE, CLOSE, and EDIT. EDIT selects delete, trash, restore, rename, same-mount move, or directory creation. It works with explicit mounts and paths; it does not grant database authority or manufacture revisions. See Files & File Manipulation.

DATA workflows

The DATA family is D/BASIC's database equivalent. It works with semantic identities, typed values, stable snapshots, writes, attachments, revisions, and receipts; it is unrelated to the classic embedded DATA statement.

The registry groups DATA rows by task:

  • capability and read: QUERY_CAPS, OPEN, GET_VALUE, CLOSE;
  • snapshots: OPEN_SNAPSHOT, FETCH_PAGE, RESOLVE_ROW, REVALIDATE_OBJECT, ACCEPT_EXACT, CLOSE_SNAPSHOT;
  • writes and attachments: QUERY_WRITE_CAPS, OPEN_WRITE, BEGIN_WRITE, BEGIN_ATTACHMENT, WRITE_ATTACHMENT_CHUNK, FINISH_ATTACHMENT, COMMIT_WRITE, WRITE_STATUS, ABORT_WRITE, CLOSE_WRITE;
  • artifacts: QUERY_ARTIFACT_CAPS, BEGIN_NEW, BEGIN_SAVE, BEGIN_SAVE_AS, BEGIN_PUBLISH, WRITE_ARTIFACT_CHUNK, FINISH_ARTIFACT, COMMIT_ARTIFACT, ARTIFACT_STATUS, ABORT_ARTIFACT, CLOSE_ARTIFACT, ACK_ARTIFACT_RECEIPT;
  • browsing and retirement: ALLOCATE_ARTIFACT_OPERATION, LIST_ARTIFACTS, OPEN_ARTIFACT_READ, READ_ARTIFACT_CHUNK, CLOSE_ARTIFACT_READ, BEGIN_RETIRE, LIST_PUBLICATIONS, OPEN_PUBLICATION_READ.

See Database & Data Intents for the full lifecycle and examples.

SERVICE-domain workflows

  • pasteboard: query, begin, write, exact-length write, commit, abort, inspect, list, negotiate, read, status, and acknowledge;
  • DOBJ schemas: length and read;
  • drag: query, begin, negotiate, accept/reject, destination commit, authorize move, source commit, status, cancel, and acknowledge.

The workflow names make ownership visible. “Begin, stage, commit, acknowledge” is intentional: a cross-application transfer should not become real merely because a pointer crossed a rectangle.

Local Service rows

The runtime Service table supplies these families:

Family Rows
process ARGUMENT_COUNT, ARGUMENT_TEXT, INSTANCE_ID, SLEEP_MS
console WRITE_TEXT, WRITE_NEWLINE, WRITE_COLUMN, WRITE_SPACES, WRITE_ZONE, READ_LINE, READ_KEY, CLEAR, LOCATE, COLUMNS, ROWS
time MONOTONIC_MS, MONOTONIC_GRADE, WALL_STATE, WALL_HHMM, TIMER_SECONDS
surface WIDTH, HEIGHT, SET_TITLE, INVALIDATE

Language conveniences project onto these rows. PRINT uses console output; TIMER exposes timer seconds; the host supplies RESIZE dimensions. Direct SERVICE statements are most useful for side-effecting rows such as SET_TITLE and INVALIDATE; scalar-producing rows normally appear through their language projection.

Admission: capability before execution

An emitted DBC image declares what it requires. Before byte zero runs, the loader validates the image and checks that the selected host offers compatible Service and Intent rows. This prevents a program from drawing half a window and only then discovering that its required presentation route never existed.

At runtime, a ticketed Intent can yield Pending; the VM parks that operation and the host resumes it in a later bounded turn. Program order is preserved while the event loop, browser, or small machine remains responsive.

Refusal is the final portability feature

There are only two honest outcomes for a capability request:

  • the host performs the registered meaning; or
  • it refuses with a stable class, rule, and detail.

There is no third path where an unknown request is ignored or a host silently changes the program. ON REFUSAL lets an application recover when the capability was genuinely optional. See Compatibility, Migration & Refusals.

Rules for portable application code

  1. Ask for semantic outcomes, never device registers.
  2. Query capabilities when more than one honest experience is possible.
  3. Treat geometry, event order, and carrier bounds as contracts.
  4. Prefer typed D/Works wrappers for complex array carriers.
  5. Let the runner upgrade or lower presentation; do not duplicate target branches in BASIC.
  6. Handle optional refusal deliberately. Required refusal should stop the program loudly.

Next: Drag, Drop & DOBJ →

See also: Windows & Events · Widgets · Resources, Images & Sound · Networking · Drag, Drop & DOBJ · Compiler & Optimizer · Bytecode & Delivery