Skip to content

feat(website): interactive Lua showcase site#239

Merged
davydog187 merged 20 commits into
mainfrom
website-lua-showcase
May 26, 2026
Merged

feat(website): interactive Lua showcase site#239
davydog187 merged 20 commits into
mainfrom
website-lua-showcase

Conversation

@davydog187
Copy link
Copy Markdown
Contributor

Summary

Adds a Phoenix LiveView site under website/ that shows off this VM the way godbolt shows off compilers — write Lua, run it on the BEAM, see the register-based bytecode it executes.

  • / — landing page (hero, feature grid, compiler-explorer teaser, embed example, CTA)
  • /playground[/:example] — Lua editor with print capture, return values, and a per-prototype bytecode panel with register-aware formatting. Eight preloaded snippets including a recursive fib, the BEAM creators in a table, closures, metatables, compile errors, and runtime errors.
  • /tour[/:slug] — eight bite-sized lessons (values, control flow, tables, functions, closures, metatables, patterns, errors) with editable per-lesson runnables and an optional bytecode toggle.

Snippets run in Website.LuaSandbox — a Task.async wrapper around Lua.eval!/2 with a 1.5s timeout, the library's default sandboxing, and ANSI stripped from error messages. multi(n) counts and the rest of the instruction set get per-opcode disassembly so registers display as rN and counts/literals stay bare.

The website depends on the parent Lua library via {:lua, path: ".."}, so it always exercises the in-repo VM.

Test plan

  • cd website && mix test (currently 5 passing)
  • cd website && mix format --check-formatted
  • cd website && mix phx.server and visit:
    • / renders hero + feature grid + compiler-explorer promo
    • /playground runs each of the 8 examples (Hello, fib, tables, closures, patterns, metatables, compile error, runtime error)
    • Bytecode panel renders for fib with both main chunk and function #1 prototypes selectable
    • /tour cycles through all 8 lessons and runs each
    • Cmd+Enter in the editor submits the form; Tab/Shift+Tab indents

davydog187 added 20 commits May 24, 2026 09:04
Adds a Phoenix LiveView site under `website/` that demos this VM:

* Landing page — hero, feature grid, compiler-explorer teaser, embed
  example, CTA
* `/playground[/:example]` — Lua editor with `print` capture, return
  values, and a Godbolt-style register-aware bytecode panel that
  walks every prototype (closures included). Eight preloaded
  snippets: hello, fib, BEAM creators table, closures, patterns,
  metatables, compile error, runtime error.
* `/tour[/:slug]` — eight bite-sized lessons (values, control flow,
  tables, functions, closures, metatables, patterns, errors) with
  per-lesson editable runnables and optional bytecode toggle.

Snippets run in `Website.LuaSandbox`: a `Task.async` wrapper around
`Lua.eval!/2` with a 1.5s timeout, default sandboxing, and ANSI
stripped from error messages. `multi(n)` counts and the rest of the
instruction set get per-opcode disassembly so registers display as
`rN` and counts/literals stay bare.

Depends on the parent Lua library via `{:lua, path: ".."}`.
Adds a Makeup-backed `<.code_block>` component used across the home,
playground, and tour pages, plus a CodeRotator JS hook that cycles
through labelled snippets. Snippets live in their own module so they
can be unit-tested and edited without heredoc-in-heredoc pain.

Also fixes two display issues in the home hero:
- Moves the "~LUA sigil" floating chip from `-bottom-4 -left-4`
  (which covered the rotator dots) to `top-full mt-3` so it sits
  cleanly below the code panel.
- Reflows the queue.exs and formulas.exs embed snippets so they fit
  the panel without horizontal clipping.
Iterates over every Lua snippet rendered on the marketing home, the
playground, and the tour, asserting each one either runs cleanly or
fails in the expected way. The two intentional-error playground demos
are tagged with `expect:` so the test asserts the correct error kind
(compile vs. runtime).

