# Drawing, text, audio and HTTP with Raylib

[العربية](guide.ar.md) · [Exact API](reference.en.md) · [Deployment](deployment.en.md) · [Examples](../examples/raylib/README.en.md)

ASPL supplies one Arabic-first Raylib library with exact English aliases. Import
`core::raylib` or `أساسي::رايليب`. Either written prefix accepts member names
in both languages. Import both module spellings to use both short prefixes. It uses the pinned Raylib 6.0 backend for native
windows, 2D drawing, PNG textures and WAV/OGG/MP3 playback. Text uses embedded
HarfBuzz, ICU, FreeType and default Arabic/Latin fonts. The online playground
refuses this library, including an unused import.

## Run the examples

From the repository root, use the installed `aspl` or contributor `build/aspl`:

```sh
aspl check docs/examples/raylib/نافذة-وإدخال.لبات
aspl run docs/examples/raylib/نافذة-وإدخال.لبات
aspl build -o build/sprites docs/examples/raylib/sprite-camera.aspl
./build/sprites
```

Checking and building need no display/audio device or C compiler. Running the
window and audio examples needs the facilities in the deployment guide. Asset
paths start at the process working directory. The examples use the small assets
in `docs/examples/assets` and their `.NOTICE` files. The identity example works
without display or audio facilities and measures embedded shaped text.

## Handle a checked result

ASPL converts native aggregate values field by field and returns expected errors
through `result<T>`. Numeric widths are exact; convert an already typed wider
number explicitly. Check the result before reading its payload:

```aspl
import core::raylib;
fn start_main() -> i64 {
    let opened = raylib::InitWindow(640, 360, "سلام ASPL");
    if not opened::ok {
        print(opened::error::code);
        print(opened::error::message);
        return 1;
    }
    let closed = raylib::CloseWindow();
    if not closed::ok { print(closed::error::message); return 2; }
    return 0;
}
```

`ok` / `نجاح`, `value` / `قيمة`, `error` / `الخطأ`, `code` / `الرمز` and
`message` / `الرسالة` are the existing result fields. No diagnostic fields were
added. Reading the wrong result arm traps. Programs compare the stable ASCII
code; new Raylib messages contain both languages regardless of source vocabulary
or locale. The seven readiness/validity probes return bool directly.

| Codes | Meaning |
| --- | --- |
| `raylib.invalid_argument`, `raylib.numeric_overflow` | Invalid range, choice, scalar, NUL path/title, or unrepresentable conversion/derived arithmetic. |
| `raylib.invalid_order` | Missing device, duplicate init, bad drawing/mode pair or forbidden frame state. |
| `raylib.invalid_context`, `raylib.owner_busy` | Wrong execution/thread/effect context, or another execution holds the device lease. |
| `raylib.closed_resource` | This shared resource owner is logically closed. |
| `raylib.load_failed`, `raylib.unsupported_asset` | Asset read/decoder failure, or an unselected image/audio format. |
| `raylib.invalid_font`, `raylib.unsupported_font` | Malformed required font data, or an unsupported font profile. |
| `raylib.invalid_text`, `raylib.missing_glyph` | Unsupported control/malformed input, or no admitted font covers the text. |
| `raylib.resource_limit` | Shared backend allowance or bounded native/cache capacity exhausted. |
| `raylib.host_unavailable`, `raylib.host_incompatible` | Missing/unreachable host facility, or incompatible symbol/protocol/context. |
| `raylib.initialization_failed`, `raylib.host_failure` | Safely released initialization/start failure, or another native/upload failure. |

Messages name the canonical operation and affected input/resource. Text errors
include zero-based logical `scalar_index=N` and `scalar=U+XXXX`; malformed native
UTF-8 uses `byte_offset=N`. These are message details, not extra fields or a
message parsing API. NUL/control bytes are escaped. Source checking uses stable
keys such as `type-mismatch`, `invalid-field`, `forbidden-context-operation` and
`supplied-operator-not-supported`. CLI diagnostics default to Arabic; select
English with `--diagnostic-language=en`. Generated programs accept
`--aspl-diagnostic-language=en`.

Active floating inputs must be finite. Window dimensions, camera zoom, audio
pitch and line thickness are positive; radius and FPS are nonnegative. Volume
is 0..1 and pan -1..1. Derived coordinates, resampling rates, counts and byte
products are checked before native entry. Signed texture rectangles, zero or
negative texture scale and admitted degenerate shapes keep the pinned behavior.
A refusal before native entry leaves current state unchanged; a failure after
native effects promises owned cleanup rather than general rollback.

## Own resources and drawing frames

Texture, Font, Sound, Music and TextLayout are opaque managed owners. Copies,
lists and HTTP state share the same closeable resource. Unload through one alias
closes them all and is idempotent. Checked closed-resource access takes precedence
over a missing former device. Native backing and its original memory charge stay
alive until admitted native use ends. An accepted draw can retain backing after
logical unload, including unload within a frame.

One execution holds the process device lease. Device operations use the process
main thread. Texture belongs to a window generation; Sound/Music belong to an
audio generation. Device close closes their aliases before native destruction.
Reopen creates a new generation and never revives old owners. CPU fonts and
layouts survive window closure. A layout retains font backing after Font unload;
unloading the default Font succeeds without closing it. Titles retain charged
copies until replacement/quiescence. Custom font owners retain copied file bytes.

