feat(website): interactive Lua showcase site#239
Merged
Conversation
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`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 withprintcapture, return values, and a per-prototype bytecode panel with register-aware formatting. Eight preloaded snippets including a recursivefib, 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— aTask.asyncwrapper aroundLua.eval!/2with 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 asrNand 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-formattedcd website && mix phx.serverand visit:/renders hero + feature grid + compiler-explorer promo/playgroundruns each of the 8 examples (Hello, fib, tables, closures, patterns, metatables, compile error, runtime error)fibwith bothmain chunkandfunction #1prototypes selectable/tourcycles through all 8 lessons and runs each