Adds Website.LuaSandbox.home_snippets/0 as a single source of truth
for the hero compiler-explorer snippet; the matching page_controller
refactor lands separately.
Add a `website` job that runs `mix deps.get`, `mix test`, and
`mix format --check-formatted` from inside `website/`. The website
depends on lua via a path dependency, so its tests exercise the local
build on every PR.
Restructures /tour from 16 mostly-runnable lessons into 27 lessons across
five chapters: Language basics, Idioms & deeper language, The standard
library, Lua.ex integration, and Under the hood. Each lesson now meets
a rubric (title ≤ 32 chars, body ≤ 90 words, source ≤ 18 lines / 12 for
integration) enforced in lua_examples_test.exs.

- adds missing PIL fundamentals: locals/scope, truthiness gotchas,
  pairs vs ipairs + custom iterators, integer/float subtypes,
  metatable inheritance, operator overloading, xpcall, coroutines
  (preview / read-only — not yet implemented in Lua.ex).
- adds a Chapter IV (Lua.ex integration) with dual-pane lessons:
  embedding, set!/get!, deflua, call_function!, put_private, the
  ~LUA sigil, and error-rescue across the boundary. Each lesson
  shows the host Elixir alongside a runnable Lua snippet.
- groups the sidebar by chapter with continuous global numbering;
  adds a chapter eyebrow, a "Host integration" badge for Chapter IV,
  a "See also" pill row, markdown links in body text, a read-only
  banner for non-runnable lessons, and a prose-only closing page.
- extends lua_examples_test.exs with rubric checks plus an API-drift
  test that asserts every Lua.ex symbol named in Chapter IV
  (Lua.new, eval!, set!, get!, call_function!, load_api, put_private,
  get_private!, sigil_LUA, deflua) still exists.
- fixes a pre-existing disassembler bug: format_op_args(:set_list, …)
  was string-interpolating {:multi, n} count values directly and
  crashing on table-constructor + multi-return snippets. Now routes
  through the existing count/1 helper.
Lift the TV Labs wordmark slightly and bump to h-6 so it sits flush
with the "BUILT AT" label, and tighten hero bottom padding so the
section doesn't leave a visual gap below the new attribution row.
Render the tour sidebar and footer columns as two siblings — a real
<details> for mobile, a plain <div> for desktop — and show one or the
other with Tailwind's responsive `hidden`/`lg:block` (or `sm:block`).

Replaces the layered approach that tried to make a single <details>
"act open" on desktop (responsive Tailwind selectors on the details,
data-open-above JS sync on resize/page-loading-stop, LiveSocket
onBeforeElUpdated to preserve the JS-applied `open` across morphs).
Each fix surfaced another edge case because <details> ties content
visibility to the `open` attribute via the browser-internal
::details-content slot; CSS on the children can't override it.

The desktop footer column also gains a semantic <h3> heading in place
of a styled-summary, a small a11y win.
One eased orbit on page load and a continuous orbit + drop-shadow glow
while the nav or footer mark is hovered, replacing the old rotate-12
tilt. Scoped to a new `.lua-mark-satellite` class so the homepage's
background `lua_orbit` keeps its slow infinite spin untouched.
`LuaSandbox.run/2` was wrapping each evaluation in `Task.async` +
`Task.yield`/`Task.shutdown` to enforce a 1.5s timeout. That put
process lifecycle in the sandbox layer where the LiveView already owns
the socket-bound process tree.

This collapses `run/2` to a synchronous `run/1` and pulls the process
machinery up to the LiveViews: `start_async(:lua_run, ...)` spawns the
work, a `Process.send_after(:lua_timeout, 1500)` arms a cancellation
timer, and `handle_async/3` produces either the result or a timeout
record (on `{:exit, _}` from `cancel_async`). The tour also cancels
in-flight runs on lesson change so stale results never bleed across
lessons.

Drive-bys: drop unused `Lua.Compiler.Instruction` alias + its
warning-silencer shim, tighten the ANSI strip regex to the full CSI
final-byte range (`\x40-\x7E`), and add `is_binary` guard on
`select-block`'s `String.to_integer`.
@davydog187 davydog187 merged commit 6fbf49b into main May 26, 2026
5 checks passed
@davydog187 davydog187 deleted the website-lua-showcase branch May 26, 2026 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant