backupRoswaal has moved to roswaal.app. These pages are a backup copy.Go to roswaal.app

Settings and themes✎

What is a project setting, what is yours, and how a colour scheme is written.

Verified

There are two kinds of setting and they behave differently, which is worth getting straight before changing either. Project settings are roswaal.json: committed, shared by everyone working on the repository, and they change what the compiler does. Preferences are yours — stored in your browser, never written to the project, and invisible to everybody else.

Info

Both are edited from Settings, which lists its pages under where they are kept, so a personal colour scheme stays out of pull requests.
PageKept inWhat is on it
Compilingroswaal.jsonWhere graphs and Luau live, how a graph compiles, and indentation
Node packsroswaal.jsonThe directories scanned for node packs
CanvasThis browserThe grid, wires, node corners, and what scrolling does
NodesThis browserLong names, and what a new logic, cast or concatenate node starts as
WorkspaceThis browserWriting a graph, the Variables panel, function tabs, the action row, and what opens first
ThemesThis browserThe colour scheme
DocsThis browserThe docs' font and the size of their pictures

Search settings, at the top of the list, finds a setting on any page by its name or by what it does; Esc clears it, and Esc again closes Settings. Node Design has no project to change, so its Settings has no project pages; the docs' has only Themes and Docs, and says the rest is in the editor.

Project settings

Written to roswaal.json in the project root. roswaal init writes the defaults out; every one of them is optional in a hand-written file.

KeyDefaultWhat it does
targetrobloxWhich flavour of Luau new graphs compile for. lune is experimental, and not yet tested by an experienced Lune developer; it drops the Roblox globals and nodes.
sourceDir.roswaal/scriptsWhere .nodescript and .nodemap files are read from.
outDirsrcWhere generated .luau is written. This is the directory Rojo syncs.
compileModemanualhot recompiles a graph every time it is written, which is every edit; manual waits to be asked. The editor shows these as Dynamic and Manual — the stored name is hot for the sake of every roswaal.json already written.
nodePaths[".roswaal/nodes"]Directories scanned for .nodedef.json node packs.
formattrueRun stylua over generated files when it is on PATH. When it is not, the file is written unformatted rather than not written.
commentstrueWrite each comment's header into the generated Luau, above the code of the nodes it is drawn around. A header of one line is written -- like this, one of several as a --[[ ]] block. Off keeps them in the editor, which is what other visual scripting tools do — see Coming from Blueprints if that is the habit you have.
castsByHierarchyfalseAn Implicit Cast inside an Is A branch is always left out when the branch proved exactly its classes. On, it is also left out when the branch proved a class derived from the one it casts to — Is A Part covering a cast to BasePart.
indentStyletabWhat one level of indentation is in the generated Luau: tab, or space. Handed to stylua as well when format is on, so this decides rather than whatever stylua.toml says.
indentWidth4How many spaces one level is, when indentStyle is space. Ignored otherwise, except that stylua is told it so a tab still counts the right amount against its column limit.
rojoProjectunsetNo longer read. An older roswaal.json may carry it, and it still loads. The Rojo project file is written by a node map, at the map's own Output — default.project.json unless it says otherwise — and only over a file Roswaal wrote, or one you hand over with force.
placeunsetThe project's place file, set by roswaal import. Unset, a .rbxl or .rbxlx in the project root, place.rbxl first.
schemaVersionset for youWhich schema the file was written against. migrate.ts reads it.

Preferences

Stored in this browser under one key, and nowhere else. They do not follow you to another machine, which is the right thing to give up: the alternative is a per-developer file in a shared checkout.

PreferenceWhat it does
ThemeThe colour scheme, or Follow the system — which is the absence of a theme rather than a scheme of its own, so the app keeps changing with your OS.
WiresCurved is a bezier out of each pin, and the default. Rigid turns at right angles only. Angular leaves the pin level, takes one straight run to the other end, and arrives level — a diagonal rather than a cut corner. Where the input is behind the output there is no straight line to take, so angular borrows rigid's lane out and back, with its corners cut.
Node cornersRounded or square. Capsule getters and reroute knots keep their shapes either way — a pill and a circle are what say this is a value and this is a bend in the wire, and neither has a title to say it instead.
GridThe pattern behind a graph, on the canvas, in Node Design and on the start page. Dots, the default, puts a dot at every point Shift-drag snaps a node to, and leaves the nodes and wires the strongest thing on the canvas. Lines rules the canvas as Roswaal did before 0.150.0, every fifth line heavier, for anyone who lines nodes up by eye. Zoomed far out either keeps only every fifth.
Grid contrastHow strongly the grid draws. Auto, the default, is light, and strong when your system asks for more contrast. Light is faint, there when you look for it; Standard is easier to see on a bright screen; Strong is clearly visible, with larger dots, for low vision or a washed-out display. The grid only decorates: nothing about a graph is shown by it alone.
Long namesTruncate cuts a header too long for its node short, with the whole of it in the tooltip — what nodes have always done. Widen draws the node wide enough for its header instead. It is the one of these looks that moves pins, so the wire router and the pictures on these pages are computed from the same width: a node and its own picture are never two different sizes.
New concatenate nodesWhat a new Concatenate writes: a join with .., or an interpolated string, where a part typed into the node is text and a part wired in is a hole in braces. The same string either way, and both are Luau, so the choice is about how the line reads. Stored on the node, as the brackets are — this only decides what one you drop today starts as, and Concatenation Type in the Inspector changes any of them.
New logic nodesWhether a new And, Or, Not, comparison or arithmetic pill starts out bracketing its expression. Only the starting point: whether a node brackets is stored on the node, so it travels with the graph and reads the same on everybody's machine. Precedence is handled either way — this is about how the line reads, never about what it means. The casts are pills too and are not offered it: (value :: T) brackets itself already.
Shorten function tabsWhat a function's tab says. None keeps ƒ hide (Occupancy); Function name and Script name keep one of the two. The tooltip has both.
Write a graphHow long after your last edit a graph is written. A delay, not a switch — there is no unsaved copy of a graph, so switching it off would give you a document that quietly stops matching itself rather than a buffer.
ExportingWhat the Export menu starts with: zip or place, compile first, Modify RBXL, and the place's format. Kept in roswaal.json.
Modify DataModel InstancesOff by default. On, Properties changes values in the place file, after a backup. See Places and Rojo.
On opening RoswaalReopen the last project, or start at the picker.
Docs fontThe face the docs are read in: System, Serif, Wide or Monospace. Code keeps its own.
Preview sizeHow large node and graph pictures are drawn in the docs, from 50% to 300%. A graph bigger than its frame can be dragged around.

