Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Important

DO NOT FLASH THIS ON A LOCKED XTEINK VIA THE UNLOCKER YOU WILL LIKELY BRICK YOUR DEVICE! this is only for unlocked xteink’s only

CrossLua Reader

A Lua-powered firmware runtime for the Xteink X4 e-paper reader.

A TeamIDE project.

Join the community on Discord · Follow on X · Subreddit: r/TeamIDELabs · YouTube: @TeamIDElabs.

CrossLua Reader is a C runtime that turns the Xteink X4 into an extensible e-reader platform. The firmware provides hardware drivers, a font renderer, and a Lua 5.4 interpreter. Everything else — readers, menus, network features — runs as Lua plugins loaded from the SD card.

Built on the hardware knowledge from CrossPoint Reader, rewritten from the ground up in pure C.

Why

CrossPoint Reader is an excellent e-reader firmware, but it's a monolithic C++ application. Every feature is compiled into the firmware. Adding new functionality requires C++ embedded development, a PlatformIO toolchain, and a firmware flash.

CrossLua Reader takes a different approach: the firmware is a compact ~640KB runtime, and all application logic lives as Lua scripts on the SD card. No recompilation, no reflashing — just drop a .lua file on the SD card:

  • Want to browse Project Gutenberg? Drop gutenberg.lua on the SD card.

  • Want to read JSON files? Drop json_viewer.lua on the SD card.

  • Want an RSS feed reader? Drop rss_reader.lua on the SD card.

  • Want a dictionary lookup? Drop dictionary.lua on the SD card.

  • Want a note-taking tool? Drop notes.lua on the SD card.

  • Want a daily quote reader? Drop daily_quotes.lua on the SD card.

  • Want a Bible reader with chapter navigation? Drop bible.lua on the SD card.

  • Want a Pomodoro timer for reading sessions? Drop pomodoro.lua on the SD card.

The goal is to let people customize and extend the firmware without ever touching a C++ compiler. If you build a plugin you think others would enjoy, send a PR — I'll audit it and ship it in the community plugins directory.

Architecture

SD Card Flash (~640KB)
├── plugins/ ├── C HAL drivers
│ ├── epub_reader.lua ├── Font loader + renderer
│ ├── txt_reader.lua ├── Framebuffer renderer
│ ├── md_reader.lua ├── Lua 5.4 interpreter
│ ├── file_browser.lua ├── C → Lua API bindings
│ ├── settings.lua └── Plugin manager
│ ├── sefaria.lua
│ └── ...
├── fonts/
│ ├── NotoSans-14-Regular.cfont
│ └── ...
└── books/

Features

  • Plugin system — extend the device by dropping .lua files on the SD card

  • C runtime — minimal flash footprint, maximum headroom (C++ only in SDK bridge layer)

  • SD-loadable fonts — add fonts without reflashing (.cfont format)

  • Hebrew/RTL support — bidirectional text rendering built into the core

  • Full Lua 5.4 — tables, closures, coroutines, string manipulation

  • Native API — display, input, storage, WiFi, fonts, ZIP, XML, JSON exposed to Lua

Hardware

  • MCU: ESP32-C3 (single-core RISC-V @ 160MHz)

  • RAM: ~380KB (no PSRAM)

  • Flash: 16MB

  • Display: 800x480 e-ink

  • Storage: SD card

  • Device: Xteink X4

Status

Early development. See build_plan.md for the phased roadmap.

Contributing

CrossLua Reader is designed so contributing is as simple as writing a Lua script.

  • Try an idea — write a .lua file, drop it on your SD card, reload. No toolchain, no flash.

  • Share it — open a PR with your plugin and a short description.

  • Get it shipped — accepted plugins land in the community/ directory of the next release.

Plugins must be MIT-licensed, free of network calls to non-public APIs, and pass a basic code audit (no os.execute shenanigans, no busy loops that wreck the battery).

Using AI to contribute is welcome — please mention AI use in your PR description. I've intentionally left my Claude Code setup (.claude/, .skills/, CLAUDE.md) in the repo so contributors using Claude Code (or any tool that reads CLAUDE.md) start with my conventions, style preferences, and project gotchas already loaded. That's especially aimed at folks who want to contribute but aren't deeply technical — open the repo in Claude Code, describe what you want to build, and the assistant should know enough to make something close to what I'd accept. Full AI policy and contribution details in CONTRIBUTING.md.

Translations

CrossLua Reader can be translated into any language by dropping a single JSON file on the SD card. No code, no toolchain — if you can edit a text file, you can ship a language pack.

Each pack lives at sdcard/languages/{code}/lang.json (where {code} is the ISO 639-1 code: es, fr, ja, ar, etc.) and follows the same schema as sdcard/languages/en/lang.json:

{
"code": "es",
"name": "Español",
"direction": "ltr",
"fontFamily": null,
"strings": {
"home": "Inicio",
"settings": "Configuración"
}
}

A few notes for translators:

  • name should be the language's name in its own script (Español, 日本語, العربية) — that's what shows up in the language picker.

  • direction is "ltr" or "rtl". The runtime handles bidirectional text rendering automatically.

  • fontFamily is null if your language uses Latin or Cyrillic glyphs already shipped with the firmware. For scripts that aren't covered (Hebrew, Arabic, CJK, Greek, etc.), bundle a .cfont file inside languages/{code}/fonts/ and set fontFamily to its family name. The .cfont format is documented in docs/cfont-format.md and there's a converter in tools/.

  • Partial translations are welcome. Any keys you skip fall back to English at runtime, so you can ship what you have and the community can fill in the rest.

To contribute a language pack, open a PR adding your languages/{code}/ folder. Translation PRs land fast — there's no code to audit, just a quick sanity check on UTF-8 encoding and that the strings render in the app.

Support the project

I've been writing code since high school — starting with LAMP-stack stuff back when that was the move. Built a little browser-based OS, a custom CMS, a static site generator. But coding has always been a side thing, never my career: I spent two decades in the electronics recycling industry, where I built my own inventory system to keep the doors open. So I'm a developer in practice, more hobbyist than professional, and I've been at it long enough to know what I'm doing.

CrossLua Reader is one of several projects I'm building under TeamIDE. I'm not great at self-promotion or monetization, so if this is useful to you, send me some love at teamide.dev/support. Every bit helps me keep TeamIDE's projects going.

License

MIT

About

Lua-powered e-reader runtime for the Xteink X4. C runtime + Lua plugin architecture.

Resources

Contributing

Stars

36 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages