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:
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:
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:
- Admit the exact operation and version before trusting the image.
- Choose a route appropriate to this host.
- Preserve the semantic contract while upgrading or lowering the implementation.
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:
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:
BEGIN_FRAME- zero or more drawing calls
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:
Math is also an adaptive Intent family¶
The familiar expression remains the source interface:
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, andPOW; SQR,LOG,EXP,SIN,COS,TAN, andATN;- canonical
RNDandSEED; - numeric
FORMAT,PARSE, andCONVERT; ARRAY_MAPandARRAY_REDUCE; andQUERY_CAPSand batchedEVAL.
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¶
- Ask for semantic outcomes, never device registers.
- Query capabilities when more than one honest experience is possible.
- Treat geometry, event order, and carrier bounds as contracts.
- Prefer typed D/Works wrappers for complex array carriers.
- Let the runner upgrade or lower presentation; do not duplicate target branches in BASIC.
- 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