Files
tactility_apps/Apps/LuaGame
Adolfo 88870d7ac5 feat(LuaGame): Pico API compatibility layer + 17 games ported
- Added renderer, game, INPUT tables mapping Pico monochrome API to RGB565 framebuffer
  - renderer.clear, pixel, line, rect, circle, triangle (filled via scanline), text, text_scaled (8x8 font scaled)
  - game.width/height, vars, set_frame_updates, exit
  - INPUT constants NONE, TOUCH_DOWN/MOVE/UP, BUTTON_0/1, FRAME_TICK, GESTURE
- Event generation: touch down/move/up detection + FRAME_TICK each frame
- is_pico detection via source content (renderer./INPUT.) and game.vars heuristic
- Unified game loop handling both sys API (update(dt)) and Pico API (update(event))
- Generated pico_games.h with all 17 examples from pico-bare-metal:
  2048, air_hockey, asteroids, ball, breakout, counter, flappy_bird, lunar_lander,
  memory_match, pacman, pong, simon_says, snake, solitaire, tetris, tic_tac_toe
- Tested: Pong runs at 17 FPS, 'Pong initialized' log, no Lua errors
- Fixes: renamed breakout_lua_src to embedded_breakout_lua_src to avoid conflict with pico breakout
- Ready for game selector UI (menu wrapper) - currently embedded breakout fast v2 remains default, pico test flag use_pico_test available for dev
2026-07-31 12:56:53 -04:00
..

LuaGame - Lua Interpreter Game Engine

External ELF app that runs Lua games on Tactility OS (ES3C35P 320x480 tested on 192.168.68.107).

How it works

  • Embeds Lua 5.4.7 source (no external dependency, avoids missing symbol issues)
  • Lua init runs in dedicated 16K stack FreeRTOS task to avoid GUI task (4096 bytes) stack overflow
  • Game framebuffer: 240x240 RGB565 in PSRAM, rendered via LVGL canvas
  • Sys API (as used in breakout.lua):
    • sys.log(msg)
    • sys.clear(hexColor)
    • sys.print(x,y,text,hexColor) - uses LVGL labels overlay
    • sys.rect(x,y,w,h,hexColor,filled)
    • sys.circle(x,y,r,hexColor,filled)
    • sys.line(x0,y0,x1,y1,hexColor)
    • sys.touch() -> pressed, tx, ty (touch coords mapped to 240 game space)
    • sys.tone, sys.sfx stubs (logs)
  • Embedded breakout.lua as fallback, but tries to load from SD in order:
    • /sdcard/lua/breakout.lua
    • /sdcard/lua/game.lua
    • /data/lua/breakout.lua
    • /sdcard/breakout.lua
  • File loading uses PSRAM buffer + luaL_loadbuffer to avoid luaL_loadfile stack issues.

Symbol fixes

Previous attempts hit missing symbols: clearerr, clock, getenv, gmtime, setlocale, setvbuf, tmpfile, tmpnam, ungetc, plus LVGL lv_canvas_get_draw_buf, lv_draw_buf_invalidate_cache, lv_image_cache_drop. Fixed by:

  • Providing local stubs for missing libc functions
  • Removing use of unexported LVGL cache APIs, using only lv_canvas_create, lv_canvas_set_buffer, lv_obj_invalidate
  • Verifying with verify_symbols.py - 0 missing.

Build / Install

cd /Users/adolforeyna/Projects/Tactility/apps
unset PYTHONPATH; unset PYTHONHOME
export IDF_PYTHON_ENV_PATH=/Users/adolforeyna/.espressif/python_env/idf5.3_py3.9_env
source /Users/adolforeyna/esp/esp-idf/export.sh
export TACTILITY_SDK_PATH=/Users/adolforeyna/Projects/Tactility/firmware/release/TactilitySDK
export ESP_IDF_VERSION=5.5
python tactility.py Apps/LuaGame build esp32s3 --local-sdk
curl -X PUT http://192.168.68.107/api/apps/install -F "file=@Apps/LuaGame/build/LuaGame.app"
curl -X POST "http://192.168.68.107/api/apps/run?id=one.tactility.luagame"

Testing

  • Serial logs: /dev/cu.usbmodem1101 115200
  • Screenshot: curl -s http://192.168.68.107/api/screenshot -o /tmp/fb.png
  • Current status: boots, loads /sdcard/lua/breakout.lua (5207 bytes), no stack overflow, renders bricks/ball/paddle, handles float coords for circle.

TODO

  • Implement proper game selection UI for /sdcard/lua/ directory
  • Map touch to paddle correctly (currently uses canvas coords)
  • Implement audio via SfxEngine
  • Scale canvas to full display or allow dynamic resolution via sys.width/height
  • Add file browser in-app