Open a frame with BeginDrawing, draw in screen coordinates, optionally enter
BeginMode2D and leave with EndMode2D, then call EndDrawing. A mismatched or nested
pair returns `raylib.invalid_order` and preserves the current state. Close camera
mode before ending the frame. Draw/ClearBackground require a frame; asset loads,
device lifecycle, title/exit/FPS changes and texture filter/wrap changes require
a closed frame. SetConfigFlags replaces the saved next-window flags and must run
before a window is open. Flags and pacing survive reopen; Escape/input/timing reset.

Only pure math, CPU text, total probes and read-only owner metadata are permitted
in HTTP handlers and managed callbacks. The reference lists this context for
every operation. Helpers, stored owners and callable values cannot bypass effects.
Source checking, bytecode admission and runtime admission enforce these rules.
There is no source callback from the mixer thread.

## Shape text and measure its box

Keep text in logical order. Strings, normalization, user names and path bytes
remain unchanged. Arabic joining, ligatures/marks and mixed Arabic/Latin bidi
layout use pinned fonts and Unicode 17. Host fonts, locale and `ICU_DATA` do not
change them. Font selection keeps grapheme clusters and Arabic joining sequences
together, with custom-font then script-preferred default fallback. No final
replacement boxes are accepted.

MeasureText/DrawText use Auto direction, Start alignment, no wrap and no extra
line spacing. Ex/Pro character spacing must be zero. CreateTextLayout takes all
six TextOptions fields explicitly; Auto chooses first-strong direction, with LTR
for neutral-only paragraphs. Start/End follow the paragraph base, Left/Right are
physical. A supplied width enables wrapping with ICU root breaks and emergency
grapheme breaks. An oversized cluster may overflow that width.

LF, CR, CRLF and U+2029 separate paragraphs; U+2028 breaks a line. Blank/trailing
lines, bidi controls, ZWJ/ZWNJ and soft hyphens follow the layout contract. NUL,
tab, DEL and other unsupported Cc controls fail. Integer sizes are 1..4096,
render f32 sizes 0.5..4096; effective size rounds to 1/64 with ties to even.

TextMetrics.size is the logical box; ink is local glyph bounds including marks
and overhangs. Measurement and drawing use identical positions. Draw at logical
top-left; origin, rotation and Camera2D transform placement without changing
local metrics. Empty text has zero lines/height. MeasureText rounds width upward
to checked i32. Layouts are immutable CPU values that can be prepared before a
window and drawn after recreation. Glyph-cache eviction preserves metrics.
Known validation, glyph, numeric or preparation failure submits none of that
text request; previously accepted draws remain valid.

## Update sound, music and serving explicitly

Initialize audio before loading Sound or Music. Playback/volume/pan/pitch and
UpdateMusicStream may run inside a drawing frame. Volume is 0..1, pan -1..1 and
pitch is positive with a checked derived native rate. Streamed music advances
only when the application calls UpdateMusicStream. SeekMusicStream accepts
0..reported length inclusive; the endpoint is logical EOF. The next update
restarts playing looping music or stops nonlooping/empty music.

HTTP start returns Session<C,S> after all listeners are ready and dispatches no
handler. Call progress outside frames. Budget defaults are 4096 instructions,
2 active ms and zero wait ms. Progress is cooperative, with serialized bounded
turns; OS/native work can overrun active_ms. Normal explicit handlers run only
through progress. EndDrawing and parked input may maintain transport/deadlines
outside drawing but dispatch no source handler. Input within a frame drives
neither HTTP nor handlers. A blocking top-level HTTP request can time out against
its own explicit server. Call progress often enough for your application's work.

Session state/configuration helpers are application-only and may run in a frame.
Context helpers remain live-handler-only. Reads copy state. Snapshots retain a
hidden session/version identity and their read-only value survives close.
Conditional publication returns successful false for stale state and
`http.invalid_argument` for a foreign-session snapshot. A successful publication
replaces whole state and advances its version. A snapshot grants no Context or
device authority. stop_session begins drain; continue explicit progress until
closed. close_session immediately revokes serving without dispatching drain
handlers. Repeated normal stop/close succeeds and normal closed progress reports
SESSION_CLOSED. Closed state helpers return `http.closed_session`; invalid frame
or context uses `http.invalid_order` or `http.invalid_context`, with bilingual
messages. Existing HTTP codes and producer messages keep their contracts.

## Automatic cleanup and interruption

Return, trap, limits and cancellation revoke source work and abandon an open
frame without intentionally presenting a final frame. Cleanup releases GPU work
before its window and decoder/mixer work before its audio device. Backing and
charges remain retained when release cannot be proved. Default memory limits are
256 MiB VM and one shared 128 MiB Raylib/HTTP backend account. VM call-frame and
slot limits apply across suspended work too.

The first SIGINT/SIGTERM permanently stops application code, cancels parked
input/application requests and drains only already admitted HTTP handlers outside
drawing. The second signal revokes remaining drain. Traps, limits and other
cancellation dispatch no drain handlers. Remaining-resource cleanup establishes
one deadline `t + max(R,H)`, capped by earlier execution and operation/session
scopes; retries do not renew it. R is Raylib's allowance. H is the remaining
session's allowance, otherwise the maximum of 1000 ms and admitted client cleanup
allowances when HTTP work remains. Unused imports/closed headers add none.
Terminal statuses remain trap 5, limit 6, cancellation 7 and host failure 8.
Earlier primary outcomes keep separate cleanup attribution. Driver hangs have
no hard in-process preemption guarantee.
