diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 572fc91..d0a1fdd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -30,7 +30,9 @@ jobs:
"3.12",
"3.13",
"3.14",
+ "3.15",
"pypy-3.11",
+ "pypy-3.12",
]
raylib-platform: ["Desktop", "SDL"]
env:
@@ -142,10 +144,10 @@ jobs:
runs-on: macos-14
strategy:
matrix:
- python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15", "pypy-3.11", "pypy-3.12"]
raylib-platform: ["Desktop", "SDL"]
env:
- MACOSX_DEPLOYMENT_TARGET: "11"
+ MACOSX_DEPLOYMENT_TARGET: "12.0"
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
@@ -255,11 +257,13 @@ jobs:
image: electronstudio/ubuntu16-modern:latest
options: --user root
volumes:
- # override /__e/node20 because GitHub Actions uses a version that requires too-recent glibc
+ # override /__e/node20 AND /__e/node24 with the image's own node because the nodes
+ # that GitHub Actions provides require too-recent glibc. Still needed for node
+ # actions such as actions/upload-artifact (we no longer use actions/checkout, we
+ # just run git directly). Since June 2026 the runner resolves ALL js actions to
+ # /__e/node24, so both paths must be overridden.
- /tmp:/__e/node20
- env:
- # Github Actions Checkout now wants Node 24. Maybe easier just to stop using Checkout than keep messing around with Node.
- ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
+ - /tmp:/__e/node24
strategy:
# You can use PyPy versions in python-version.
# For example, pypy2 and pypy3
@@ -274,13 +278,27 @@ jobs:
"python3.12",
"python3.13",
"python3.14",
+ "python3.15",
"pypy3.11",
+ "pypy3.12"
]
raylib-platform: ["Desktop", "SDL", "DRM", "SDL_SOFT"]
steps:
+ # Must be the first step so the workspace is empty and git clone works
+ - name: Checkout
+ run: |
+ # workspace dir is owned by the host runner user but we are root in the
+ # container, so tell git that is OK (avoids "dubious ownership" error)
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
+ git clone ${{ github.server_url }}/${{ github.repository }} .
+ git fetch --force origin "${{ github.ref }}"
+ git checkout --force FETCH_HEAD
+ git submodule update --init --recursive
+
- name: fix node
run: |
ln -s /usr/local/bin /__e/node20/bin
+ ln -s /usr/local/bin /__e/node24/bin
- name: setup wayland
run: |
@@ -303,10 +321,6 @@ jobs:
cmake --build . --config Release
cmake --install .
- - uses: actions/checkout@v2
- with:
- submodules: recursive
-
- name: fix raygui bug
run: |
patch -p0 On most platforms it should install a binary wheel. If yours isn’t available then pip will attempt to build from
@@ -213,7 +213,7 @@ Platforms: Windows, Mac, Linux, Raspberry Pi, Web
Quickstart
-pip3 install raylib==6.0.1.0 --break-system-packagespip3 install raylib==6.0.1.1 --break-system-packagesfrom pyray import *
-init_window(800, 450, "Hello")
+init_window(800, 450, "Hello")
while not window_should_close():
begin_drawing()
clear_background(WHITE)
- draw_text("Hello world", 190, 200, 20, VIOLET)
+ draw_text("Hello world", 190, 200, 20, VIOLET)
end_drawing()
close_window()
Installation
python3 -m pip install setuptools
-python3 -m pip install raylib==6.0.1.0
+python3 -m pip install raylib==6.0.1.1
MacOSOlder MacOS requires building from source but this is usually simple:
brew install pkg-config
brew install raylib
-python3 -m pip install raylib==6.0.1.0
+python3 -m pip install raylib==6.0.1.1
main.py:
# /// script
# dependencies = [
-# "cffi",
-# "raylib"
+# "cffi",
+# "raylib"
# ]
# ///
import asyncio
@@ -297,12 +297,12 @@ Running in a web browserfrom pyray import *
async def main(): # You MUST have an async main function
- init_window(500, 500, "Hello")
+ init_window(500, 500, "Hello")
platform.window.window_resize() # You MAY want to add this line
while not window_should_close():
begin_drawing()
clear_background(WHITE)
- draw_text("Hello world", 190, 200, 20, VIOLET)
+ draw_text("Hello world", 190, 200, 20, VIOLET)
end_drawing()
await asyncio.sleep(0) # You MUST call this in your main loop
close_window()
@@ -317,7 +317,7 @@ Running in a web browserif platform.system() != "Emscripten": # audio may not work on current version of emscripten
+if platform.system() != "Emscripten": # audio may not work on current version of emscripten
init_audio_device()
@@ -331,7 +331,7 @@ Startup without printing anythinglogging.basicConfig(level=logging.ERROR)
import pyray
pyray.set_trace_log_level(pyray.LOG_ERROR)
-pyray.init_window(100,100,"test")
+pyray.init_window(100,100,"test")
Example program:
import pyray as pr
-pr.init_window(800, 450, "Hello Pyray")
+pr.init_window(800, 450, "Hello Pyray")
pr.set_target_fps(60)
camera = pr.Camera3D([18.0, 16.0, 18.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], 45.0, 0)
@@ -2551,7 +2551,7 @@ Examples
pr.begin_mode_3d(camera)
pr.draw_grid(20, 1.0)
pr.end_mode_3d()
- pr.draw_text("Hello world", 190, 200, 20, pr.VIOLET)
+ pr.draw_text("Hello world", 190, 200, 20, pr.VIOLET)
pr.end_drawing()
pr.close_window()
You can also now import the functions with no prefix:
from pyray import *
-init_window(800, 450, "Raylib texture test")
+init_window(800, 450, "Raylib texture test")
...
from raylib import *
-InitWindow(800, 450, b"Hello Raylib")
+InitWindow(800, 450, b"Hello Raylib")
SetTargetFPS(60)
-camera = ffi.new("struct Camera3D *", [[18.0, 16.0, 18.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], 45.0, 0])
+camera = ffi.new("struct Camera3D *", [[18.0, 16.0, 18.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], 45.0, 0])
while not WindowShouldClose():
UpdateCamera(camera, CAMERA_ORBITAL)
@@ -2517,7 +2517,7 @@ C APIBeginMode3D(camera[0])
DrawGrid(20, 1.0)
EndMode3D()
- DrawText(b"Hellow World", 190, 200, 20, VIOLET)
+ DrawText(b"Hellow World", 190, 200, 20, VIOLET)
EndDrawing()
CloseWindow()
from raylib import ffi, rl, colors
-rl.InitWindow(800, 450, b"Hello Raylib")
+rl.InitWindow(800, 450, b"Hello Raylib")
rl.SetTargetFPS(60)
...