Try it in your browserpreview Source

The Roblox demo✎

The project that ships: a module, a server script, and the map that places them.

Pending review

One project, two graphs and a node map. It is examples/demo — the project the Roswaal panel offers to take a copy of, and the one roswaal init leaves you standing in — so what is drawn here is what you would open.

Info

Take a copy rather than opening it in place. Demos under the mark copies it somewhere of your own; the original is shared by everyone who installed Roswaal.

A module, and a function in it

Greeter is a ModuleScript. It declares a function, returns a string from it, and hands the function out through Module Exports — which is the node that decides what require gives back.

AccumulateNumGreetPlayerModule Exports−+greetexport2
The graph this was compiled from, and what it declares.
++−Return−+AccumulatedSet VariableAccumulatorValueAccumulatorAccumulateNum(A: number) → number−+FunctionA
Concatenate−+Hello, ABGreetPlayer(who: string) → string−+FunctionwhoReturn−+message
luau
local Accumulator: number = 0

local function AccumulateNum(A: number): number
	Accumulator = A + Accumulator
	return Accumulator
end

local function GreetPlayer(who: string): string
	return "Hello, " .. who
end

return {
	greet = GreetPlayer,
	export2 = AccumulateNum,
}

Info

Each Function has a tab of its own, as in the editor. See Functions.

A script that runs when the place does

Main is a Script, so it runs on the server. It gets a service, requires the module beside it, calls the function out of it, and connects to an event — which between them is most of what any Roblox script does.

Sequence−+Then 0Then 1Custom CodenewPart.Material = Enu…CodeCustom Code(empty)CodeConnect EventBodySignalConnectionplayerplayersJoinedSet VariableplayersJoinedValueCall Function−+ResultFunctionArgumentRequire ModuleReplicated…InShared.G…PathGreeterAsGet FieldObjectgreetField1++−Get PropertyInstanceNamePropertyPrintValueGet EventInstancePlayerAd…EventScript StartGet ServicePlayersService
The graph this was compiled from, and what it declares.
luau
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Greeter = require(ReplicatedStorage.Shared.Greeter)

-- How many players have joined since the server started.
local playersJoined: number = 0

Players.PlayerAdded:Connect(function(player: Instance)
	local result = Greeter.greet(player.Name)
	print(result)
	playersJoined = playersJoined + 1
end)

-- your Luau here

print("This is from a custom code block.")

local newPart = Instance.new("Part")
newPart.Parent = workspace
newPart.Anchored = true
newPart.Size = Vector3.new(5, 5, 5)

newPart.Position = Vector3.new(10, 5, 10)
newPart.Material = Enum.Material.Neon

Info

Nothing in that file arrived on its own: the require, the Get Service and the Connect are all nodes. See Modules and Services and their methods.

Where it lands in the DataModel

The map says where the generated files go, and compiles to the default.project.json that Rojo reads. This is the demo's own, in the editor that edits it:

roswaal-demo
▸DataModelDataModel
▸ServerScriptService
SourceFoldersrc/ServerScriptService/Source
▸ReplicatedStorage
SharedFoldersrc/ReplicatedStorage/Shared

This map

Instance

Ignore paths

Globs under this instance's path that Rojo should skip, e.g. shared/** — how you stop a nested mapping syncing twice.

Project file

Written to default.project.json when this map is compiled.

Project-wide ignores

Passed to Rojo as globIgnorePaths, unanchored.

{  "name": "roswaal-demo",  "tree": {    "$className": "DataModel",    "ServerScriptService": {      "Source": {        "$path": "src/ServerScriptService/Source"      }    },    "ReplicatedStorage": {      "Shared": {        "$path": "src/ReplicatedStorage/Shared"      }    }  },  "globIgnorePaths": [    "**/*.spec.luau"  ]}
  • The treeEvery instance the map describes. 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.
  • NameThe instance's name in the DataModel.
  • ClassBlank on a service, because Rojo infers it from the key and rejects it being said twice.
  • PathThe folder or file on disk whose contents fill this instance.
  • Ignore unknownRojo leaves alone anything in Studio that it did not put there.
  • Ignore pathsGlobs under this instance's path that Rojo should skip.
  • Add folder, Add service, DeleteBuild the tree. Services can only be added to the root.
  • OutputWhere the project file is written, relative to the project root.
  • Project-wide ignoresPassed to Rojo as globIgnorePaths, unanchored.
  • The project fileWhat the map compiles to. Selecting a row lights the lines that row writes.
The demo's map. Select a row and the Inspector fills with that instance's fields, while the project file scrolls to the lines the row writes.

Compiling and nodemaps for Roblox is the page about that panel — what each field does, and what happens when you compile.

Running it

Compile the project, then point Rojo at it and connect from Studio. Roswaal writes the .luau files and the project file; everything after that is Rojo's, and Roswaal never talks to Studio itself.

sh
roswaal compile   # writes src/ and default.project.json
rojo serve        # then connect from Studio

Info

The demo also ships two node packs in .roswaal/nodes, unused by these graphs, to open in Node Design. See Creating custom nodes.

Not reviewed yet