Getting Started =============== This guide walks through creating a dashboard from scratch and covers the key concepts of the Simucube Dash Lua scripting API. Dashboard Structure ------------------- A dashboard is a directory containing a JSON configuration file, Lua scripts, and optional assets (fonts, images). :: my_dash/ ├── dash.json # configuration file ├── script/ │ └── main.lua # main Lua script (entry point) ├── fonts/ │ └── MyFont.ttf # font files └── images/ └── background.png # image files JSON Configuration ------------------ The JSON file declares fonts, images, and scripts used by the dashboard. All paths are relative to the dashboard directory. .. code-block:: json { "version": "1.0.0", "name": "My Dashboard", "author": "Your Name", "preview_image": "images/preview.png", "fonts": { "main_font": { "path": "fonts/MyFont.ttf", "size": 24, "additional_chars": "0123456789:. " }, "large_font": { "path": "fonts/MyFont.ttf", "size": 48 } }, "scripts": { "main": "script/main.lua" }, "images": { "background": "images/background.png" } } ``fonts``: Each entry defines a font with a name (used as ``dash.font.`` in Lua), a path to the font file, and a pixel size. The optional ``additional_chars`` field lists characters to pre-render -- useful for optimizing memory on embedded displays when only certain characters are needed. ``scripts``: The ``"main"`` script is the entry point. Additional scripts (e.g. ``"widgets"``) are loaded before main and can be accessed via ``require()``. The following names are reserved and cannot be used as script names: ``dash``, ``manufacturer``, ``sc``, ``simucube``. ``images``: Each entry can be a path string or an object with ``"path"`` and optional ``"format"`` (e.g. ``"alpha_only"`` for mask images). Loading the Dash Module ----------------------- Scripts must load the ``dash`` module with ``require`` before using it. Usually this is the first thing a dash script does: .. code-block:: lua local dash = require("dash") Every script file that uses the ``dash`` API needs its own ``require`` call -- this includes widget modules and other helper scripts, not just the main entry point. Minimal Example --------------- A complete minimal dashboard: .. code-block:: lua -- main.lua local dash = require("dash") local page = dash.Page() page:set_background_color(0xFF000000) -- black background local label = dash.Label(page, { x = 10, y = 10, text = "Hello!", font = dash.font.main_font, text_color = 0xFFFFFFFF }) while true do dash.update() end Main Loop --------- Every dashboard script must have a main loop that calls ``dash.update()``. This function processes input events, runs telemetry update hooks, advances timers, and renders the current frame. .. code-block:: lua while true do -- your per-frame logic here dash.update() end Node Types ---------- All visual elements are **nodes** in a parent-child tree. The root of each tree is a **Page**. Available node types: - **Page** -- root container, one per screen layout - **Box** -- filled rectangle with optional border and rounded corners - **Label** -- text display with auto-sizing or fixed-rect modes - **Image** -- displays an image resource with automatic mosaic repeat for oversized nodes - **Line** -- line segment between two points - **Circle** -- circle with optional fill and border - **Triangle** -- triangle with three vertices - **Graph** -- scrolling line chart - **Canvas** -- free-form pixel drawing Nodes are created with factory functions on the ``dash`` module: .. code-block:: lua local page = dash.Page() local box = dash.Box(page, { x=10, y=10, width=100, height=50 }) local label = dash.Label(box, { text="Inside box", font=dash.font.main_font }) Each node's position is relative to its parent. Hiding a parent hides all its children. Colors ------ Colors use ARGB32 format where alpha is in the highest byte: ``0xAARRGGBB``. Full opacity is ``0xFF``. .. code-block:: lua 0xFFFF0000 -- opaque red 0xFF00FF00 -- opaque green 0x80FFFFFF -- 50% transparent white Color helper functions: .. code-block:: lua dash.rgb(255, 0, 0) -- opaque red dash.rgba(255, 0, 0, 128) -- 50% transparent red dash.color("#FF0000") -- opaque red from hex string Hex string formats: ``"#RGB"``, ``"#ARGB"``, ``"#RRGGBB"``, ``"#AARRGGBB"``. Telemetry --------- Telemetry objects provide live data from the connected racing simulator. Access them through ``dash.telemetry.``: .. code-block:: lua local rpm = dash.telemetry.engine_rpm local speed = dash.telemetry.speed if rpm:valid() then print(rpm:value()) end **Polling** -- read values in the main loop: .. code-block:: lua while true do label:set_text(string.format("%d RPM", dash.telemetry.engine_rpm:value())) dash.update() end **Update hooks** -- more efficient, only called when values change: .. code-block:: lua local rpm = dash.telemetry.engine_rpm label:set_telemetry_update_hook(30, function() label:set_text(string.format("%d RPM", rpm:value())) end, rpm) while true do dash.update() end The first argument to ``set_telemetry_update_hook`` is the maximum check rate in Hz. The callback fires only when a watched value actually changes. Custom Widgets with OOP Inheritance ------------------------------------ Use ``extend()`` to create reusable widget classes: .. code-block:: lua -- Define a reusable telemetry display widget local TelemetryLabel = dash.Label:extend({ font = dash.font.main_font, text_color = 0xFFFFFFFF }) function TelemetryLabel:init(parent, props) self._telemetry = props.telemetry self._format = props.format or "%d" self:set_telemetry_update_hook( props.update_rate or 30, self.update, props.telemetry ) self:update() end function TelemetryLabel:update() self:set_text(string.format(self._format, self._telemetry:value())) end -- Create instances local rpm = TelemetryLabel(page, { x = 10, y = 10, telemetry = dash.telemetry.engine_rpm, format = "%d RPM" }) local speed = TelemetryLabel(page, { x = 10, y = 40, telemetry = dash.telemetry.speed, format = "%.0f km/h" }) The ``defaults`` table in ``extend()`` provides default creation parameters. Child defaults override parent defaults. The ``init`` method is called automatically after the node is created. Multi-level inheritance is supported: .. code-block:: lua local WarningLabel = TelemetryLabel:extend({ text_color = 0xFFFF0000 -- red text }) Layout Helpers -------------- Two helpers simplify positioning nodes: **align_in_parent** -- position a node within its parent using a 9-point grid: .. code-block:: lua label:align_in_parent("center") label:align_in_parent("bottom_right", -10, -10) **anchor_to** -- position a node relative to a sibling: .. code-block:: lua -- Place label2 below label1 with 5px gap label2:anchor_to(label1, "bottom_left", "top_left", 0, 5) Multiple Pages -------------- Dashboards can have multiple pages. The first page created is shown initially: .. code-block:: lua local dash = require("dash") local page1 = dash.Page() local page2 = dash.Page() dash.Label(page1, { text="Page 1", font=dash.font.main_font }) dash.Label(page2, { text="Page 2", font=dash.font.main_font }) while true do -- Switch pages with a button press if dash.wheel.get_digital_input(1) then local current = dash.get_current_page_index() dash.change_page(current == 1 and 2 or 1) end dash.update() end Unit Conversion --------------- Display values in the user's preferred units: .. code-block:: lua local speed_ms = dash.telemetry.speed:value() local speed = dash.unit.convert_to_user_speed(speed_ms) local unit_str = dash.unit.get_user_speed_unit() label:set_text(string.format("%.0f %s", speed, unit_str)) Input units are always SI: m/s for speed, meters for distance, celsius for temperature, litres for volume, kPa for pressure. Modular Scripts --------------- Organize larger dashboards into multiple script files. All scripts listed in the JSON ``"scripts"`` section are loaded before the main script runs. Use ``require()`` to access them: .. code-block:: json { "scripts": { "main": "script/main.lua", "widgets": "script/widgets.lua", "style": "script/style.lua" } } .. code-block:: lua -- style.lua local style = {} style.COLOR_BG = 0xFF1A1A1A style.COLOR_TEXT = 0xFFFFFFFF style.COLOR_ACCENT = 0xFF00AAFF return style .. code-block:: lua -- main.lua local dash = require("dash") local style = require("style") local page = dash.Page() page:set_background_color(style.COLOR_BG) Editor Support -------------- The ``.lua`` files in this documentation directory are LuaLS-annotated definition stubs. Configure your editor to use them as a workspace library for autocompletion, type checking, and hover documentation. See the ``readme.md`` file in this directory for setup instructions for VS Code (EmmyLua and LuaLS extensions) and other editors.