canaryThese pages document the canary: an unreleased build. What they describe may not be in the version you have, and may change before it is.The stable build
Try it in your browsercanary Source

Compiling and nodemaps for Lune✎

A graph becomes a file, and the file is where it is. No DataModel, no project file.

Pending review

This page is about graphs whose Target is Lune. The bar along the top of the canvas says which, and a new graph takes the project's. For Roblox, the answer is a different one and it is on Compiling and nodemaps for Roblox.

A graph is a .nodescript under .roswaal/scripts. Compiling it writes a .luau file to the same place under the output directory, in the same shape: .roswaal/scripts/lib/json.nodescript writes src/lib/json.luau. Both directories are project settings.

Info

There is no DataModel, so there is nothing to sync. Lune runs the file where it is — lune run main — so the layout on disk is the whole answer.

Nodemap basics

Here is the whole of it. A .nodemap is edited in Roswaal rather than by hand, and this is that editor with Describes set to A filesystem — the tree on the left, the Inspector on the right, and the layout it describes underneath. Every part is named beside it; the rest of this page explains them in order.

tool
▸tool
main.luau
▸lib
json.luau
text.luau

This map

Directory

The layout

Directories and files, as they sit on disk. Nothing is written when this is compiled — a Lune program has no project file, so what compiling does is check the layout holds together.

main.luaurequire("./main")lib/  lib/json.luaurequire("./lib/json")  lib/text.luaurequire("./lib/text")
  • The treeEvery directory and file the project has. Pick one and the Inspector follows.
  • DescribesWhether this is a DataModel for Roblox or a filesystem for Lune. It decides what the rest of the panel is.
  • NameWhat it is called on disk — with no extension, which the row on the right adds.
  • KindA directory, or a file Roswaal writes a .luau for. Absent on the project root, which is neither.
  • Add directory, Add file, DeleteBuild the tree. A file takes no children.
  • The layoutThe directories and files as they land, and the require that reaches each one. Nothing is written — compiling a filesystem map checks it.
The same panel, describing a filesystem. Select a row to fill the Inspector. A name carries no extension — main in the map, main.luau on disk, and the require that reaches it beside.

What a graph compiles to

Always a .luau file named after the graph. A Roblox graph picks between Script, LocalScript and ModuleScript, and the choice decides the file's ending because Rojo reads it — Greeter.server.luau. Lune has no such distinction: a file is a file, and whether it is a program or a module is decided by whether something requires it.

Warning

Lune support is experimental. It has not yet been tested by an experienced Lune developer, so treat what it writes as a starting point.

Compiling

What it compiles
Compile script, or Ctrl + SThe open graph
Compile projectEvery graph, then every node map
Compile: DynamicEach graph as you edit it, and any that change on disk — after a git pull, say
roswaal compileEverything, or the one graph or map you give it
roswaal watchThe same, without the editor

A graph with errors writes nothing; warnings do not stop it. With format on and StyLua on your PATH, the file is formatted as it is written. Then lune run main — Roswaal does not run it for you.

A generated file starts with a header naming its graph and a hash of what was written. Roswaal will not overwrite a file whose hash no longer matches — one edited by hand — or a file it did not write. Rename a graph or move it and its next compile removes the file it used to write; roswaal prune lists the ones left behind by a graph that is gone.

What a nodemap is for here

A map still has a job, and it is the one Rojo was doing incidentally: saying the layout out loud, and checking it holds together. Set a map's Describes to A filesystem and it becomes directories and files rather than services and instances. A new map is already the right kind — it follows the project's target.

What the right-hand column is not is a file Roswaal writes. A filesystem map compiles to nothing: the disk is already the answer, and compiling the map is checking that the answer is one Luau can load.

A DataModel mapA filesystem map
Root isThe DataModelThe project directory
Children areServices, folders, instancesDirectories and files
Compiles todefault.project.json, for RojoNothing — it is a check
A node hasA class and a path on diskA name, and whether it is a file

What it checks

These are require-time errors in Luau, not house style. The language refuses an ambiguous path rather than picking one, so a layout with both of these is one the runtime will not load — and a map catches it while you can still move something, with both things named.

  • A file beside a directory of the same name. require("./foo") cannot mean both foo.luau and foo/init.luau.
  • Two files differing only by extension. foo.luau and foo.lua both answer to ./foo.
  • A name a require cannot reach — letters, digits, ., - and _, and no directory separators.

Info

A file's name has no extension: main in the map, main.luau on disk. Typing one is a warning, so you do not end up with main.luau.luau.

Requires, and what the file depends on

Everything a Lune program reaches for arrives through a require you wrote. The standard library is Lune's standard library; a short name for a path is Aliases and .luaurc; and the rule behind both is on Modules — a generated file does not grow imports nobody chose.

Warning

Roblox datatypes need @lune/roblox. Vector3 and CFrame compile once it is required with the datatype as a member; the Inspector has the button. TweenInfo is not offered in Lune.

Not reviewed yet