Skip to content
AsHyAmS
Network state observed every site read A snapshot, not live telemetry.

Library morrowind active current

l3i

The Luau runtime for DreamWeave: a Rust binder that owns its Luau 0.744 build, plans every VM before it exists, and lowers hot script calls to native code.

Indexed from l3i. Project metadata is published by the project's own site; AsHyAmS indexes that claim.

stable · current
2.2.0 2026-10-23
License
MIT OR Apache-2.0
Versioning
numeric

01Dependencies

From the current release, stable 2.2.0.

Requires

  • dream-net=1.1.0 satisfied by stable 1.1.0Runtime infrastructure: the @dream/udp module is in every plan, and l3i owns the bridge.

Recommends

  • dream-soft-render=1.0.0 satisfied by stable 1.0.0The @dream/soft-render module, when the soft-render feature is on.

02Used by

Current releases of indexed projects that point here, by id or through a capability.

Nothing indexed points here.

l3i and its direct relationshipsDependents above, dependencies below. The tables on this page list the same relationships.l3i recommends dream-soft-renderl3i requires dream-netl3i · 2.2.0l3i2.2.0dream-net · librarydream-netlibrarydream-soft-render · librarydream-soft-renderlibrary
Direct relationships. Dependents above, dependencies below; the lists above are the same facts.

03Compatibility

As the publisher declares it for the current release. This index claims nothing further.

Platforms
not restricted

04Releases

