ASPL لباتASPL 0.7.0

Search documentation

Search starts with current English documentation · ASPL 0.7.0

Enter a complete name such as read_line, or words about a topic.

    العربية
    Source files

    Open one UTF-8 .aspl or .لبات file, up to 1 MiB, in a new draft. It stays in this browser and does not run automatically.

    Draw, shape text, play audio and serve HTTP with Raylib

    ASPL 0.7.0 · Current release

    Native 0.7.0 windows, shaped Arabic/mixed text, font and audio lifetimes, explicit serving and deployment.

    On this page

    Prepare the native host

    Native only, published ASPL 0.7.0. Install the native toolchain. Import core::raylib or أساسي::رايليب in each source module that uses the library. Either imported prefix accepts exact Arabic and English member aliases. Import both spellings to use both short prefixes. User names, strings and paths retain their bytes.

    Checking and building require no display or C compiler. Running a window needs x86_64 Linux, glibc 2.34 or later, a reachable Wayland/EGL or X11/GLX display and OpenGL 3.3 core. XWayland uses the X11 route. The tool embeds the pinned Raylib 6.0 backend; no system Raylib is required. See system requirements.

    With both endpoints present, exact XDG_SESSION_TYPE=wayland selects Wayland first; other values select X11 first. With one nonempty WAYLAND_DISPLAY or DISPLAY, only that route is attempted. A safely released failure may fall back to the other endpoint. With neither endpoint, InitWindow returns raylib.host_unavailable. There is no headless window success. A successful backend remains fixed until close.

    Download programs from the Raylib collection. Each family lists its supplied variants and any licensed files before source. Keep the original source filenames and asset paths. The sprite family needs its PNG and notice under docs/examples/assets, relative to the process working directory. No source modules are required by these families. The browser rejects the library even when an import is unused.

    Check each result

    Ordinary operations return result<T>; readiness/validity probes return bool directly. Test ok / نجاح before reading value / قيمة or error / الخطأ. Reading the wrong arm traps. Compare stable ASCII error::code; Raylib messages contain both languages. Use --diagnostic-language=en for CLI diagnostics, or --aspl-diagnostic-language=en for a generated program.

    Illustrative fragment

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

    This fragment illustrates checked lifecycle calls. Complete downloadable programs below retain their catalog outcomes. See the API reference for exact widths, contexts and failures.

    Own a window generation

    Call SetConfigFlags before opening the window. It replaces the saved next-window flags. SetTargetFPS accepts nonnegative FPS, including zero for uncapped pacing. Open with positive i32 dimensions and a title without NUL. Titles are copied and retained until replacement or native quiescence. SetWindowTitle needs a live window and a closed frame.

    One execution holds the process device lease. Device operations run on the process main thread. IsWindowReady is a total probe; WindowShouldClose is a checked observation. A close request does not itself close the window. The application decides when to finish or close it. CloseWindow succeeds when already closed.

    Close invalidates texture aliases before destroying the graphics context. Reopen creates a fresh generation. Saved flags and pacing survive, while Escape, input queues, mouse history and timing reset. The window family changes the title, waits for Enter in the terminal, closes and reopens.

    Pair drawing frames

    Call BeginDrawing, then ClearBackground and drawing operations, then EndDrawing. Draw and clear calls need an open frame. A duplicate begin or unmatched end returns raylib.invalid_order and preserves the current state. End camera mode before ending the frame.

    Loads, window lifecycle, title/exit/FPS changes and texture filter/wrap changes require a closed frame. Input and timing observations can read the current sample inside a frame. EndDrawing presents accepted work, polls native events and applies target pacing. GetTime returns f64; GetFrameTime returns f32; GetFPS returns i32. Fresh windows report zero frame time and FPS before their first completed frame.

    The frame family presents two short loops and checks timing reset after reopen. FPS is a target, not a guarantee about a busy host.

    Read keyboard, mouse and resize samples

    Window/input observations require the calling execution's live window and main thread. They read sampled state rather than installing source callbacks. Use exact Key and MouseButton constants; integer construction is not allowed. Down/up describe held state; pressed/released describe transitions; IsKeyPressedRepeat includes repeat observations.

    GetKeyPressed consumes one queued key and returns KEY_NULL when empty. GetCharPressed consumes one queued Unicode scalar and returns zero when empty. Call repeatedly to drain queues when needed. A key event and typed text are distinct observations. SetExitKey(KEY_NULL) disables the exit key; opening a new window restores Escape.

    Mouse position/delta and wheel values use checked f32 values. Logical GetScreenWidth/GetScreenHeight can differ from physical GetRenderWidth/GetRenderHeight. IsWindowResized reports the current resize sample.

    Native only · ASPL 0.7.0 · English source

    Execution: Native only · ASPL 0.7.0

    Prerequisites:
    • Native ASPL 0.7.0 on x86_64 Linux with glibc 2.34 or later.
    • Running needs a reachable Wayland/EGL or X11/GLX display and OpenGL 3.3 core; no system Raylib or C compiler is required. Checking and building need no display.

    Input: No input lines are required.

    // Run with: aspl run docs/examples/raylib/window-input.mixed.aspl
    // Type text, click or scroll to change color. Resize to print new dimensions.
    // Escape requests close. The demo also stops after 180 frames.
    import core::raylib;
    
    fn start_main() -> i64 {
        let flags = raylib::SetConfigFlags(raylib::FLAG_WINDOW_RESIZABLE);
        let pacing = raylib::SetTargetFPS(60);
        if not flags::ok or not pacing::ok { return 1; }
        let opened = raylib::InitWindow(640, 360, "ASPL input / إدخال رايليب");
        if not opened::ok { print(opened::error::message); return 2; }
        let exit_key = raylib::SetExitKey(raylib::KEY_ESCAPE);
        if not exit_key::ok { print(exit_key::error::message); return 3; }
        var frame: i64 = 0;
        var color = raylib::SKYBLUE;
        while frame < 180 {
            let closing = raylib::WindowShouldClose();
            if not closing::ok { print(closing::error::message); return 4; }
            if closing::value { return 0; }
            let clicked = raylib::IsMouseButtonPressed(raylib::MOUSE_BUTTON_LEFT);
            let pressed = raylib::IsKeyPressed(raylib::KEY_SPACE);
            let wheel = raylib::GetMouseWheelMove();
            if not clicked::ok or not pressed::ok or not wheel::ok { return 5; }
            if clicked::value or pressed::value or wheel::value not matches 0.0 { color = raylib::MAROON; }
            let typed = raylib::GetCharPressed();
            let key = raylib::GetKeyPressed();
            if not typed::ok or not key::ok { return 6; }
            if typed::value not matches 0 {
                color = raylib::DARKGREEN;
                print("Unicode / محرف: "); print(format_i64(i64(typed::value))); print("\n");
            }
            let resized = raylib::IsWindowResized();
            if not resized::ok { return 7; }
            if resized::value or frame matches 0 {
                let width = raylib::GetScreenWidth(); let height = raylib::GetScreenHeight();
                let render_width = raylib::GetRenderWidth(); let render_height = raylib::GetRenderHeight();
                if not width::ok or not height::ok or not render_width::ok or not render_height::ok { return 8; }
                print("Screen / شاشة: "); print(format_i64(i64(width::value))); print("x"); print(format_i64(i64(height::value)));
                print(" render="); print(format_i64(i64(render_width::value))); print("x"); print(format_i64(i64(render_height::value))); print("\n");
            }
            let begun = raylib::BeginDrawing();
            if not begun::ok { print(begun::error::message); return 9; }
            // Sampled observations also work in an open drawing frame.
            let position = raylib::GetMousePosition(); let delta = raylib::GetMouseDelta();
            if not position::ok or not delta::ok { return 10; }
            let cleared = raylib::ClearBackground(color);
            if not cleared::ok { print(cleared::error::message); return 11; }
            let ended = raylib::EndDrawing();
            if not ended::ok { print(ended::error::message); return 12; }
            frame = frame + 1;
        }
        let closed = raylib::CloseWindow();
        if not closed::ok { print(closed::error::message); return 13; }
        return 0;
    }
    

    Follow the Linux instructions to run this example. Download the source to keep a copy.

    Download window-input.aspl

    Expected outcomes
    {
      "native": {
        "check": 0,
        "status": 0,
        "behavior": {
          "en": "Left click or scroll selects maroon. Space also selects maroon, but a queued character, including a typed space, takes precedence and selects dark green. Each consumed character prints its Unicode scalar number. The first frame and resizes print logical screen and physical render dimensions. Escape or 180 frames ends the loop with status 0. Output depends on the host and input.",
          "ar": "يختار النقر الأيسر أو التمرير اللون العنابي. يختاره مفتاح المسافة أيضا، لكن يتقدم المحرف المنتظر في الطابور، بما فيه المسافة المكتوبة، ويختار الأخضر الداكن. يطبع كل محرف مستهلك رقم قيمة Unicode له. يطبع الإطار الأول وتغيير الحجم أبعاد الشاشة المنطقية والتصيير الفيزيائية. ينتهي التكرار بمفتاح الهروب أو بعد 180 إطارا بحالة 0. يعتمد الإخراج على المضيف والإدخال."
        }
      }
    }

    Share and close textures

    LoadTexture admits PNG files and requires a live window outside a frame. Paths resolve from the process working directory. Check the result before taking its opaque Texture. GetTextureWidth and GetTextureHeight return checked metadata. Choose POINT/BILINEAR filtering and REPEAT/CLAMP wrapping outside frames.

    Texture copies share one closeable managed owner. UnloadTexture through any alias closes every alias and is idempotent. IsTextureValid then returns false. Other access returns raylib.closed_resource, even if the former window is also gone. Accepted drawing retains backing until native use ends, so logical unload during the final frame does not invalidate earlier accepted work. Reopening the window never revives old textures.

    Draw with DrawTexture, DrawTextureV, DrawTextureEx, DrawTextureRec or DrawTexturePro. Source rectangles with signed dimensions preserve flips. Zero/negative scale and signed destination rectangles retain admitted Raylib behavior, with derived arithmetic checked before native entry.

    Native only · ASPL 0.7.0 · English source

    Execution: Native only · ASPL 0.7.0

    Prerequisites:
    • Native ASPL 0.7.0 on x86_64 Linux with glibc 2.34 or later.
    • Running needs a reachable Wayland/EGL or X11/GLX display and OpenGL 3.3 core; no system Raylib or C compiler is required. Checking and building need no display.

    Input: No input lines are required.

    Download and prepare the required files before running:

    import core::raylib;
    
    fn start_main() -> i64 {
        let opened = raylib::InitWindow(480, 300, "PNG sprites / صور متحركة");
        if not opened::ok { print(opened::error::message); return 1; }
        let loaded = raylib::LoadTexture("docs/examples/assets/raylib-sprites.png");
        if not loaded::ok { print(loaded::error::message); return 2; }
        let texture = loaded::value;
        let alias = texture;
        if raylib::GetTextureWidth(texture)::value not matches 32 or raylib::GetTextureHeight(texture)::value not matches 16 { return 3; }
        let filter = raylib::SetTextureFilter(texture, raylib::TEXTURE_FILTER_POINT);
        let wrap = raylib::SetTextureWrap(texture, raylib::TEXTURE_WRAP_CLAMP);
        let pacing = raylib::SetTargetFPS(60);
        if not filter::ok or not wrap::ok or not pacing::ok { return 4; }
        let camera = raylib::Camera2D {
            offset: raylib::Vector2 { x: 15.0, y: 10.0 }, target: raylib::Vector2 { x: 0.0, y: 0.0 },
            rotation: 0.0, zoom: 1.0
        };
        let first = raylib::Rectangle { x: 24.0, y: 24.0, width: 32.0, height: 16.0 };
        let second = raylib::Rectangle { x: 30.0, y: 28.0, width: 32.0, height: 16.0 };
        let collision = raylib::CheckCollisionRecs(first, second);
        let overlap = raylib::GetCollisionRec(first, second);
        if not collision::ok or not overlap::ok { return 16; }
        if not collision::value { return 17; }
        var frame: i32 = 0;
        while frame < 20 {
            if not raylib::BeginDrawing()::ok or not raylib::ClearBackground(raylib::RAYWHITE)::ok { return 5; }
            if not raylib::BeginMode2D(camera)::ok { return 6; }
            if not raylib::DrawTexture(texture, 24, 24, raylib::WHITE)::ok { return 7; }
            if not raylib::DrawTextureV(texture, raylib::Vector2 { x: 100.0, y: 24.0 }, raylib::SKYBLUE)::ok { return 8; }
            if not raylib::DrawTextureEx(texture, raylib::Vector2 { x: 40.0, y: 110.0 }, -10.0, 4.0, raylib::WHITE)::ok { return 9; }
            if not raylib::DrawTextureRec(texture, raylib::Rectangle { x: 16.0, y: 0.0, width: -16.0, height: 16.0 },
                raylib::Vector2 { x: 250.0, y: 24.0 }, raylib::WHITE)::ok { return 10; }
            if not raylib::DrawTexturePro(texture, raylib::Rectangle { x: 16.0, y: 0.0, width: 16.0, height: -16.0 },
                raylib::Rectangle { x: 330.0, y: 160.0, width: -96.0, height: 96.0 },
                raylib::Vector2 { x: 48.0, y: 48.0 }, 25.0, raylib::Color { r: 255, g: 255, b: 255, a: 210 })::ok { return 11; }
            if not raylib::DrawRectangleLinesEx(overlap::value, 1.0, raylib::RED)::ok { return 18; }
            if not raylib::EndMode2D()::ok { return 12; }
            if frame matches 19 {
                if not raylib::UnloadTexture(alias)::ok or raylib::IsTextureValid(texture) { return 13; }
            }
            if not raylib::EndDrawing()::ok { return 14; }
            frame = frame + 1;
        }
        if not raylib::UnloadTexture(texture)::ok or not raylib::CloseWindow()::ok { return 15; }
        print("texture sprites complete");
        return 0;
    }
    

    Follow the Linux instructions to run this example. Download the source to keep a copy.

    Download sprite-camera.aspl

    Expected outcomes
    {
      "native": {
        "check": 0,
        "status": 0,
        "output": "texture sprites complete",
        "behavior": {
          "en": "20 frames show tinted, rotated and flipped atlas sprites with a red rectangle intersection. The final frame unloads an alias before presentation and checks that the original is invalid. Success prints texture sprites complete without a trailing newline and returns 0.",
          "ar": "تعرض 20 إطارا صور الأطلس الملونة والمدورة والمنعكسة مع تقاطع مستطيل أحمر. يحرر الإطار الأخير نسخة المالك قبل العرض ويتحقق من بطلان الأصل. يطبع النجاح texture sprites complete دون سطر جديد ويعيد 0."
        }
      }
    }

    Transform Camera2D coordinates

    Construct every Camera2D field: offset, target, rotation and positive zoom. Angles use degrees. BeginMode2D(camera) needs an open drawing frame and no active camera mode. Pair it with EndMode2D before EndDrawing. Nested or unmatched modes return raylib.invalid_order without changing the current pair.

    Draw inside the mode in world coordinates, then draw screen-space borders or controls after leaving it. GetWorldToScreen2D and GetScreenToWorld2D are pure checked helpers and need no window or frame. Convert sampled mouse coordinates with the same camera when testing world-space objects. Nonfinite inputs, zero zoom and unrepresentable derived transforms fail before native entry.

    The camera shapes family draws a rectangle, circle, thick line and triangle through a camera, then a screen-space pixel and border.

    Test collisions in one coordinate space

    Collision helpers are pure checked operations. They need no display, frame or resource owner and are allowed in HTTP handlers and managed callbacks. Drawing and device operations are application-only; a helper or stored callable cannot bypass their effect restrictions.

    Use CheckCollisionRecs and GetCollisionRec for rectangles, or the circle/rectangle/point/triangle tests in the reference. Supply both operands in the same coordinate space. Radius must be nonnegative. Admitted signed or degenerate geometry follows the pinned backend's behavior. Checked derived arithmetic can return raylib.numeric_overflow even when all inputs are finite.

    The sprite family checks that rectangles at 24,24 and 30,28 overlap, then draws the returned intersection in red inside camera mode. This tests collision geometry as well as visual placement.

    Select embedded or custom fonts

    GetFontDefault returns the embedded Arabic/Latin Font with base size 32. CPU text needs no display or audio device. The pinned HarfBuzz, ICU and FreeType stack uses Unicode 17 and embedded Noto Sans Arabic Regular 2.013 and Noto Sans Regular 2.015. Host fonts, locale and ICU_DATA do not replace that baseline. The generated companion notices include the fonts' licenses and FreeType credit/disclaimer.

    For a custom font, supply your own licensed single-face TrueType outline file relative to the working directory. LoadFont uses base size 32; LoadFontEx accepts base size 1..4096 and copied list<i32> scalar prewarming hints. Empty hints mean no prewarming, never restricted coverage. Collections, CFF/PostScript, WOFF/WOFF2, bitmap and color-font profiles are unsupported. Malformed required tables return raylib.invalid_font; unsupported profiles return raylib.unsupported_font; file read failures return raylib.load_failed.

    Selection tries the custom font then script-preferred embedded fallback. It keeps grapheme clusters and Arabic joining sequences together. Arabic custom selection requires the admitted joining/mark features. No final replacement boxes are accepted; uncovered text returns raylib.missing_glyph.

    Font copies share closure. A custom font owns copied file bytes, so replacing the file after loading does not change existing text. UnloadFont closes custom aliases, while existing layouts retain independent font backing. Unloading the default font succeeds without invalidating it. GetFontBaseSize reads metadata; it does not set a rendering size. Font loads require application/main-thread admission outside frames, but need no live window. Default access, measurement, layout creation and CPU unload are permitted in HTTP handlers and managed callbacks.

    Keep logical text and measure its layout

    Pass text in logical order. Arabic joining, ligatures, marks and mixed Arabic/Latin bidi placement do not rewrite the string, normalize identifiers or change path bytes. MeasureText and DrawText use Auto direction, Start alignment, no wrapping and no extra line spacing. MeasureTextEx, DrawTextEx and DrawTextPro require character spacing zero.

    CreateTextLayout takes all six TextOptions fields. font_size is finite 0.5..4096. direction is Auto, LTR or RTL; Auto uses the first strong character, with LTR for neutral-only paragraphs. has_width activates a finite positive width; otherwise width is inactive. alignment is Start, End, Center, Left or Right. Start/End follow the paragraph base direction; Left/Right are physical. line_spacing is finite and nonnegative.

    Wrapping uses ICU root line breaks, then emergency grapheme breaks. An oversized cluster may overflow the supplied 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 rules. Empty text has zero lines and height. NUL, tab, DEL and other unsupported Cc controls return raylib.invalid_text.

    MeasureTextLayout returns TextMetrics. size is the logical box, using the supplied width when active. ink is local glyph bounds including marks and overhangs. Effective font size rounds to 1/64 with ties to even. MeasureText accepts integer sizes 1..4096 and rounds the shaped width upward to checked i32; MeasureTextEx returns logical Vector2 size. These CPU operations work before window creation.

    Layouts are immutable shared owners. Unloading one alias closes all aliases and repeated unload succeeds. A layout retains its fonts after custom Font unload and survives window close/reopen. Access to a closed layout returns raylib.closed_resource; the validity probe returns false.

    Draw the measured positions

    DrawTextLayout draws at logical top-left. DrawTextLayoutPro adds origin and rotation. DrawTextEx and DrawTextPro shape the same logical text with zero character spacing. Origin, rotation and Camera2D transform placement without changing local metrics. Glyph-cache eviction preserves those metrics.

    Text drawing requires the application's main thread, a live window and an open drawing frame. A known validation, glyph, numeric or preparation failure submits none of that text request. Previously accepted draws remain valid. Accepted work may retain glyph backing after logical unload until presentation or native quiescence.

    The shaped text/audio family prepares and measures its layout before the window opens. Gray outlines show the logical box; red outlines show ink. The original OGG tone and CC0 notice are required external assets; default fonts are embedded.

    Native only · ASPL 0.7.0 · English source

    Execution: Native only · ASPL 0.7.0

    Prerequisites:
    • Native ASPL 0.7.0 on x86_64 Linux with glibc 2.34 or later.
    • Running needs a reachable Wayland/EGL or X11/GLX display and OpenGL 3.3 core. Checking/building need no devices, C compiler or system Raylib.
    • A reachable PulseAudio/PipeWire-compatible playback service or direct ALSA device. Embedded licensed default fonts require no font download.
    • Keep the supplied OGG and its CC0 notice in the asset tree shown on this page, relative to the process working directory.

    Input: No input lines are required.

    Download and prepare the required files before running:

    import core::raylib;
    
    fn start_main() -> i64 {
        // Layout and measurement need no display. Text stays in logical order.
        let loaded_font = raylib::GetFontDefault();
        if not loaded_font::ok { print(loaded_font::error::message); return 1; }
        let options = raylib::TextOptions {
            font_size: 32.0, direction: raylib::TEXT_DIRECTION_AUTO,
            has_width: true, width: 430.0, alignment: raylib::TEXT_ALIGNMENT_START,
            line_spacing: 4.0
        };
        let prepared = raylib::CreateTextLayout(loaded_font::value, "سلام ASPL 123\nبَِّ Hello", options);
        if not prepared::ok { print(prepared::error::message); return 2; }
        let layout = prepared::value;
        let measured = raylib::MeasureTextLayout(layout);
        if not measured::ok { print(measured::error::message); return 3; }
        let audio = raylib::InitAudioDevice();
        if not audio::ok { print(audio::error::message); return 4; }
        let loaded_music = raylib::LoadMusicStream("docs/examples/assets/raylib-tone.ogg");
        if not loaded_music::ok { print(loaded_music::error::message); return 5; }
        let music = loaded_music::value;
        if not raylib::SetMusicLooping(music, true)::ok or not raylib::PlayMusicStream(music)::ok { return 6; }
        let opened = raylib::InitWindow(500, 300, "Shaped text / نص مشكل");
        if not opened::ok { print(opened::error::message); return 7; }
        if not raylib::SetTargetFPS(60)::ok { return 8; }
        var frame: i32 = 0;
        while frame < 60 {
            let closing = raylib::WindowShouldClose();
            if not closing::ok { return 9; }
            if closing::value { return 0; }
            // Streaming advances only when the application calls UpdateMusicStream.
            if not raylib::UpdateMusicStream(music)::ok { return 10; }
            if not raylib::BeginDrawing()::ok or not raylib::ClearBackground(raylib::RAYWHITE)::ok { return 11; }
            let size = measured::value::size;
            let ink = measured::value::ink;
            let box = raylib::Rectangle { x: 30.0, y: 30.0, width: size::x, height: size::y };
            if not raylib::DrawRectangleLinesEx(box, 1.0, raylib::GRAY)::ok { return 12; }
            let ink_box = raylib::Rectangle { x: 30.0 + ink::x, y: 30.0 + ink::y, width: ink::width, height: ink::height };
            if not raylib::DrawRectangleLinesEx(ink_box, 1.0, raylib::RED)::ok { return 13; }
            if not raylib::DrawTextLayout(layout, raylib::Vector2 { x: 30.0, y: 30.0 }, raylib::BLACK)::ok { return 14; }
            if not raylib::EndDrawing()::ok { return 15; }
            frame = frame + 1;
        }
        if not raylib::UnloadMusicStream(music)::ok or not raylib::CloseAudioDevice()::ok { return 16; }
        if not raylib::CloseWindow()::ok or not raylib::UnloadTextLayout(layout)::ok { return 17; }
        print("shaped text and explicit music updates complete\n");
        return 0;
    }
    

    Follow the Linux instructions to run this example. Download the source to keep a copy.

    Download shaped-text-audio.aspl

    Expected outcomes
    {
      "native": {
        "check": 0,
        "status": 0,
        "behavior": {
          "en": "Up to 60 frames draw logical Arabic/Latin text and marks, with gray logical-box and red ink outlines. Looping OGG advances through explicit updates. Normal completion prints shaped text and explicit music updates complete followed by a newline and returns 0. Closing early also returns 0 without that final line.",
          "ar": "ترسم حتى 60 إطارا نصا عربيا ولاتينيا منطقيا وعلامات، بحدود رمادية للصندوق المنطقي وحمراء للحبر. يتقدم OGG المتكرر بتحديثات صريحة. يطبع الاكتمال الطبيعي shaped text and explicit music updates complete ثم سطرا جديدا ويعيد 0. يعيد الإغلاق المبكر أيضا 0 دون السطر النهائي."
        }
      }
    }

    Initialize audio and update music

    InitAudioDevice tries PulseAudio through libpulse.so.0, then direct ALSA through libasound.so.2, including playback-start failures. PipeWire works through its PulseAudio-compatible service. Each fallback requires complete safe release. A successful route stays fixed until close; there is no null-device success. Audio and window share the execution's process device lease but have separate close/rollback scopes.

    Load Sound or Music after audio initialization and outside drawing frames. LoadSound decodes copied WAV/OGG/MP3 bytes; LoadMusicStream retains copied bytes, decoder and bounded stream buffers independently of the original file. Playback, pause/resume/stop, volume, pan, pitch, seek, looping and UpdateMusicStream are application/main-thread operations permitted inside a frame. Volume is finite 0..1, pan finite -1..1 and pitch finite and positive. The derived resampling rate must fit the admitted native range; refusal preserves the prior pitch, while converter failure restores it or closes that owner.

    Playing streamed music alone does not decode or refill it. Call UpdateMusicStream explicitly, usually once per frame. GetMusicTimeLength and GetMusicTimePlayed report checked f32 seconds. SeekMusicStream admits 0..reported length inclusive. The endpoint means logical EOF; the next update restarts playing looping music or stops nonlooping/empty music. Paused/stopped updates stay inactive. Decoder seek refusal closes that Music's aliases and returns raylib.load_failed.

    Sound and Music copies share a closeable owner in the current audio generation. Unload stops/untracks playback; device close invalidates all dependents before native destruction. Reopen never revives old aliases. Backing and memory charges remain until mixer/decoder use ends, independent of playback completion. IsAudioDeviceReady, IsSoundValid and IsMusicValid are total probes; GetMusicLooping reads retained metadata. These may run in handlers/callbacks. Playback observations and SetMusicLooping still require application admission. The mixer never calls an ASPL source callback.

    Give HTTP and drawing explicit turns

    Import core::http as well as Raylib. HTTP guidance and the HTTP API own complete service declarations. start returns Session<C,S> after listeners are ready and dispatches no handler. Call progress outside drawing frames. Its default budget is 4096 instructions, 2 active ms and zero wait ms. Turns are bounded and serialized; OS/native work can overrun active_ms. A busy handler can yield at its instruction budget while the application continues drawing.

    EndDrawing and parked input may maintain transport/deadlines outside drawing but dispatch no source handler. Input inside a frame drives neither HTTP nor handlers. A blocking top-level HTTP client request against its own explicit server can time out. Arrange explicit progress frequently enough for the application.

    Application session state/configuration helpers can run inside a frame. Handler Context helpers remain live-handler-only. Reads copy state; snapshots keep hidden session/version identity and their read-only value survives close. Conditional publication replaces whole state and advances its version. A stale same-session snapshot returns successful false; a foreign-session snapshot returns http.invalid_argument. A saved owner/snapshot or callable grants no device/Context authority. Device calls are forbidden transitively in handlers; pure math, CPU text, total probes and read-only owner metadata remain permitted.

    stop_session starts drain; continue progress until SESSION_CLOSED. close_session revokes serving immediately without dispatching drain handlers. Repeated normal stop/close succeeds. Closed state helpers return http.closed_session; wrong frame/context returns http.invalid_order or http.invalid_context. Safely released host failures remain latched.

    The concurrent HTTP/frame family supplies original Arabic, English and mixed programs. Prepare the loopback upstream and clients described there. The square moves while /busy, /wait and /fast share turns; a delayed upstream lets the snapshot become stale. See HTTP deployment for TLS/trust facilities.

    Native only · ASPL 0.7.0 · English source

    Execution: Native only · ASPL 0.7.0

    Prerequisites:
    • Native ASPL 0.7.0 on x86_64 Linux with glibc 2.34 or later.
    • Running needs a reachable Wayland/EGL or X11/GLX display and OpenGL 3.3 core. Checking/building need no devices, C compiler or system Raylib.
    • Free loopback ports 8000 and 8001. Prepare the local upstream and independent concurrent clients as shown on this page. Delaying the upstream makes the stale snapshot reproducible. No source modules or file assets are needed.

    Input: No input lines are required.

    // Run an upstream HTTP server on 127.0.0.1:8001, then request /busy, /wait and
    // /fast on port 8000. The window keeps drawing while the handlers share turns.
    import core::raylib;
    import core::http;
    
    record State { frames: i64, busy: bool, fast: bool, conflict: bool }
    
    fn outbound(ctx: http::Context<string,State>, saved: i64) -> http::ServerResponse {
        let snapshot = http::snapshot_state(ctx);
        let request = http::client_request("GET", http::read_config(ctx))::value;
        let reply = http::request(request, http::client_options());
        if not reply::ok {
            return http::text_response(502, reply::error::code, "text/plain")::value;
        }
        if saved not matches 7 { return http::response(500, [])::value; }
        let published = http::replace_state_if_current(ctx, snapshot, snapshot::value)::value;
        var current = http::read_state(ctx);
        current::conflict = not published;
        http::replace_state(ctx, current);
        return http::text_response(200, "conflict", "text/plain")::value;
    }
    
    fn handler(req: http::IncomingRequest, ctx: http::Context<string,State>) -> http::ServerResponse {
        if req::path matches "/busy" {
            var state = http::read_state(ctx);
            state::busy = true;
            http::replace_state(ctx, state);
            while true {}
        }
        if req::path matches "/wait" { return outbound(ctx, 7); }
        var current = http::read_state(ctx);
        current::fast = raylib::IsWindowReady();
        http::replace_state(ctx, current);
        return http::text_response(200, "fast", "text/plain")::value;
    }
    
    fn start_main() -> i64 {
        let opened = raylib::InitWindow(480, 240, "ASPL HTTP and drawing");
        if not opened::ok { print(opened::error::code); return 1; }
        let pacing = raylib::SetTargetFPS(60);
        if not pacing::ok { return 9; }
        var server = http::server_config();
        server::listeners = [http::listener("127.0.0.1", 8000)::value];
        let routes = http::router([
            http::route("GET", "/busy", handler)::value,
            http::route("GET", "/wait", handler)::value,
            http::route("GET", "/fast", handler)::value
        ])::value;
        let started = http::start(server, routes, "http://127.0.0.1:8001/",
            State {frames: 0, busy: false, fast: false, conflict: false});
        if not started::ok { print(started::error::code); return 2; }
        let owner = started::value;
        print("ready\n");
        var budget = http::progress_budget();
        budget::max_instructions = 128;
        var frames: i32 = 0;
        while frames < 180 and not raylib::WindowShouldClose()::value {
            if not http::progress(owner, budget)::ok { return 3; }
            if not raylib::BeginDrawing()::ok { return 4; }
            if not raylib::ClearBackground(raylib::RAYWHITE)::ok { return 10; }
            var state = http::snapshot_session_state(owner)::value::value;
            state::frames = state::frames + 1;
            if not http::replace_session_state(owner, state)::ok { return 5; }
            if not raylib::DrawRectangle(frames, 90, 40, 40, raylib::BLUE)::ok { return 11; }
            if not raylib::EndDrawing()::ok { return 6; }
            frames = frames + 1;
        }
        let final = http::session_state(owner)::value;
        if not http::close_session(owner)::ok { return 7; }
        if not raylib::CloseWindow()::ok { return 8; }
        if final::busy and final::fast and final::conflict {
            print("busy fast conflict\n");
        }
        return 0;
    }
    

    Follow the Linux instructions to run this example. Download the source to keep a copy.

    Download concurrent-http.aspl

    Expected outcomes
    {
      "native": {
        "check": 0,
        "status": 0,
        "behavior": {
          "en": "A square moves for up to 180 frames. The program prints ready followed by a newline after listener startup. Concurrent busy, wait and fast requests exercise bounded handler turns and a stale snapshot. It prints busy fast conflict followed by a newline only if all three observations occur, then returns 0. Client timing and early window closure affect that final line.",
          "ar": "يتحرك مربع حتى 180 إطارا. يطبع البرنامج ready ثم سطرا جديدا بعد بدء المستمع. تفحص طلبات busy وwait وfast المتزامنة أدوار المعالج المحدودة ولقطة قديمة. يطبع busy fast conflict ثم سطرا جديدا فقط عند تحقق الملاحظات الثلاث، ثم يعيد 0. يؤثر توقيت العملاء والإغلاق المبكر في السطر النهائي."
        }
      }
    }

    Preserve aliases, user identity and literals

    Exact supplied aliases name the same types/operations. Both aliases of one supplied record field count as a duplicate. User records and fields keep their written names. Locale switching selects documentation, not source translation. Strings keep decomposed characters and NUL bytes; a path-shaped literal is not a file read. Text, path and title operations separately enforce their allowed input.

    The identity/literals family runs without graphics, audio or an upstream. It uses embedded shaped measurement, exact record/enum/flag aliases and the pure HTTP progress budget. Its ordinary unsafe libc.so.6 abs call retains the C-interoperability contract. It prints a bilingual invalid-tab diagnostic, a literal PNG path and decomposed/NUL content. No PNG download is required.

    Text error messages 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 result fields or a message-parsing API. Unsupported controls are escaped in the diagnostic, while ordinary output keeps literal bytes.

    Native only · ASPL 0.7.0 · English source

    Execution: Native only · ASPL 0.7.0

    Prerequisites:
    • Native ASPL 0.7.0 on x86_64 Linux with glibc 2.34 or later.
    • No display, audio device, upstream, asset files or source modules. Shaped measurement uses embedded licensed fonts; the unsafe abs call uses the baseline system C library.

    Input: No input lines are required.

    import core::raylib;
    import core::http;
    
    unsafe foreign absolute(number: i32) -> i32 = c("libc.so.6", "abs");
    
    // User identifiers and record fields keep their own names in all three files.
    record Asset { filename: string, untouched: string }
    
    fn start_main() -> i64 {
        if unsafe absolute(-7) not matches 7 { return 11; }
        let asset = Asset { filename: "docs/examples/assets/raylib-sprites.png", untouched: "مسار/é.png\0A" };
        if asset::filename not matches "docs/examples/assets/raylib-sprites.png" { return 1; }
        if asset::untouched not matches "مسار/e\u{0301}.png\0A" { return 2; }
        let a: raylib::Vector2 = raylib::Vector2 { x: 1.25, y: 2.5 };
        let b: raylib::Vector2 = raylib::Vector2 { x: a::x, y: a::y };
        if b::x not matches 1.25 or b::y not matches 2.5 { return 3; }
        let key: raylib::Key = raylib::KEY_SPACE;
        if key not matches raylib::KEY_SPACE { return 4; }
        let flags = raylib::FLAG_WINDOW_RESIZABLE | raylib::FLAG_VSYNC_HINT;
        if flags not matches raylib::FLAG_WINDOW_RESIZABLE | raylib::FLAG_VSYNC_HINT { return 5; }
        let budget: http::ProgressBudget = http::progress_budget();
        if budget::max_instructions not matches 4096 { return 6; }
        let font = raylib::GetFontDefault();
        if not font::ok { print(font::error::message); return 7; }
        let english = raylib::MeasureTextEx(font::value, "سلام ASPL 123", 32.0, 0.0);
        let arabic = raylib::MeasureTextEx(font::value, "سلام ASPL 123", 32.0, 0.0);
        if not english::ok or not arabic::ok { return 8; }
        if english::value::x not matches arabic::value::x { return 9; }
        let invalid = raylib::MeasureText("bad\ttext", 32);
        if invalid::ok or invalid::error::code not matches "raylib.invalid_text" { return 10; }
        print(invalid::error::message); print("\n");
        print(asset::filename); print("\n");
        print(asset::untouched); print("\nidentity and literals complete\n");
        return 0;
    }
    

    Follow the Linux instructions to run this example. Download the source to keep a copy.

    Download identity-literals.aspl

    Expected outcomes
    {
      "native": {
        "check": 0,
        "status": 0,
        "behavior": {
          "en": "Runs headlessly with status 0. It prints the bilingual invalid-tab diagnostic with the tab's zero-based scalar position and Unicode value, a literal PNG path, decomposed e plus U+0301 and an actual NUL before A, then identity and literals complete. The path is never opened. All supplied variants have identical output bytes.",
          "ar": "يعمل دون أجهزة بحالة 0. يطبع رسالة الجدولة غير الصالحة باللغتين مع موضع محرف الجدولة من الصفر وقيمة Unicode له، ومسار PNG نصيا، وe مفككة مع U+0301 وNUL فعلية قبل A، ثم identity and literals complete. لا يفتح المسار. لكل الصيغ الموردة بايتات إخراج متطابقة."
        },
        "output": "Text input is invalid. مدخل النص غير صالح. MeasureText: text.input: scalar_index=3 scalar=U+0009.\ndocs/examples/assets/raylib-sprites.png\nمسار/é.png\u0000A\nidentity and literals complete\n"
      }
    }

    Finish and release resources

    Check explicit unload/close results on normal completion. Return, trap, limit or cancellation revokes source work and abandons an open frame without intentionally presenting a final frame. Cleanup releases GPU work before its window and mixer/decoder work before its audio device. Backing and charges remain retained when native release cannot be proved. Driver hangs have no hard in-process preemption guarantee.

    Default limits are 256 MiB for the VM and one shared 128 MiB Raylib/HTTP backend account. Refusal before native entry preserves state; failure after native effects promises owned cleanup rather than general rollback. See limits and errors.

    When distributing an ELF program, keep its generated .THIRD-PARTY-NOTICES companion and required assets/notices. A generated program runs without the source or ASPL compiler but still needs the documented Linux graphics facilities. The original guide source (opens in a new tab) remains an exact published download.

    The first SIGINT/SIGTERM permanently stops application code, cancels parked input/application requests and drains only already admitted HTTP handlers outside drawing. A second signal revokes remaining drain. Traps, limits and other cancellation dispatch no drain handlers. Remaining-resource cleanup uses one deadline t + max(R,H), capped by earlier execution and operation/session scopes; retries never renew it. R is Raylib's cleanup 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 and closed headers add none. Terminal statuses retain trap 5, limit 6, cancellation 7 and host failure 8, with separate cleanup attribution for an earlier primary outcome.

    Deploy with the actual host dependencies

    The tool and generated programs target x86_64 Linux with glibc 2.34 or later. They are ELF64 PIE with interpreter /lib64/ld-linux-x86-64.so.2, direct dependencies libc.so.6 and libm.so.6, RELRO, immediate binding, non-executable stack and no RPATH/RUNPATH. Dynamically loaded host graphics/audio libraries bring their own dependency closures, permissions and drivers. CPU text and pure helpers require only the CPU/glibc baseline; an import alone acquires no display or audio device.

    Route Required host libraries and facilities
    X11 or XWayland libX11.so.6, libXxf86vm.so.1, libXi.so.6, libXrandr.so.2, libXcursor.so.1, libXinerama.so.1, libXrender.so.1, libXext.so.6; GLX tries libGLX.so.0, then libGL.so.1. Authorized DISPLAY and OpenGL 3.3 core.
    Wayland libwayland-client.so.0, libwayland-cursor.so.0, libwayland-egl.so.1, libxkbcommon.so.0, libEGL.so.1; compositor/subcompositor, xdg-shell, shared memory, keyboard/pointer, usable outputs and cursor theme. Non-libdecor desktop OpenGL 3.3 core; missing EGL GL procedures try libOpenGL.so.0, then libGL.so.1.
    PulseAudio or PipeWire-compatible service libpulse.so.0, reachable playback service and usable endpoint.
    Direct ALSA libasound.so.2, permitted usable playback device.

    Host loading uses normal loader search with immediate/local scope and required symbol checks. Development symlinks are unnecessary. Display selection follows host preparation; audio tries PulseAudio then ALSA. Invalid arguments, resource refusal, cancellation or unproved cleanup stop retries. All safely failed candidates report the final candidate's category and attempted backends. No graphics/audio route substitutes headless success.

    The tool embeds Raylib 6.0, HarfBuzz 14.4.0, ICU 78.3 with full Unicode 17.0.0 data, FreeType 2.14.3 and the default fonts. Application check/build invokes no C compiler, assembler or linker and acquires no device. Recipients need no ASPL runtime, system Raylib, host fonts or source. PNG, WAV/OGG/MP3 and custom font files remain external when used. Preserve working-directory paths and their licenses.

    After downloading the shaped family and its OGG/notice into the stated tree:

    mkdir -p deploy/docs/examples/assets
    aspl build -o deploy/shaped docs/examples/raylib/shaped-text-audio.aspl
    cp docs/examples/assets/raylib-tone.ogg docs/examples/assets/raylib-tone.NOTICE deploy/docs/examples/assets/
    cd deploy
    ./shaped --aspl-diagnostic-language=en

    Ship <program>.THIRD-PARTY-NOTICES beside the executable with asset notices. Runtime does not read the companion. Build publishes it atomically first, then the executable. Notice failure prevents executable publication; later executable failure preserves the old executable and reports the already published notice. Source/module collisions report output-is-source, executable/companion aliases output-path-collision, and unsafe/write/publication failures host-operation-failed with phase/path/partial-result details. Source runs create no companion.

    The whole import graph, including unused/transitive imports, selects core, HTTP, Raylib or combined prepared programs. Core/HTTP-only outputs add no Raylib/font/device requirements. Private bytecode/catalog/preparation records must match the selected tool; they are not a stable public ABI. Previously distributed self-contained programs retain their embedded identities. Installation, system requirements, downloads and HTTP deployment provide the related workflows. The original deployment source (opens in a new tab) retains its released bytes and evidence scope.

    Historical normative scope

    • Historical specification, English source

      Historical MVP foreign-operation background only; native Raylib text/audio/drawing/HTTP is a later extension audited against published ASPL 0.7.0, not an MVP requirement

    Browse pages