Ember is a reusable Go-native Luau-compatible scripting runtime.
The long-term goal is not to mechanically translate Luau's C++ source into Go. The goal is to grow a small, testable Go implementation piece by piece, using upstream Luau as the behavioral reference. Hearth is the first production host that proves the embedding interface, not the domain model of the runtime.
Ember currently has a tiny root-package vertical slice:
- a value model for nil, booleans, numbers, strings, host-visible tables, and opaque host userdata;
- internal bytecode for constants, globals, register moves, table fields and indexes, arithmetic, calls, and return;
- a minimal interpreter loop;
- a narrow
Compilepath for scalar local bindings, assignments to existing locals and chained table selectors, erased Luau type annotations, generic function type parameters,typeoftype queries, aliases, and casts, array, named-field, and computed-key table literals, chained dot-field and bracket reads,do/endlexical blocks,if/then/elseif/else/endcontrol flow with Luau truthiness,while/do/end,repeat/until, numericfor, and genericforloops over iterator expressions or direct table values with__iter,break, andcontinue, host-visible table mutation, host globals read and assigned as expression values, host callback calls through names or selector expressions as expressions or statements, method calls with receiver self-arguments, minimal local and anonymous closures with upvalues, table field and method function declarations, table metatables with table-valued and function-valued__indexand__newindex, function-valued__iterand__tostring, function-valued__call, arithmetic and concat metamethods including__unm, relational and equality metamethods, plus__metatableprotection, multiple return values and value-list adjustment for returns, local bindings, assignment, and final call arguments, variadic script functions with..., plus expressions joined by+,-,*,/,//,%,^,..,==,~=,<,<=,>,>=,and, oror,if/then/elseif/elseexpressions, unarynot, unary numeric-, unary length#, and parentheses for grouping; - a strict-mode
Checkfoothold that recognizes--!strictfile comments and retains an internal type tree with source ranges for the future typed-analysis path; - a tiny pure base-library foothold with
type,math,setmetatable,tonumber,tostring,getmetatable,next,pairs,ipairs,rawget,rawset, andrawlen, plusselect,unpack, andtable.pack/table.unpack,table.insert,table.remove,table.concat,table.find,table.clear, andtable.sort; - source-to-result tests such as
return 1 + 2, scalar literals, and local references; - exact prepared execution through static generated Go, plus same-process reload-time ARM64/x86-64 native preparation for a proved numeric subset on supported Darwin, Linux, and Windows hosts. Unsupported functions, values, and platforms replay through the canonical Machine before effects.
This is only a seed. Full Luau grammar, full function syntax, broader standard libraries, and analyzer behavior remain future slices.
import "github.com/besmpl/ember"The root package should remain small. Future packages should exist only after a slice proves that the split makes the public interface smaller or the implementation easier to test.
For embedding, compile a program and use Runtime.Invoke to call one module
export with explicit globals. Use InvokeResumable when host calls may wait;
use Dispatch only when the application intentionally wants ordered fan-out
across an entrypoint cohort. See the runnable ExampleRuntime_Invoke and
host embedding guide.
Ember should be:
- Go-native, with ordinary Go values, errors, tests, and package structure;
- Luau-compatible where compatibility is claimed;
- deterministic for hosts that need repeatable execution;
- embeddable without hidden global runtime ownership;
- explicit about host callbacks, clocks, I/O, randomness, and cancellation;
- built in vertical slices that run real scripts or conformance fixtures.
Start with the small durable documentation set:
- docs/README.md
- docs/principles.md
- docs/design.md
- docs/compatibility.md
- docs/public-surface.md
- docs/embedding.md
- docs/prepared.md
- docs/checks.md
The compatibility document is the maintained feature manifest: every claimed Luau slice points to at least one behavior test, and a package test checks that the referenced test names still exist.
Standing future-plan docs are intentionally not kept in the repository. When a slice needs coordination, write the smallest temporary plan that proves useful and retire or delete it when the slice lands or is abandoned.
scripts/check-fast
scripts/checkFor focused Go work, run package-local tests first, then use the scripts before calling a slice done.