Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
90e846e
chore(examples): keep unfinished prototypes local
espressif2022 Oct 8, 2026
3214826
feat(release): prepare standalone component and packaged examples
espressif2022 Oct 8, 2026
34c92fd
docs: clarify supported workflows and simplify project guides
espressif2022 Oct 8, 2026
40d395a
feat(examples): restore Neon Rift Rally and disable Iris by default
espressif2022 Oct 8, 2026
4edba99
test: colocate game suites and trim brittle checks
espressif2022 Oct 8, 2026
dd61ae9
perf(renderer): optimize triangle spans and opaque texture tint
espressif2022 Oct 8, 2026
51d1c92
fix(ci): package board partitions and use the published IDF image
espressif2022 Oct 8, 2026
2548c80
fix(integration): align standalone games, board overrides and release…
espressif2022 Oct 9, 2026
3136d01
refactor: move Iris application services out of native boards
espressif2022 Oct 9, 2026
0dfa5f1
build: pin decoupled BSP and simplify local board overrides
espressif2022 Oct 9, 2026
da07924
build: pin BSP without obsolete splash component
espressif2022 Oct 9, 2026
2c35c74
refactor: use Board Manager and shared presenter in native boards
espressif2022 Oct 9, 2026
670adc0
build: validate BMGR profiles and expand release consumer checks
espressif2022 Oct 9, 2026
ab2894e
ci: generate Mosaico BMGR configuration before configure
espressif2022 Oct 9, 2026
a743377
refactor(examples): centralize game defaults and partitions in boards
espressif2022 Oct 9, 2026
a81c769
ci: validate release consumers with ESP-IDF v6.1 and latest
espressif2022 Oct 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
with:
python-version: '3.12'
- name: Install Host dependency
run: python3 -m pip install Pillow
run: python3 -m pip install Pillow numpy PyYAML
- name: Check maintained Markdown links
run: python3 tools/check_markdown_links.py
- name: Check whitespace
Expand Down
96 changes: 96 additions & 0 deletions .github/workflows/release-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Registry package, IDF consumer and component upload
on:
pull_request:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
package-and-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Assemble, pack and build an isolated consumer
uses: espressif/esp-idf-ci-action@v1
with:
# Use public IDF development images until a stable 6.2 image exists.
# Pin this to the verified release image when 6.2 is released.
esp_idf_version: master
target: esp32s3
path: '.'
command: |
python -m pip install Pillow numpy PyYAML
python tools/prepare_release.py --output /tmp/raylib-release
compote component pack --project-dir /tmp/raylib-release/component --name raylib-lite-engine --dest-dir /tmp/raylib-release/archives
python tools/check_release.py --stage /tmp/raylib-release > /tmp/raylib-release/package-check.json
cat /tmp/raylib-release/package-check.json
python tools/prepare_release_consumer.py --archive /tmp/raylib-release/archives/raylib-lite-engine_$(cat VERSION).tgz --example minimal --output /tmp/raylib-consumer
idf.py -C /tmp/raylib-consumer -B /tmp/raylib-consumer-build -DIDF_TARGET=esp32s3 build
mkdir -p dist
cp /tmp/raylib-release/archives/*.tgz dist/
cp /tmp/raylib-release/release-manifest.json dist/
cp /tmp/raylib-release/package-check.json dist/
- uses: actions/upload-artifact@v4
with:
name: registry-release-candidate
path: dist/

upload_components:
name: Upload assembled component to Espressif Component Service
needs: package-and-build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/download-artifact@v4
with:
name: registry-release-candidate
path: release-artifacts
- name: Verify and unpack the checked release archive
env:
RELEASE_SOURCE_SHA: ${{ github.sha }}
run: |
python -m pip install PyYAML
python - <<'PY'
import hashlib
import json
import os
from pathlib import Path
import tarfile
import yaml

artifacts = Path("release-artifacts")
checks = json.loads((artifacts / "package-check.json").read_text())
if len(checks["archives"]) != 1:
raise SystemExit("Expected exactly one checked component archive")
expected = checks["archives"][0]
archive = artifacts / expected["file"]
if archive.name != expected["file"]:
raise SystemExit("Invalid archive filename")
if hashlib.sha256(archive.read_bytes()).hexdigest() != expected["sha256"]:
raise SystemExit("Release archive checksum mismatch")
component = Path("publish/raylib-lite-engine")
component.mkdir(parents=True)
with tarfile.open(archive) as stream:
stream.extractall(component, filter="data")
# The uploader otherwise records this generated folder as the source
# repository path. Source lives at the actual repository root.
manifest = component / "idf_component.yml"
data = yaml.safe_load(manifest.read_text())
data["repository_info"] = {"path": ".", "commit_sha": os.environ["RELEASE_SOURCE_SHA"]}
manifest.write_text(yaml.safe_dump(data, sort_keys=False))
PY
- name: Upload components to component service
uses: espressif/upload-components-ci-action@v1
with:
directories: publish/raylib-lite-engine
name: raylib-lite-engine
namespace: espressif2022
api_token: ${{ secrets.COMPONENTS_TOKEN }}
# Preserve explicit root-source metadata in the assembled manifest.
repository_url: ''
commit_sha: ''
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,15 @@ artifacts/
**/.codex-runs/
# Local documentation drafts, experiment logs, and historical snapshots.
/docs/debug/

