Skip to main content

Scripts

Behaviour is written in Kalem, Caria's language, in .kalem files of the project. A script is attached as a component to a package, a part or the world.

Writing​

New › Sakin › Kalem Script makes a script from its label: "Door bell" becomes door-bell.kalem, script DoorBell. The editor carries Kalem's language server and starts one per project; it works on unsaved text and never compiles (compiling happens when Play starts).

  • Errors as you type, on their line: syntax, types and effects. The messages are in Turkish today ("if bloğu kapanmadı: end eksik": the if block is not closed, end is missing).
  • Colours by meaning: a property (read-only in code, set in the Inspector), memory, a contract field, a state, timer or event, a function, the library, a parameter and a local each have their own colour, mapped onto the colour scheme's known keys.
  • Completion: host types after extends, triggers and events after on, payload fields in on event(, types after :, states after goto, timers after timer, a field's parts after field., the functions that take a value's type after its dot (and r g b a on a colour), the words that start a declaration or a statement, the locals in view, the script's names and the natives open to its side. Code inside {…} in a string is coloured and completed as code.
  • On hover: a declaration's line and its /// description, a local's type, a native's signature and effect, a host type's and an event's description from the catalog.
  • Navigation: go to definition (a started timer goes to its first start timer), highlight and find usages, the Structure view, folding.

The catalog the server checks against is the editor's host types and calendar (kalem/hosts.json) and the project's events; when an event document is added, changed or removed, open scripts are checked again.

Components​

A component is kept in the components list of a package's or part's object.json, or of the .world: {id, script: "kalem/<file name>", enabled, values}. values keeps only the properties that differ from the script's defaults; a property renamed with was finds its value under the old name.

In the Inspector and the world's form, every component is a card:

  • its enabled box, the script's label, ↑ ↓ (the order is the order they run in) and remove;
  • below, the script's name (a click opens the .kalem), its host type and category; its error count when it has errors;
  • the script's properties by group, with their /// descriptions (made from the script's manifest; hidden ones do not show, an int stays a whole number);
  • at the bottom, what the script reacts to ("On ready · timer opening · city.powerChanged") and the signal it is bound to.

The card compares the fields the script reads and writes with the holder's (Fields): a missing field, another type (bool ↔ Yes / No, int ↔ whole number, float ↔ number, string, time), or a field another component writes too is written in red, and Add the fields it uses adds what is missing in one command. When the language server did not answer for a script, its card has Try again. Cards follow a script shortly after it changes, is added or is removed.

Add Component​

Add Component offers, in the selector, the project's scripts that can go on the selection, by their host type: World on the world, Building on a building, Character on a character, Part on a part or an object, VisualEffect and Light on a part (Host types).

  • Categories are the scripts' category; the search looks in the name, description, file path, host type, properties and events.
  • The details show the file path (copyable), where it runs, its properties, the events it reacts to, the fields it reads and writes, and its errors.
  • A script that cannot be added still shows, with why: one already on the selection is "Added"; one without a header, or that could not be read, is under "Not ready"; two scripts with the same file name (the id is the file name) both are.

Signals​

A client script with an input has a Signal row on its card: Choose… offers the fields of the right type (the package's, its parts' and the project's first world's, and "Not bound"), and the choice is written on the component as input: {holder, field} (the holder is a part's id, package or world). An unbound input keeps its default; a field that is gone or has another type is written in red (Visual effects).