14 releases, newest first. Yanked and deprecated releases stay listed.

  1. 2.2.0 stablecurrentmigration notes 2026-10-23

    `@dream/process` says which OS it runs on and where the user's home and Documents folders are, so a script can find an application's files the way the application does.

    Publisher's notes

    Added

    • process.platform(): the OS the host was built for, as Rust names it (windows, macos, linux, ...). A call rather than a constant, so compiled code never carries another platform's answer. No capability.
    • process.knownFolder('home'): HOME, or on Windows USERPROFILE, then HOMEDRIVE with HOMEPATH, then HOME. process.knownFolder('documents'): the Windows Documents known folder from SHGetKnownFolderPath, wherever the user or OneDrive moved it, and nil elsewhere. Both need process.environment, as env does.

    Migration

    Nothing to change. Take 2.2.0 in place of 2.1.3. No dependency was added: the one Windows call is declared by l3i itself.

    2 relationships source 66e15c2184ea · tag 2.2.0

    l3i-2.2.0.crate 2.3 MiB · Rust crate
    Verify · sha256 3dbae044498b…45910b33 · 1 source
    SHA-256
    3dbae044498ba00495399af9886d8d7b0474537fb5ac96a33bc67e9b45910b33
    Size
    2421355 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.2.0.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.2.0.crate must print the digest above.

  2. 2.1.3 stablemigration notes 2026-10-21

    Security release: every dependency updated, closing seven RustSec advisories in the TLS stack and the Zstandard decoder, one of them high severity.

    Publisher's notes

    Changed

    • ruzstd 0.9.1: RUSTSEC-2026-0344, a decompression bomb where a tiny input could exhaust memory (high). The JPK reader's zstd entries and bytes.zstd decode through it.
    • rustls 0.23.46: RUSTSEC-2026-0346 (session Debug impls exposed TLS secrets, medium), RUSTSEC-2026-0347, RUSTSEC-2026-0348, and RUSTSEC-2026-0349 (buffered data after ECH rejection, a 1 GiB certificate decompression before authentication, and a downgrade to classical key exchange from an unauthenticated ServerHello, all low).
    • rustls-webpki 0.103.16 and webpki-root-certs 1.0.10: RUSTSEC-2026-0382 and RUSTSEC-2026-0383, certificate verification and the bundled roots accepting distrusted intermediates.
    • The manifest's floors for rustls and ruzstd now start at the fixed versions, so a fresh resolution of a dependent can't pick the vulnerable ones. Every other dependency in the lock moved to its current compatible release. No API changed.

    Migration

    Nothing to change. Take 2.1.3 in place of 2.1.2; cargo update -p l3i in a dependent does it, and cargo audit there should come back clean of these seven.

    2 relationships source ddb82c859fba · tag 2.1.3

    l3i-2.1.3.crate 2.3 MiB · Rust crate
    Verify · sha256 015d366501f8…c887a7cb · 1 source
    SHA-256
    015d366501f86898bd49684c4bc74302d775066d9e80a0deb68816bec887a7cb
    Size
    2419507 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.1.3.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.1.3.crate must print the digest above.

  3. 2.1.2 stablemigration notes 2026-10-15

    2.1.1's fixes, released through the pipeline: 2.1.1 went to crates.io by hand, without its GitHub release or documentation.

    Publisher's notes

    Changed

    • Two push closures end with a semicolon, as the pedantic lints ask. Nothing else differs from 2.1.1.

    Migration

    Nothing to change. Take 2.1.2 in place of 2.1.1; they are the same code.

    2 relationships source 3bdcd7f87494 · tag 2.1.2

    l3i-2.1.2.crate 2.3 MiB · Rust crate
    Verify · sha256 197c73848c84…726b2b7d · 1 source
    SHA-256
    197c73848c84525b51058592349450423934aaabc5998b1854a17df2726b2b7d
    Size
    2419486 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.1.2.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.1.2.crate must print the digest above.

  4. 2.1.1 stablemigration notes 2026-10-15

    Fixes to 2.1.0's limits: no push or host-level allocation aborts the process, a wait the time limit cuts short fails the call it ends, process.run stops at the limit whatever holds its pipes, and a child finds programs on the host's PATH again.

    Publisher's notes

    Fixed

    • A child started without process.environment gets the host's PATH along with what env names, so process.run('git') finds a program where the host would, and so does whatever that program starts. 2.1.0 cleared PATH with the rest, and a bare name fell back to libc's default path. clearEnv = true still clears it.
    • bytes.shortest(value, 'f32') answers nil for a double past single precision's range, which narrows to an infinity. It formatted that infinity as inf, found no exponent, and aborted the process from inside the native call.
    • Every scalar, vector, light userdata and pinned-value push makes room on the stack first, and pinning a value, making a table, a closure or a userdata, and looking up a global run under protection at host level. A host that filled the stack, or ran out of memory under the cap while doing any of those outside a Lua call, aborted with Rust cannot catch foreign exceptions; it gets Err.
    • A @dream/tcp poller's or @dream/dns request's wait cut short by the execution time limit marks the call expired, as process.sleep and process.run do, so a script that ends with the wait fails with the limit instead of returning Ok.
    • process.run ends at the execution time limit even while a process the child started holds a captured pipe open, abandoning the capture instead of waiting for its reader, and kills and reaps a child whose wait fails.

    Migration

    Nothing to change. A host that wanted a child to have no PATH passes clearEnv = true. Value::clone, Value::type_of and Value::eq answer as for an invalid value (an invalid clone, Type::None, false) when the main thread has no stack slot left, where they could abort before.

    2 relationships source 3f93eba47e74 · tag 2.1.1

    l3i-2.1.1.crate 2.3 MiB · Rust crate
    Verify · sha256 858748417438…f038a1ea · 1 source
    SHA-256
    8587484174381768eb24e756c1a64abd41e13c9ed284558297ceb98cf038a1ea
    Size
    2419471 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.1.1.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.1.1.crate must print the digest above.

  5. 2.1.0 stablebreaking notesmigration notes 2026-10-15

    Limits that hold: an uncatchable watchdog on every host call, a memory cap the allocator enforces, protected host-level pushes, deeply frozen sandboxes, and process capabilities that mean what they say; plus process.sleep, @dream/fs path functions and atomic writes, the rest of a regex API, trimming, shortest float digits, and Runtime::shutdown for hosts that exit without dropping the runtime.

    Publisher's notes

    Breaking changes

    • Stack and Frame pushes, open_standard_libraries, sandbox_globals and sandbox_luau return Result: a push checks the stack has room, and host-level pushes and setup that allocate run under protection, so a stack overflow or an out of memory at host level is Err instead of an abort.
    • process.write needs the process.stdio capability. process.run starts a child with only the variables env names unless process.environment is granted, and kills a child still running when the execution time limit runs out.
    • data.count is data.countWhere and data.compare is data.select, so neither shares a name with bytes.count or bytes.compare.
    • bytes.translate(text, rules) takes the rules table intern.new takes (nocase, replace, collapse, trimStart, trimEnd), or a bytes.rules compiled from one, in place of its own from, to and options.
    • The TLS stream's shutdownWrite() is shutdown('write'), as a TCP stream half-closes.
    • raster's module rgba8 and rgb8 clamp and round as the receiver's always did, instead of raising on a channel out of range.

    Added

    • process.sleep(seconds), never past the runtime's execution time limit.
    • @dream/fs join, parent, fileName, extension and isFileName, which touch no disk and need no capability; isFile and isDir; writeFile's exclusive, atomic and createParents.
    • bytes.regex match, captures, a matches iterator, replace and replaceAll by template or function, split, tostring, and bytes.regexEscape.
    • bytes.trim, trimStart and trimEnd: Unicode whitespace on UTF-8, ASCII otherwise, or a given byte set.
    • bytes.shortest(value, width?), the fewest decimal digits that read back as a value at f64 or f32 width, and bytes.toF32.
    • Runtime::shutdown(), which flushes and closes every live @dream/fs writer without freeing the heap, for a host that leaves the heap to the process's exit.
    • runtime::watchdog_remaining(scope) and runtime::expire_if_due(scope), so a host's own blocking native clamps its wait to the watchdog.
    • Error::ExecutionTimeLimit and Error::MemoryLimit (Error::is_limit()), CallContext::HOST, Scope::is_host_level, flags::luau_assertions().
    • One capability denial, Error::denied and ModuleInstaller::gated, and one stack::push_list, for extensions.
    • raster's module gains the channel getters its receiver has; every math() receiver method and its module function are expanded from one list, and a test holds them to each other.

    Changed

    • Every host call into Luau runs under the runtime's limits: an implicit host-interface scope arms the watchdog and the memory cap unless the host opens an Initialization scope itself.
    • Release builds define NDEBUG, so they no longer carry Luau's assertions and traps.
    • udp's capability denials read like every other module's.

    Fixed

    • A timeout is sticky: once a call's execution time limit runs out, every safepoint raises until the scope that armed it ends, so pcall, xpcall and coroutines can't catch it and carry on.
    • The memory limit is the allocator's: a growth past it fails at the allocation, so one buffer.create can't take a gigabyte between watchdog polls.
    • Thread::reset refuses a thread that is running or resuming another, instead of tripping Luau's assertion and freeing the stack it runs on.
    • readFile, readFileString and open refuse a FIFO, a socket or a device instead of blocking on it or reading without end.
    • Every table and metatable a sandbox's library views and common packages reach is frozen, so one instance can't write through a nested table or a shared metatable to another.

    Migration

    Handle the Result every push and setup call now returns (? in a function returning l3i::Result). Grant process.stdio to a runtime whose scripts write to the terminal through process.write, and process.environment to one whose children need the parent's environment, or pass env. Rename data.count and data.compare calls, rewrite bytes.translate(text, from, to, options) as bytes.translate(text, bytes.rules { replace = { ... }, collapse = ..., ... }) (compile the rules once outside a loop), and shutdownWrite() as shutdown('write'). A script that caught a timeout with pcall to carry on now stops; that was the bug.

    bytes.shortest gives Rust's digits, which can differ from Ryū's (serde_json's) in the last digit where two shortest spellings both read back as the value.

    2 relationships source e7f92781ad28 · tag 2.1.0

    l3i-2.1.0.crate 2.3 MiB · Rust crate
    Verify · sha256 8cca3d3535f2…8af60ec4 · 1 source
    SHA-256
    8cca3d3535f26fb266995be7de041be19e50ef75b08169f73313e7ad8af60ec4
    Size
    2416845 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.1.0.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.1.0.crate must print the digest above.

  6. 2.0.3 stablemigration notes 2026-10-14

    Analysis checks a buffer slice generator as a buffer with the default options, and in the modules a checked module requires.

    Publisher's notes

    Fixed

    • A slice generator over a buffer ([for byte in data[1:4] => byte], any[for byte in data[1:n] => byte ~= 0]) is lowered for analysis as a table slice until Luau has inferred its source, then as a buffer. That second step read the types Luau inferred, which a module keeps only with its full type graph, so with retain_full_type_graphs off, the default, every buffer slice generator was checked as a table: Expected type table, got 'buffer' instead and two operator errors at each one. It also ran for the module named in the check only, so a required module's buffer slices were checked as tables whatever the options. A check now keeps each module's type graph, and specializes every module it reaches.

    Migration

    Nothing to change. A strict package that reported the three errors above at its buffer slice generators reports none.

    Known, and not l3i's to fix: under Luau's new solver, a function literal inside an if condition has its returns checked against the declared return type of the function holding the if. A reducer is lowered for analysis to such a literal, so if any[for value in values => value > 2] then inside a function declared to return, say, buffer? reports Expected this to be 'buffer?', but got 'boolean' twice. The code is correct and runs as written. To check clean, bind the reducer to a local before the if: local found = any[...], then if found then.

    2 relationships source 8c0144d1ca06 · tag 2.0.3

    l3i-2.0.3.crate 2.3 MiB · Rust crate
    Verify · sha256 e599f383ca7b…877bc8e2 · 1 source
    SHA-256
    e599f383ca7b3ee378d5ddee3d0b151b5a17a029de9b0b032fad7e5b877bc8e2
    Size
    2395447 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.0.3.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.0.3.crate must print the digest above.

  7. 2.0.2 stablemigration notes 2026-10-12

    A natively lowered `@dream/intern` lookup no longer reads a slot table the pool has freed, and the `@dream/data` definitions say what a span's `kind` is.

    Publisher's notes

    Fixed

    • Interning a key a pool already held, through the binder, while the pool sat at its load limit (12, 24, 48 ... identities) grew the slot table before looking the key up, and did not tell native code the table had moved, because the pool's length had not changed. Until the next new key, a lowered pool:find or pool:intern on an annotated dream_intern_Pool read the freed table: wrong tokens, nil for a key the pool held. A pool now looks a key up first and grows only to add one, so a key it holds moves nothing. Unannotated pools were never affected.
    • The @dream/data definitions gave gather, scatter and add a kind: dream_data_Kind parameter, the union of receiver classes, where the runtime takes the layout string every other span takes; and they typed a span's kind as the eight bare kinds, so the documented strided form ("f32@16+12") was a type error under --!strict. A span's kind is now a dream_data_Layout, dream_data_ElementKind | string, in every signature, and the strict-script gate that checks the definitions against the runtime covers @dream/data, which it had left out.
    • data.fill's description said the value converts as buffer.write<kind> converts. It is written as every data-plane write is: a number, truncated toward zero and wrapped to the width, saturating first beyond 2^63. The description says so now; the behaviour is unchanged.

    Migration

    Nothing to change. A pool annotated dream_intern_Pool that also receives keys through unannotated code was the exposed case, and is correct after an upgrade. A strict script that cast a strided layout to pass it to @dream/data can drop the cast.

    2 relationships source 4153fd64c1b7 · tag 2.0.2

    l3i-2.0.2.crate 2.3 MiB · Rust crate
    Verify · sha256 18ad03a9047a…dbe36a5e · 1 source
    SHA-256
    18ad03a9047a3e169553e0540a553e8c7442f428b6b0bd7a272983cedbe36a5e
    Size
    2394884 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.0.2.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.0.2.crate must print the digest above.

  8. 2.0.1 stablemigration notes 2026-10-12

    A sink or slice statement may open a function body, and the `@dream/luau` definitions declare the record pattern nodes the tree has carried since 2.0.0.

    Publisher's notes

    Fixed

    • A statement that begins with a sink or a slice (into(out)[for x in xs => x], grid[2:3][1][1] = 5) failed to compile as the first statement of a function body, with Expected identifier when parsing expression, got ';': the lowering separated it from a statement that was not there. A body's first statement now gets no separator, whatever the header ends with, and where a return type ends is decided by Luau's parser, not estimated.
    • The @dream/luau definitions did not declare StatLocalPattern, PatternRecord, PatternField or PatternIdentifier, and typed ExprFunction.args and ComprehensionGenerator.bindings as lists of dream_luau_Local although a record pattern can stand in either. They are declared now, dream_luau_StatLocalPattern is a member of dream_luau_Stat, and a slot that may hold a pattern is a dream_luau_Binding, dream_luau_Local | dream_luau_PatternRecord.

    Migration

    A strict script that reads name off an element of ExprFunction.args or of a generator's bindings refines it by kind first, "Local" or "PatternRecord". Nothing changes at run time.

    2 relationships source 0d1b245d21f6 · tag 2.0.1

    l3i-2.0.1.crate 2.3 MiB · Rust crate
    Verify · sha256 4867f43ba175…b6e5eb06 · 1 source
    SHA-256
    4867f43ba1752f1ecbbe48dc6be68e9dc9ac342b2743a5417dc34f5eb6e5eb06
    Size
    2393217 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.0.1.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.0.1.crate must print the digest above.

  9. 2.0.0 stablebreaking notesmigration notes 2026-10-11

    A dialect of Luau whose comprehensions, reducers, sinks, slices and record patterns lower to the handwritten loop with tooling in original coordinates; a bulk-data plane over typed buffer spans with native loops; raw TCP, DNS and verified TLS; locales, plural rules and decimal formatting; Luau 0.742; and the renames and defaults that needed a major version to change.

    Publisher's notes

    Breaking changes

    • @dream/net is @dream/udp: the extension is dream.udp, the Rust module l3i::udp, the type UdpExtension, the C symbols dream_udp_*. The capability is still network.transport.
    • TcpExtension and TlsExtension are no longer unit structs. .extension(TcpExtension) becomes .extension(TcpExtension::default()); TlsExtension::new() or ::default() likewise.
    • noDelay defaults to true on tcp.connect and tcp.listen: Nagle's algorithm is off unless a script passes { noDelay = false }.
    • luau.parse defaults to the l3i dialect, so comprehensions, slices and record patterns come back as source nodes; { dialect = "luau" } selects strict stock syntax.
    • Luau 0.742 (from 0.740). ffi::lua_setbuffercage is lua_setmemorycage; disable_native_execution_for_function is gone with Luau's own; LuauNoDuplicateBinaryPrefix and LuauCompileIifeInline graduated and left the flag list.
    • Coroutine finalizers are chosen on the builder: RuntimeBuilder::coroutine_finalizers(bool) replaces Runtime::enable_coroutine_finalizers, and Thread::finalizer_function(scope, close) replaces Runtime::finalizer_function(). The first runtime built in a process decides for the process.
    • DnsExtension::new lets 8 of a runtime's lookups occupy a shared resolver by default, not 2.
    • The growable public types new since 1.3.1 are #[non_exhaustive]: tcp::StreamState, tls::TlsState, dns::LookupError, dns::ResolverConfig, data::Kind, data::Layout, data::ReductionOp, data::Reduction, intl::Grouping, intl::DecimalOptions, intl::FormatterError, intl::Operand, intl::NumberError, intl::LocaleError, intl::UnsupportedLocale. Matches need a wildcard arm; the structs are built with ResolverConfig::new(workers, queue), Layout::new(kind, stride, offset), Reduction::new(op, filter) and DecimalOptions::new().grouping(..).fraction_digits(min, max).

    Added

    • The l3i dialect: [for e in entities if e.active => e.id] comprehensions with range, enumerate, zipShortest and zipStrict generators; #, sum, min, max, any and all consumers that allocate no result; into(destination) table sinks and into(buffer, "kind"[, offset]) buffer sinks; inclusive slices t[a:b] of tables and buffers and typed slices buf[1:n, "f32@16"]; and record patterns local {x, y} = p in declarations, parameters and generator slots. One frontend built on Luau's lexer lowers all of it to the same-contract handwritten loop, one setup instruction apart, and compilation is strict while Analysis and @dream/luau recover unfinished constructs.
    • Original coordinates everywhere: Analysis diagnostics and autocomplete, analysis::parse, @dream/luau trees, compile errors, runtime errors, tracebacks, breakpoints and coverage all report the source you wrote, through a source map the frontend records as it lowers.
    • @dream/data (feature data): reductions, comparisons into reusable selections, selection algebra, gather, scatter, fill, add, scale, clamp, stable argsort with optional caller scratch, and partition over typed, optionally strided buffer spans, bound once per operation with no per-element callback. Typed receivers data.u8() through data.f64() lower their thirty-nine reductions and selects to unrolled native loops under jit, and the dialect's recognized reductions over buffer slices call the plane automatically.
    • @dream/tcp (feature tcp): nonblocking listeners and byte streams over numeric addresses, readInto into caller buffers with end of stream kept apart from would-block, partial writes with no hidden queue, half-close, and a bounded, level-triggered poller that never calls Luau and watches only what has something to report. Behind network.tcp.connect, network.tcp.listen and network.tcp.public.
    • @dream/dns (feature dns): host name resolution through the OS resolver on a bounded worker pool: one-shot requests that never block the script, IDNA names, both address families in the OS's order, deadlines and cancellation, watchable by the TCP poller. Behind network.dns.resolve.
    • @dream/tls (feature tls): verified TLS 1.3 and 1.2 client and server sessions over TCP streams with rustls, the platform trust store or explicit roots, name verification independent of the address, ALPN and SNI, bounded buffers, close_notify kept apart from truncation, nonblocking and watchable. There is no way to skip verification.
    • @dream/intl (feature intl): BCP 47 locale identity, CLDR cardinal and ordinal plural categories that see visible fraction digits, and locale-aware decimal formatting from ICU4X's compiled data; no catalog and no current locale.
    • ExtensionDescriptor::widen_type_alias, so an extension can add its handle type to a union another extension declared without that extension knowing it; dream_tcp_Watchable is widened by dream.dns and dream.tls.
    • Luau 0.741's GC heap-shrink pacing fix and 0.742's compiler and code generator fixes are on, each with its reason beside its name in flags::LUAU_FLAGS.

    Changed

    • A tcp Poller:wait scans only the watches with something to report, so idle sockets cost it nothing: one ready stream among 8192 idle watches costs 0.4 µs, as among 1024. The event buffer starts at 256 entries and doubles as waits fill it, up to maxEvents, instead of being allocated at maxEvents up front.
    • A tcp stream's localAddress is asked of the OS on first use and remembered. Deadline-based readiness is judged once per wait, not per next().
    • tls.clientConfig{ roots } with the platform store caches the verifier per distinct root set (8 sets of at most 256 KiB each per runtime) instead of reloading the store per call; the platform store alone is still loaded once per runtime. A TLS write whose socket has just refused bytes does not try the socket again in the same call.
    • Pollers and TLS configurations are capped per runtime (TcpExtension::max_pollers 64, TlsExtension::max_configs 32), and the documentation says which native memory the VM's memory limit does not see.
    • A slice bound spelled as an integer literal skips its run-time check; a standalone slice of a 16-element table costs about 215 ns against 150 for a handwritten table.create plus table.move.
    • Plain Luau that never uses the dialect is lexed once by the frontend, and only when it contains a [: about 17 to 20 percent over stock luau_compile on 16,000 lines with indexing in loops or calls inside brackets, nothing without a bracket.
    • The fast-flag policy is documented as l3i's own named list rather than as another project's.

    Fixed

    • Standalone slices after a .name, :method(), call or index chain, slices of slices, and slices or comprehensions that use the enclosing function's ... lowered to broken Luau; a slice that starts a statement was refused.
    • zipStrict never compared the first argument's length. any and all over a buffer slice past the end asked the data plane for a span at an out-of-range offset.
    • Data span arithmetic could overflow (an abort when bound, a wrap when native); any/all consumers now guard an empty span like the other reductions.
    • A handshaking TLS session reported a stale readable bit while rustls had unsent flight bytes, a latent busy loop. Poller:close leaked a descriptor. An accept refused for want of descriptors re-armed the listener on every wait.
    • SIGPIPE from a TLS writev and from process.run's stdin feeder killed the host; stack overflows in the location remapper and tree builder on deep shadow chains; quadratic prescans in the frontend; intl decimal exponents past 32767 overflowed an i16 in the parser.
    • The comprehension nesting limit counted clause delimiters; parentheses and brackets inside a clause no longer count toward the 128 levels.

    Migration

    Downstream plans need one line per network extension: .extension(TcpExtension::default()) and .extension(TlsExtension::new()). Rename @dream/net requires and net compat globals to @dream/udp and udp. A match over any of the types listed above needs a wildcard arm. Tools that read @dream/luau trees and expect generated wrappers pass { dialect = "luau" } or, better, handle the dialect's nodes. Scripts that relied on Nagle pass { noDelay = false }. Recompile cached bytecode to pick up original debug lines.

    2 relationships source 579589fcf210 · tag 2.0.0

    l3i-2.0.0.crate 2.3 MiB · Rust crate
    Verify · sha256 e4cb6a3e1060…569f35d8 · 1 source
    SHA-256
    e4cb6a3e1060b0bf2480b0970b5f0eefe363cf7c94fc1dad47342b3f569f35d8
    Size
    2377858 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-2.0.0.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-2.0.0.crate must print the digest above.

  10. 1.3.1 stable 2026-10-02

    Luau can now create capability-gated dream.net servers and mint private-key-backed connect tokens, and l3i can emit a textual disassembly of the exact compiled bytecode.

    Publisher's notes

    Added

    • net.server{ schema, address, protocolId, maxClients? } creates a dream.net server from Luau when network.transport is granted. The generated signing key remains private inside the server userdata; server:connectToken(clientId, expiresInSeconds?, timeoutSeconds?) returns only the token clients need.
    • l3i::source::disassemble(source, options) emits Luau's textual bytecode listing for every function, including instructions, source lines, locals and constants, using the same compiler options and library callbacks as source::compile.

    2 relationships source 29cc97da2076 · tag 1.3.1

    l3i-1.3.1.crate 1.8 MiB · Rust crate
    Verify · sha256 fbbb48c9258b…9f497b7d · 1 source
    SHA-256
    fbbb48c9258b9488248e8d07928c6f47ffdd01bf1e1d55267456f8c39f497b7d
    Size
    1869180 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-1.3.1.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-1.3.1.crate must print the digest above.

  11. 1.3.0 stable 2026-10-01

    Luau's own parser for scripts with `@dream/luau`: the syntax tree with exact spans, comments, errors and the token stream, built as tables in native code and typed for strict walkers; and named Luau types for extensions whose values are plain tables.

    Publisher's notes

    Added

    • @dream/luau (feature syntax): luau.parse(source, options?) runs Luau::Parser under the runtime's fast flags and returns the tree as tables, every node with its kind and a 1-based span, one table per local shared by its declaration and every use, string quote styles, every comment and hot comment, parse errors as data with the recovered tree, and, with { tokens = true }, Luau's token stream as a buffer of 12-byte records; { declarations = true } parses definition-file syntax.
    • The tree costs 17205 instructions per source line built and collected, against 27861 for the parser and Luau's own JSON encoding of it, which a script would still have to decode.
    • ExtensionDescriptor::type_alias: a named Luau type an extension's signatures refer to, for values that are plain tables, rendered as export type ahead of every module.
    • @dream/bytes's toBase64 and fromBase64: standard padded base64 of a range of a buffer or string in one call, and back, refusing anything that isn't base64 by naming the byte.
    • @dream/bytes's frame: one native walk over a run of tag-length-payload chunks (RIFF, IFF, PNG, GLB, Bethesda records), the layout given as data, returning every chunk's start and end as u32 pairs and, when it stops early, why and where; an inner layout checks that each payload's chunks tile it. A megabyte of records and fields in 0.98 ms against 9.8 ms for the Luau walk.
    • @dream/bytes's regex (feature bytes-regex): a pattern compiled once over bytes, whose matchSpans tests every (start, end) range of a buffer in one call and answers with a byte per range, so a thousand small fields cost one call and no strings; isMatch and find over one range.
    • @dream/fs (feature fs): the host filesystem over byte paths, with whole and positional reads, readers over a memory map, writers with positions and truncation, stat and lstat, a walk that returns parallel columns, recursive removal, renames, copies, hard and symbolic links, canonical paths and file identity, behind the filesystem.read and filesystem.write capabilities. What the OS refuses returns nil, the message and the error's kind, the way io.open does.
    • @dream/process (feature process): run starts a program with no shell, waits for it, and returns its exit code with its output passed through, captured or discarded, behind process.spawn; env behind process.environment; write and isTerminal for the standard streams.
    • @dream/bytes's translate(text, from, to, { collapse?, trimStart?, trimEnd? }?): bytes mapped like tr, runs of one byte collapsed, one byte trimmed from each end, and the text itself returned when nothing changes; folding a path's case and separators costs 141 ns a call against 470 ns for string.lower plus string.gsub.
    • @dream/intern's rules policy, intern.new({ nocase?, replace?, collapse?, trimStart?, trimEnd? }): keys normalized inside the hash and the compare, so Meshes\\X//Rock.NIF and meshes/x/rock.nif are one token with no normalized string made; the byte map lowers to native code eight bytes at a time, 522 instructions for a duplicate 31-byte path against 5008 for string.lower plus string.gsub and a table read, and resolve returns the normal form.

    2 relationships source fe45a61c195a · tag 1.3.0

    l3i-1.3.0.crate 1.8 MiB · Rust crate
    Verify · sha256 2a7408935412…86a577c6 · 1 source
    SHA-256
    2a74089354121cdfe98845443e87f1eaf8e5b616ab9c3a08dcbaa2fb86a577c6
    Size
    1867226 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-1.3.0.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-1.3.0.crate must print the digest above.

  12. 1.2.0 stable 2026-09-30

    Textual identity as dense numbers with `@dream/intern`, lowered so a repeated identity never leaves native code; a zstd encoder; a constant that says whether a build used the verified toolchain; a slow path for lowering hooks that stays native; and cheaper string, buffer and optional arguments for every binding.

    Publisher's notes

    Added

    • @dream/intern (feature intern): pools that turn strings or buffer spans into dense number tokens under exact or ascii-nocase equality, folding case inside the hash and the comparison, so no lowered copy is made and a repeated identity allocates nothing. find, resolve to the first spelling seen, and interner() for interpreted code.
    • Under jit, an annotated dream_intern_Pool's intern and find lower to native code: a case-insensitive duplicate costs 315 instructions against 1378 for string.lower and a table lookup, and an insert or a bad argument runs the bound method without leaving native code.
    • IrBuilder::namecall_call: the namecall and call Luau would have emitted, as a userdata namecall hook's slow path.
    • l3i::VERIFIED_TOOLCHAIN: true exactly when build.rs found the verified toolchain, whether or not L3I_UNVERIFIED_TOOLCHAIN was set, for hosts that publish performance numbers.
    • @dream/bytes's zstdCompress, through ruzstd's one implemented level; any other level is refused by name.
    • Runtime::registered_require_modules: every path registered with register_require_module, the plan's included, in registration order.

    Changed

    • Q:fromXYZW lowers to native code: 93 instructions against the binder's 459.
    • String, buffer and string-or-buffer arguments are read straight from Luau's value layout (54 instructions instead of 293), and a trailing optional argument is read once (two optional integers cost 335 fewer instructions).

    Fixed

    • A lowered rotation packs with the omitted component's own sign, so a quarter turn whose two largest components tie with opposite signs no longer packs a different rotation.

    2 relationships source 8d793d4c5cdb · tag 1.2.0

    l3i-1.2.0.crate 1.7 MiB · Rust crate
    Verify · sha256 40aa6321c1d1…3c6aec8c · 1 source
    SHA-256
    40aa6321c1d1b5e2ab41e9efaa8af0d97b1b79a2dcb89c92b9d7f89a3c6aec8c
    Size
    1803998 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-1.2.0.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-1.2.0.crate must print the digest above.

  13. 1.1.0 stable 2026-09-30

    Chunks load on any scope's thread under the runtime's native code policy, the code generator is reachable from a call, templates resolve their imports at load time, and a frame's call site costs two debug fields.

    Publisher's notes

    Added

    • source::LoadScope, implemented for every scope: load_bytecode and load_source load a chunk on the scope's own thread, so Luau resolves its builtin imports against that thread's safe globals, and compile it natively according to the runtime's mode, so a require written in Rust needs neither the Runtime nor luau_load by hand.
    • NativeCodeGen::for_scope: the runtime's code generator from a bound function's Call or any other scope of its VM.
    • DebugScope::call_site: the chunk name and current line of a frame, asking Luau for those two fields only; Luau records lines, not columns.
    • Templates load on a loader thread whose globals are the base environment, so Luau resolves their builtin imports when the template loads and every instance takes the fast import path from its first run.

    2 relationships source 59c53ddd5b77 · tag 1.1.0

    l3i-1.1.0.crate 1.7 MiB · Rust crate
    Verify · sha256 24d35931d97c…d01d18bc · 1 source
    SHA-256
    24d35931d97c63da75ae56371bf67577f401dafe2e6546d5c2a174a8d01d18bc
    Size
    1771181 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-1.1.0.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-1.1.0.crate must print the digest above.

  14. 1.0.0 stable 2026-09-29

    First release: the whole Luau 0.740 C API under a scoped Rust layer, planned runtimes composed from extensions, sandboxes, the dream-net bridge in every VM, and native lowering hooks written in Rust.

    Publisher's notes

    Added

    • The typed binder: Runtime::bind_function reads arguments straight from Luau's 16-byte value layout, with the C++ binder's optional, variadic and overload rules and its exact error wording.
    • Tagged and untagged userdata per runtime: the same Rust type may be tag 8 in one VM, 17 in another, and untagged in a third; generated __index and __namecall dispatchers that cost one Luau call frame.
    • Runtime plans: an Extension describes modules, userdata, packed kinds, services and capabilities without a VM, and RuntimePlan::finalize assigns tags, compiler slots, atoms and direct slots, validates every identifier and path, and renders the .d.luau for the composition.
    • Sandboxes with the C++ binder's prelude, per-script instances, and compiled templates cloned per script.
    • The dream.net bridge in every plan: schemas, clients gated by the network.transport capability, host-created servers, and pollInto with one payload copy and no allocation.
    • Packed 64-bit scalars with a kind registry: dream.quat rotations and animation keys, dream.raster colours and clip rectangles, and dream.soft_render behind the soft-render feature.
    • Native code generation (jit): Luau's CodeGen with lowering hooks written in Rust against an IrBuilder C ABI; quaternion, colour and vertex-writer paths that lower to IR with no C call.
    • Luau's Analysis frontend (analysis): type checker, linter and autocomplete over a source provider, definition files, and the gate that type checks a plan's declared API against strict scripts.
    • @dream/bytes (bytes) for parsing foreign file formats in script: searching, record strings, varints, big-endian, 24-bit and half-float reads with a receiver lowered to native code, and behind their own features the codecs (DEFLATE, LZ4, zstd, LZMA), the digests (CRC-32 to BLAKE3) and the text codepages, all pure Rust.
    • Watchdog limits, memory categories, call scopes, collector control and the profiler plumbing a game engine needs, and every function in lua.h, lualib.h, luacode.h, luacodegen.h, luajitinliner.h and Require.h declared by hand.
    • The clang, lld and cross-language thin LTO toolchain, enforced by build.rs and measured in TOOLCHAIN.md: a bound call within forty instructions of a bare C function.
    • Templates load from any thread of the VM: Sandbox::load_template_in takes only the scope, so a require loader captures the sandbox and nothing else.
    • Rust 1.92, clang and lld; dream-net 1.1.0.

    2 relationships source 6752b3eaf495 · tag 1.0.0

    l3i-1.0.0.crate 1.7 MiB · Rust crate
    Verify · sha256 134fabf21800…29fbc11d · 1 source
    SHA-256
    134fabf2180017b64f9d361f2e42374aed00c22257285cc5030743aa29fbc11d
    Size
    1767011 bytes
    Media type
    application/gzip
    publisher
    https://static.crates.io/crates/l3i/l3i-1.0.0.crate

    The digest is the publisher's claim, recorded in its manifest. This index did not download the archive. Check it yourself: sha256sum l3i-1.0.0.crate must print the digest above.

07Observed changes

What this index saw change in this claim's manifest.

  1. 2 changes
  2. stable 2.1.3 → 2.2.0 releasemigrationartifacts
  3. stable 2.1.2 → 2.1.3 releasemigrationartifacts
  4. stable 2.1.0 → 2.1.2 releasemigrationartifacts
  5. stable 2.0.3 → 2.1.0 releasebreakingmigrationartifacts
  6. stable 2.0.2 → 2.0.3 releasemigrationartifacts
  7. stable 2.0.0 → 2.0.2 releasemigrationartifacts
  8. stable 1.3.1 → 2.0.0 releasebreakingmigrationartifacts
  9. stable 1.3.0 → 1.3.1 releaseartifacts
  10. stable 1.2.0 → 1.3.0 releaseartifacts
  11. stable 1.1.0 → 1.2.0 releasedependenciesartifacts
  12. stable 1.0.0 → 1.1.0 releaseartifacts
  13. first observed observed

08People

  • maintainerS3kshun8
  • Luau, the language and VM this crate builds and binds (MIT)Roblox
  • netcode, reliable and serialize, beneath dream-netMás Bandwidth LLC
  • libopus, the Opus decoder behind @dream/audio (BSD-3-Clause; a binary that ships it reproduces opus/COPYING)Xiph.Org Foundation and contributors
  • nanomp3, the MP3 decoder behind @dream/audio (MIT OR Apache-2.0)Robert B. Langer
  • lewton, the Vorbis decoder behind @dream/audio (MIT OR Apache-2.0)est31