Frame lifecycle: InitWindow through CloseWindow

raylib does not provide main() or a game loop. The contract is: initialize once, loop until close, shut down. This page traces that contract through CORE state and the functions every example uses.

Minimal program shape

#include "raylib.h"

int main(void)
{
    InitWindow(800, 450, "my game");
    SetTargetFPS(60);

    while (!WindowShouldClose())
    {
        // update logic here
        BeginDrawing();
        ClearBackground(RAYWHITE);
        DrawText("Hello", 190, 200, 20, DARKGRAY);
        EndDrawing();
    }

    CloseWindow();
    return 0;
}

examples/core/core_basic_window.c

InitWindow sequence

InitWindow(w, h, title)
  ├─ init CORE.Window, CORE.Input (exit key = ESC)
  ├─ InitPlatform()          // GLFW: glfwInit, create window, GL context
  ├─ rlglInit(renderW, renderH)   // default texture, shader, batch
  ├─ SetupViewport(...)
  ├─ LoadFontDefault()       // if SUPPORT_MODULE_RTEXT
  ├─ SetShapesTexture(...)   // share font atlas with rshapes batching
  └─ SetRandomSeed(time(NULL))

Failure mode: If InitPlatform() returns non-zero, InitWindow logs a warning and returns early. IsWindowReady() stays false and WindowShouldClose() returns true immediately.

BeginDrawing — start of draw phase

Updates CORE.Time.current and CORE.Time.update (seconds since last BeginDrawing). Resets modelview with rlLoadIdentity() and applies CORE.Window.screenScale for Retina/HiDPI.

Does not clear the framebuffer — you must call ClearBackground or draw over previous contents.

rcore.c L858–872

EndDrawing — flush, present, poll
  1. rlDrawRenderBatchActive() — flush 2D batch to GPU
  2. SwapScreenBuffer() — platform (e.g. glfwSwapBuffers)
  3. Measure draw time; WaitTime() if under target frame time
  4. PollInputEvents() — update keyboard/mouse/gamepad state
  5. Increment CORE.Time.frameCounter

rcore.c L875–917

Render modes that flush the batch

Switching render context always calls rlDrawRenderBatchActive() first:

  • BeginMode2D / EndMode2D — 2D camera matrix
  • BeginMode3D / EndMode3D — perspective + depth test
  • BeginTextureMode / EndTextureMode — render to FBO
  • BeginShaderMode — custom shader

Mixing 2D and 3D in one frame requires these pairs — otherwise batch state and GL state desync.

WindowShouldClose and ESC

On GLFW, PollInputEvents sets CORE.Window.shouldClose from glfwWindowShouldClose, then resets the GLFW flag so closing is driven by raylib's state. CORE.Input.Keyboard.exitKey defaults to KEY_ESCAPE.

rcore_desktop_glfw.c L1407–1410

CloseWindow teardown

UnloadFontDefault()rlglClose()ClosePlatform() (e.g. glfwTerminate). Sets CORE.Window.ready = false.

rcore.c L723–738

CORE global state

CoreData CORE holds nested structs:

  • Window — dimensions, flags, shouldClose, screenScale matrix
  • Input.Keyboard/Mouse/Touch/Gamepad — current + previous state arrays
  • Time — current, update, draw, frame, target FPS interval

rcore.c L296–399 — CoreData

Frame loop simulator

Same demo as the overview — step through poll → draw → flush → swap.

0Frame #
Poll inputPhase
0Batch verts