diff --git a/deploy/site/sdk.html b/deploy/site/sdk.html
index 904569c6..8d468f0e 100644
--- a/deploy/site/sdk.html
+++ b/deploy/site/sdk.html
@@ -526,7 +526,7 @@ end
| wada.sys.millis() | Milliseconds since boot. |
| wada.sys.board() | {w, h, touch, keyboard, trackball, gps}: size and capabilities. |
| wada.sys.toast(msg) | Brief on-screen message. |
- | wada.sys.random(n) | Integer in 1..n. |
+ wada.sys.random(n) wada.sys.random(lo, hi) | Integer in 1..n, or in lo..hi (both ends included). From hardware randomness, so there is nothing to seed. |
| wada.sys.epoch() | Unix time in seconds, or nil when the clock has not been set yet (no GPS fix and no NTP). Always handle the nil. |
| wada.sys.datetime() | {year, month, day, hour, min, sec, wday} in local time. wday is 0 for Sunday. |
| wada.ui.emoji(cb) | Open the emoji picker and call cb(glyph) with the chosen emoji as a UTF-8 string, or cb(nil) if it was dismissed. For an app that draws its own text entry and keeps the buffer itself; if you use wada.ui.input() you do not need this, the picker is already on its long-press menu. |
diff --git a/src/ui-touch/LuaAppHost.cpp b/src/ui-touch/LuaAppHost.cpp
index fb078d93..dcdd68e7 100644
--- a/src/ui-touch/LuaAppHost.cpp
+++ b/src/ui-touch/LuaAppHost.cpp
@@ -1273,8 +1273,13 @@ int sysKeepAwake(lua_State* L) {
int sysToast(lua_State* L) { luaHostToast(luaL_checkstring(L, 1), (int)luaL_optinteger(L, 2, 1500)); return 0; }
int sysRandom(lua_State* L) {
// esp_random-backed: apps should not have to seed math.random for games
- lua_Integer lo = luaL_optinteger(L, 1, 0), hi = luaL_optinteger(L, 2, 0);
- if (hi <= lo) { lua_pushinteger(L, (lua_Integer)esp_random()); return 1; }
+ // random() = a raw 32-bit value, random(n) = 1..n (as documented), random(lo, hi) =
+ // lo..hi. An empty range used to return the raw value too, so random(1, 1) at the end
+ // of a shuffle gave a huge index, and random(n) never returned 1..n at all.
+ if (lua_isnoneornil(L, 1)) { lua_pushinteger(L, (lua_Integer)esp_random()); return 1; }
+ lua_Integer lo = luaL_checkinteger(L, 1), hi;
+ if (lua_isnoneornil(L, 2)) { hi = lo; lo = 1; } else hi = luaL_checkinteger(L, 2);
+ if (hi < lo) { const lua_Integer t = lo; lo = hi; hi = t; }
lua_pushinteger(L, lo + (lua_Integer)(esp_random() % (uint32_t)(hi - lo + 1)));
return 1;
}