# Unfinished local experiments
/examples/*_dev/
/examples/vertical_dock_dev/
/examples/vector_cat_dev/
/examples/vector_pet_dev/
/examples/vector_puppet_dev/
/examples/sewer_labyrinth_dev/

# Local integration backups and generated release output
/*.patch
/dist/
75 changes: 75 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Public API and application contract

## Installation and compatibility

The component exports `include/raylib_lite/` and the separate Raylib facade under
`compat/raylib/include/`. Prefer neutral `raylib_lite_*` types for new integrations.
Public Engine headers do not expose BSP or ESP-IDF types. See [the English guide](README.md).
The historical `mosaico_*` extraction requires source migration. Public result
values are explicit; new values are appended. Host/module ABI versions are
separate from the component release version; see [Host ABI](host/README.md).

## Lifecycle and threads

1. The application creates its clock, input queue and video backend. Initialize
display workers and optional audio before invoking the game app.
2. Call `raylib_lite_game_app_run()` on the application's game thread. The Engine
does not create that thread or choose its CPU affinity/priority.
3. `on_start` initializes game resources. After it has been entered, `on_stop`
runs exactly once on every exit path, including partial startup failure.
4. `on_first_present` runs only after an accepted first frame has been flushed.
It is the application hook for device health confirmation.
5. After the app returns, stop producers/workers, drain outstanding video/audio
work, then destroy the application-owned backend and input queue.

Callbacks run on the calling game thread. Renderer state, facade globals and game
resources require serialized access; they are not an independent context per task.
Use the input queue to cross producer/game thread boundaries rather than calling
render or gameplay functions from interrupt/USB workers. Supply both queue
lock/unlock callbacks for cross-thread use; without them every queue call must
be externally serialized. The lock implementation must fit the producer context;
ordinary task locks do not authorize calling queue operations from an ISR.
Keep callbacks bounded.

## Frame ownership and errors

`get_info` describes a fixed native-endian RGB565 surface. Stride is in pixels
and must be at least width. The backend performs any transfer byte swapping.
A successful `acquire` lends one exclusively writable frame; its opaque token
belongs to the backend. The Engine holds at most one acquired frame.

`present` consumes the frame on **every** return path, including BUSY, TIMEOUT
and failures. Never access pixels after present or discard. Accepted asynchronous
frames may still be in flight; `flush` waits for the documented consumer release
point. An accepted frame is not proof that a human has seen it on the display.
`discard` consumes an unpresented frame and must not block.

Check `raylib_lite_result_t`; invalid configuration and lifecycle errors require
correction. Temporary backpressure must not be reported as successful presentation.
Use a finite timeout unless an operation explicitly permits
`RAYLIB_LITE_WAIT_FOREVER`. The public header comments are authoritative for each
function's specific ownership and return behavior.

## Scheduling, input, assets, audio and save

- `raylib_lite_runner_run` can be used without a display. It separates logic Hz
from target presentation FPS, limits catch-up to three updates per pass, and
discards stale credits after stalls. The clock must be monotonic.
- The launcher owns input producers and shutdown ordering. Gameplay consumes
queued events on its own thread. Define a policy for queue overflow.
- Mounted/registered asset memory must remain valid while loaded resources or
streams reference it. Close streams and unload textures before unmounting.
Do not mutate backing data while it is being rendered.
- Audio is optional: a NULL platform audio backend is a supported configuration.
The application owns the output device and audio worker. Stop playback and
workers before freeing their memory; the Board implements the game facade.
- The IDF save backend uses NVS. The application owns NVS initialization and
its partition choice. Handle save failures; Engine installation does not
create or replace the application's partition table.

## Product integrations

BSP, display DMA, JPEG acceleration, haptics, Iris and Recovery are application
or example Board policy. Installing this component alone does not create USB
services, provision Recovery or authorize flashing. The minimal offscreen
example exercises installation without these product dependencies.
22 changes: 12 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

## Unreleased

- Added `docs/README.md` and `host/README.md` for this repository's sim and
flash workflow; aligned example READMEs to `tools/game_cli.py` and the
5MB `factory` slot. Dropped unused `asset_prepare` / `tick_hz` keys.
- Grew the example `factory` app slot from 1.75MB to 5MB so `idf.py flash`
can hold Last Zone and Living Worlds; `ota_0` and `game_assets` shift
after it on the 16MB map.
- Pull `esp-mosaico-bsp` from Git with the Component Manager.
- Removed ESP-Iris from the engine and examples: no `esp_iris` manifest,
no Recovery cmake, no screen-mirror RPC, and `mosaico_game_iris` is gone.
- Prepared the single Engine component for Registry distribution with explicit
package filters, a minimal offscreen consumer, API contracts and release CI.
- Registry game examples are assembled with private copies of their shared
launcher and Board; downloaded examples require no sibling source directory.
- Kept BSP, Iris USB and Recovery application services in the example Board;
the Engine itself does not depend on these product components. Board dependencies
resolve from pinned Git revisions without mandatory environment exports.
- Native games use the Board partition table; vibe generates a retained Recovery
layout and installs normal games into `ota_0`. Recovery provisioning remains separate.
- Imported Sky Hop, Tower Defense, Raylib Shooter, Living Worlds, Last Zone,
and Tomb Raycast from ESP-Mosaico Vibe into `examples/`, with Host CLI
templates and game-development guides.
Expand Down Expand Up @@ -53,4 +53,6 @@
- Split the reusable game runtime and tools from ESP-Mosaico Vibe while
preserving their Git history.
- Added explicit GSP compiler and recovery-component integration paths.
- Preserved the existing `mosaico_*` API for source compatibility.
- Initial extraction used the `mosaico_*` names. The current independent Engine
uses `raylib_lite_*`; this is a source migration and is not ABI-compatible
with the historical extraction.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Raylib Lite Engine single ESP-IDF component definition.
# IDF derives the component name from this repository directory basename, so
# consumers depend on the root component as `raylib-lite-engine`.
# IDF resolves local and namespaced Registry installations; consumers use
# the manifest dependency espressif2022/raylib-lite-engine.
get_filename_component(RAYLIB_LITE_ENGINE_ROOT "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE)

set(RAYLIB_LITE_WALL_MODE "0" CACHE STRING "0 legacy, 1 exact, 2 fixed, 3 error bounded")
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.EN.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to Raylib Lite Engine

[简体中文](CONTRIBUTING.CN.md) · [Documentation](docs/README.EN.md)
[简体中文](CONTRIBUTING.CN.md) · [Documentation](docs/README.md)

Start with the [quickstart](docs/quickstart.EN.md), then choose the affected build path from the [matrix](docs/build-matrix.EN.md). Keep gameplay models and shared views portable; concrete native-example board services belong under `examples/boards/<board>/`, and game sources depend only on the shared example-board contract. Product-specific integration remains external. Use existing public APIs from the [capability catalog](docs/engine-capabilities.EN.md) before adding a game-local helper.

Expand Down
3 changes: 0 additions & 3 deletions CONTRIBUTING.md

This file was deleted.

48 changes: 26 additions & 22 deletions README.CN.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,50 @@
# Raylib Lite Engine

[English](README.EN.md) · [文档索引](docs/README.CN.md)
[English](README.md) · [开发文档](docs/README.CN.md)

Raylib Lite Engine 是面向嵌入式 RGB565 显示的轻量 Raylib 兼容游戏运行时,提供固定步长更新、软件光栅、资源打包和 PC Host 仿真。它不是 raylib 官方项目,也不代表 raylib 官方背书。
面向 ESP-IDF 的轻量游戏运行时与 RGB565 软件渲染引擎,提供固定步长更新、输入处理、资源加载、音频混合,以及场景和 UI 工具。游戏可在 PC Host 上开发和回放,再构建为设备原生固件。

引擎维护共享游戏代码、Host 后端和 ESP-IDF 集成;示例或产品固件负责选择板卡并提供设备服务。Engine 公共 API 已统一为 `raylib_lite_*` 命名;Raylib-shaped 源码兼容层只位于 `compat/raylib/`,neutral Engine header 不再暴露 ESP-IDF 或 Raylib 类型。
## 主要功能

## 从哪里开始
- RGB565 软件绘制:精灵、文字、瓦片地图、纹理三角形与四边形、光线投射墙面。
- 固定步长游戏循环、输入队列和触摸动作映射。
- 图集、地图、PCM / IMA-ADPCM 音频资源打包。
- 场景栈、UI、补间、粒子和版本化存档。
- Host 浏览器预览、固定输入回放与自动化测试。
- Raylib 风格兼容接口,以及独立的 `raylib_lite_*` API。

1. 新建游戏:按[快速入门](docs/quickstart.CN.md)看到第一个 Host 画面,再按[游戏开发指南](docs/game-development.CN.md)组织共享源码。
2. 选择路径:查看[示例支持矩阵(English)](examples/README.md)和[构建路径](docs/build-matrix.CN.md)。引擎说明 Host、通用原生固件与 ELF 接入;Iris/Gateway 的产品流程由 `esp-mosaico-vibe` 维护。
3. 设计输入、反馈、资产或绘制:查看[可复用设计方法](docs/reference-designs.CN.md)及其中链接的公共接口。
## 安装

ESP-IDF 工程通过消费组件的 `idf_component.yml` 依赖发布版 Raylib Lite Engine:
组件发布后,在应用的 `main/idf_component.yml` 中添加:

```yaml
dependencies:
idf: ">=6.2"
espressif2022/raylib-lite-engine: "^0.1.0"
```

仓库内示例保持同一个版本契约,只额外使用 `override_path: ../../..` 指向当前 checkout 做联调。外部 Game 不需要 include Engine 仓库中的 CMake helper,也不应通过 `EXTRA_COMPONENT_DIRS` 注入 Engine 根目录;组件位置由 IDF Component Manager 解析。
从[最小例程(English)](release/minimal/README.md)开始接入自己的应用,接口说明见[API 契约(English)](API.md)。

在仓库根目录运行已有示例的 Host 仿真:
## 运行示例

在仓库根目录运行 Host 预览:

```sh
python3 -m pip install Pillow
python3 -m pip install Pillow numpy
python3 tools/game_cli.py sim examples/sky_hop
```

浏览器预览地址为 `http://127.0.0.1:8460/`。原生示例的 `main/idf_component.yml` 保持 Board-neutral,只依赖 Engine;具体 Board 由示例工程的 Application CMake 层选择。`RAYLIB_LITE_BOARD` 默认是 `esp-mosaico`,也可用 `-D RAYLIB_LITE_BOARD=<board>` 选择 `examples/boards/<board>` 下的其它 Adapter。ESP-Mosaico 的 BSP 与 ESP-Iris 路径继续由其 Board component 的本地依赖配置解析。ESP-Mosaico normal Game 默认提供 Iris USB 管理、截图和远程 pointer,但固件更新采用 Recovery-first:保留的 factory Recovery 负责 USB OTA writer,并把 normal Game 安装到 `ota_0`。Recovery/Gateway 实现仍由 `esp-mosaico-utils` 维护;设备 ELF 游戏由外部 SDK 构建、打包和安装。
浏览器打开 `http://127.0.0.1:8460/`。新建游戏及回放测试见[快速入门](docs/quickstart.CN.md)和[游戏开发指南](docs/game-development.CN.md)。

仓库提供七个参考游戏和一个渲染基准工程,见[示例列表(English)](examples/README.md)。ESP-Mosaico 原生游戏使用共享 Board 适配层,自动获取板级依赖;构建和安装步骤见[构建指南](docs/build-matrix.CN.md)。

## 仓库目录
## 文档

- `src/`:引擎内部模块与 IDF backend;`include/raylib_lite/` 保存公共头文件。
- `tools/`:开发与构建辅助工具;其中 `tools/cmake/` 放置 native asset embedding 等 CMake helper。
- `examples/boards/`:具体开发板的示例/应用侧 Adapter;`esp-mosaico/` 是参考实现。
- `examples/`:参考游戏、专用渲染测试、共享原生示例代码和 Board Adapter。
- `host/`:Host ABI、RGB565 浏览器预览与固定输入回放。
- `tools/`:游戏 CLI、资源打包与性能分析工具。
- `docs/`:中英文开发、构建和可复用设计指南。
- [开发文档索引](docs/README.CN.md):资源、输入、音频、绘制和板卡移植。
- [组件发布(English)](docs/releasing.md):组装可独立使用的例程并发布组件。
- [更新记录](CHANGELOG.md)。
- [贡献指南](CONTRIBUTING.CN.md)。

## 版本与许可
## 许可

初期 `0.x` 版本使用 neutral `raylib_lite_*` Engine API;Host ABI 与二进制资源格式分别带版本号,并拒绝不兼容输入。源码除另有标注外采用 Apache-2.0 许可,见 [LICENSE](LICENSE);外部依赖见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。参与开发见[贡献指南](CONTRIBUTING.CN.md)。
源码采用 [Apache-2.0](LICENSE) 许可;外部依赖见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md),例程素材来源见[素材记录](release/asset_provenance.json)。
Loading
Loading