Info

Wires, node corners and the grid change how a graph looks, never what it compiles to.

Themes

One JSON file per scheme, in themes/ at the repository root, naming every colour the scheme sets.

SchemeCreditLicence
Roswaal Lightneopolitans0BSD, with the repository
Roswaal Darkneopolitans0BSD, with the repository
Tokyo NightEnkia — MITMIT, in full under Settings → Licences
Tokyo Night StormEnkia — MITMIT, in full under Settings → Licences
Catppuccin MochaCatppuccin — MITMIT, in full under Settings → Licences
NordSven Greb — MITMIT, in full under Settings → Licences
Aquaticneopolitans0BSD, with the repository

Adding one

Copy the closest scheme, rename it after the slug of its new name, and edit. Every field is required — there is deliberately no inheritance, because a half-defined palette silently borrowing another one's colours is far harder to debug than a missing-key error.

json
{
  "name": "My Theme",
  "order": 7,
  "dark": true,
  "credit": "You",
  "colors": {
    "app": "#16181d",
    "panel": "#1b1e24",
    "…": "…"
  },
  "code": {
    "keyword": "#c98fd0",
    "string": "#8fce9b",
    "…": "…"
  }
}

npm run build:themes compiles themes/ into the bundle and refuses to build a scheme that would not work. What it checks is worth knowing before you hit it:

  • Every role is present, and every colour is a full #rrggbb. No short form, no names, no alpha.
  • dark agrees with the actual brightness of app. It is not a description — every overlay is derived from it — so a scheme claiming true on a light ground would paint white onto white and make every hover state invisible.
  • A node is distinguishable from the canvas it sits on.
  • Body text clears 4.5:1 against both app and panel, and the quieter text roles clear their own lower bars.
  • Syntax colours are visible on the surface code is shown on. comment is held to a lower bar than the rest on purpose — every serious syntax theme mutes its comments, and that is the author's decision rather than a mistake to correct for them.

What a theme sets

RoleWhat it colours
appThe window behind everything
panelSidebars, toolbars, dialogs
canvasThe graph surface
inputText fields and dropdowns
textBody text
subTextLabels and secondary lines
dimTextDisabled and placeholder text
borderOrdinary dividers
borderStrongEmphasised edges
nodeBodyA node's fill
nodeBorderA node's outline
wireExecExecution wires
accentPrimary buttons, focus, the active toggle
dangerErrors and destructive actions
warningWarnings
okSuccess, and a clean compile
selectThe selection outline on the canvas
pureA hint in the outline of a node with no side effects
capsuleInline chips and badges
capsuleBorderTheir outline
code.keywordlocal, if, function
code.stringString literals
code.numberNumber literals
code.commentComments
code.operatorOperators and punctuation
code.propertyFields after a dot
code.globalgame, workspace, script
code.functionCalled names
code.typeTypes in annotations: x: Model

What it does not

Node category colours and pin type colours are fixed. Red is a boolean, green is a number, gold is a vector — that mapping is most of what makes a Roswaal graph readable at a glance, and a scheme that moved it would be trading the one thing the colours are for against a matter of taste. They live in palette.ts and stay there.

Hover, the grid, the watermark and the node shadow are not authored either. They are overlays — a translucent white or black over whatever is underneath — and an overlay is the one kind of token an author gets wrong without seeing it, because the mistake is invisible on the surface they happened to be looking at. They are computed from dark instead, so a palette cannot ship a hover state that does not show.

Warning

A data wire takes its pin's colour, not a theme's. Themes have no data-wire role.

Last reviewed 12 September 2026 by @neopolitans