Skip to content
Back to skills

Csp Lua

ASecurity

CSP (Custom Shaders Patch) Lua API reference for Assetto Corsa modding. Use when working with ac.*, ui.*, render.*, physics.* APIs or any CSP Lua code.

  • 666 stars
  • 0 votes
  • 2 copies
  • 3 views
  • Added February 8, 2026
documentationshellapidocumentation

Works with

  • api

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill csp-lua --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Csp Lua?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Csp Lua
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-csp-lua/badge)](https://www.skillsdirectory.com/skills/majiayu000-csp-lua)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: csp-lua
description: CSP (Custom Shaders Patch) Lua API reference for Assetto Corsa modding. Use when working with ac.*, ui.*, render.*, physics.* APIs or any CSP Lua code.
---

# CSP Lua API Reference Skill

Use this skill when working with CSP (Custom Shaders Patch) Lua code for Assetto Corsa.

## Development Rules

**NEVER use shell commands or external tools** (`io.popen`, `os.execute`, etc.) to solve problems. CSP provides comprehensive APIs for most tasks.

Before implementing any functionality:
1. **Check `reference/lib.lua`** in this skill folder for existing CSP APIs
2. Use CSP's built-in functions (e.g., `io.scanDir` instead of `dir` command)
3. Only fall back to shell if absolutely no CSP API exists

## Key File System APIs

From `reference/lib.lua`:
- `io.scanDir(directory, "*.csv")` - List files matching a pattern
- `io.dirExists(path)` - Check if directory exists
- `io.fileExists(path)` - Check if file exists
- `io.fileSize(path)` - Get file size in bytes (-1 on error)
- `io.getAttributes(path)` - Get file attributes (fileSize, creationTime, lastWriteTime, etc.)

## Track Information

### `ac.getTrackID()`
Returns the track identifier string (e.g., "ks_brands_hatch-gp", "daytona").

```lua
local trackId = ac.getTrackID()
-- Returns: "ks_brands_hatch-gp"
```

**Note:** `ac.getSim().trackId` does NOT exist. Use `ac.getTrackID()` instead.

### `ac.getTrackDataFilename(filename)`
Returns the full path to a file in the track's data folder.

```lua
local path = ac.getTrackDataFilename('traffic.json')
```

### `ac.getSim()`
Returns `ac.StateSim` reference with information about the simulation state.

Key fields:
- `sim.dt` - Delta time in seconds (0 when paused, affected by replay speed)
- `sim.isPaused` - Simulation is paused
- `sim.isOnlineRace` - True if in an online session
- `sim.trackLengthM` - Track length in meters
- `sim.time` - Total time in milliseconds since AC started
- `sim.gameTime` - Total time in seconds since AC started
- `sim.sessionTimeLeft` - Remaining session time in ms
- `sim.currentSessionIndex` - 0-based session index
- `sim.rainIntensity` - Current rain intensity (0-1)
- `sim.roadGrip` - Current track grip (0-1)
- `sim.connectedCars` - Number of connected players (online)

### Spline & World Coordinates
- `ac.worldCoordinateToTrackProgress(vec3)` - Converts world position to spline position (0-1)
- `ac.trackProgressToWorldCoordinate(pos, linear)` - Converts spline position to world position
- `ac.getTrackSectorName(pos)` - Returns the name of the sector at given spline position

## Car Information

### `ac.getCar(index)`
Returns `ac.StateCar` for the specified car index (0 = player).

Key fields:
- `car.id` - Car identifier string
- `car.speedKmh` - Speed in km/h
- `car.splinePosition` - Position on track (0-1)
- `car.lapCount` - Number of completed laps
- `car.lapTimeMs` - Current lap time in milliseconds
- `car.bestLapTimeMs` - Best lap time in this session (ms)
- `car.gas` - Throttle (0-1)
- `car.brake` - Brake (0-1)
- `car.clutch` - Clutch (0-1, 1 = fully depressed)
- `car.steer` - Steering angle in degrees
- `car.gear` - Current gear (0 = N, -1 = R)
- `car.handbrake` - Handbrake (0-1)
- `car.isLapValid` - True if current lap is considered valid by AC
- `car.resetCounter` - Increments each time car is reset (teleported)
- `car.lastLapCutsCount` - Number of cuts in the last lap
- `car.collisionDepth` - Depth of current collision in meters
- `car.isInPitlane` - True if in pitlane area
- `car.racePosition` - Current position in session/race

### Car Events
- `ac.onTrackPointCrossed(carIndex, progress, callback)` - Triggered when car crosses a specific spline point
- `ac.onCarCollision(carIndex, callback)` - Triggered on collision
- `ac.onCarJumped(carIndex, callback)` - Triggered when car jumps

## Hotkeys

### `ac.ControlButton(name, defaults)`
Creates a bindable hotkey control.

```lua
local myButton = ac.ControlButton('ac-tracer/MyHotkey', {
    keyboard = { key = ui.KeyIndex.T, ctrl = true },
    gamepad = ac.GamepadButton.Y
})

-- Check if pressed this frame
if myButton:pressed() then ... end

-- Check if currently held
if myButton:down() then ... end

-- Render binding control in settings (UI function)
myButton:control(vec2(120, 0))
```

## Storage

### `ac.storage(layout, prefix)` - PREFERRED
Advanced persistent storage with default values and automatic synchronization. **This is the recommended approach.**

```lua
-- Define layout with defaults (at module level)
local config = ac.storage{
    showTraces = true,
    autoHide = false,
    hideSpeed = 20,
    colorOwn = rgb(0.2, 0.2, 0.2)
}

-- Access/Modify (automatically persists on assignment)
if ui.checkbox('Show traces', config.showTraces) then
    config.showTraces = not config.showTraces  -- Auto-saved!
end

config.hideSpeed = ui.slider('##speed', config.hideSpeed, 0, 100, 'Speed: %.0f')
```

Values can be: strings, numbers, booleans, vectors (vec2/vec3/vec4), colors (rgb/rgbm).

**Note:** Direct access `ac.storage[key] = value` only supports strings and requires manual serialization. Avoid this pattern - use the table-based approach instead.

### SDK Examples
See working examples in other CSP apps:
- `apps/lua/Radar/Radar.lua` - Simple config with checkboxes, sliders, colors
- `apps/lua/CSPDataLogger/CSPDataLogger.lua` - Basic boolean/number settings

## Logging & UI

### `ac.log(message)`
Writes to CSP log.

### `ac.setMessage(title, description)`
Shows a toast-style message in the game UI.

### `ac.lapTimeToString(ms, allowHours)`
Utility to format milliseconds into "M:SS.ms" format.

## UI & Windows

### Window Types

Prefer these wrappers over `ui.beginWindow` / `ui.endWindow` as they handle crashes gracefully and provide standard styling.

#### `ui.toolWindow(id, pos, size, noPadding, inputs, content)`
Standard app window with background. Best for main app windows.

```lua
function script.windowMain(dt)
    ui.toolWindow('MyAppMain', vec2(100, 100), vec2(400, 300), false, true, function()
        -- Window content here
        ui.text("Hello World")
    end)
end
```

#### `ui.transparentWindow(id, pos, size, noPadding, inputs, content)`
Window with no background. Best for HUD overlays or non-intrusive elements.

```lua
function script.windowHUD(dt)
    -- Transparent, pass-through inputs unless interactive
    ui.transparentWindow('MyAppHUD', vec2(0, 0), ui.windowSize(), true, false, function()
        ui.textColored("HUD Overlay", rgbm.colors.red)
    end)
end
```

### Layout Best Practices

#### Scrollable Areas (`ui.beginChild`)
Use child windows for scrollable content lists.

```lua
-- Reserve 30px at bottom for footer
ui.beginChild('ScrollableList', vec2(0, -30), false, ui.WindowFlags.None)
    for i = 1, 100 do
        ui.text("Item " .. i)
    end
ui.endChild()

-- Footer (pinned to bottom due to child height reservation)
ui.button("Close", vec2(-1, 0)) -- -1 width = full width
```

#### Grouping & Layout
- `ui.beginGroup()` / `ui.endGroup()`: Group items to treat them as one for hover checks or same-line layout.
- `ui.sameLine(offset, spacing)`: Place next item on the same horizontal line.
- `vec2(-1, 0)`: Use as size to fill remaining horizontal space.

#### Styling
Use `ui.pushFont`, `ui.pushStyleVar`, and `ui.pushStyleColor` to customize look, but ALWAYS pair with `ui.pop...`.

```lua
ui.pushFont(ui.Font.Title)
ui.text("Title")
ui.popFont()

ui.pushStyleVar(ui.StyleVar.Alpha, 0.5)
ui.button("Dimmed Button")
ui.popStyleVar()
```

## Settings Integration

### `ui.addSettings(params, callback)`
Registers a settings window accessible via the taskbar context menu or settings apps.

```lua
ui.addSettings({
    name = "My App Settings",
    id = "MyAppSettings",
    icon = ui.Icons.Settings,
    size = {
        default = vec2(400, 300),
        min = vec2(300, 200)
    }
}, function()
    ui.header("General Options")

    if ui.checkbox("Enable Feature", state.enabled) then
        state.enabled = not state.enabled
    end

    ui.separator()

    ui.header("Visuals")

    local newVal, changed = ui.slider("Opacity", state.opacity, 0, 1, "%.2f")
    if changed then state.opacity = newVal end

    ui.combo("Mode", state.mode, ui.ComboFlags.None, function()
        if ui.selectable("Mode A", state.mode == "A") then state.mode = "A" end
        if ui.selectable("Mode B", state.mode == "B") then state.mode = "B" end
    end)

    ui.text("Toggle Key:")
    ui.sameLine()
    myBindableHotkey:control(vec2(-1, 0))
end)
```

### Window Visibility & Management

Use `ac.getAppWindows()` to list all windows and check their status, and `ac.accessAppWindow()` to modify them.

#### `ac.getAppWindows()`
Returns an array of descriptors for all available windows.

```lua
local windows = ac.getAppWindows()
for _, w in ipairs(windows) do
    ac.log(string.format("Window: %s, Visible: %s", w.name, tostring(w.visible)))
end
```

#### `ac.accessAppWindow(windowName)`
Returns an `ac.AppWindowAccessor` for the specified window name.

```lua
local window = ac.accessAppWindow("ac-tracer/corners")
if window and window:valid() then
    window:setVisible(true)
end
```

#### `ac.setAppWindowVisible(appID, windowFilter, visible)`
Toggle windows that might be hidden or not yet initialized.

```lua
ac.setAppWindowVisible("ac-tracer", "telemetry", true)
```

## Full API Reference

For the complete API reference with all types, enums, and functions, read the file `reference/lib.lua` in this skill folder (17,000+ lines of type definitions and documentation).

## Scripts

### `scripts/logs.ps1`
View CSP logs filtered for ac-tracer entries.

```powershell
# Default: last 20 entries
.\.claude\skills\scripts\logs.ps1

# Last 50 entries
.\.claude\skills\scripts\logs.ps1 -l 50

# Only errors
.\.claude\skills\scripts\logs.ps1 -only ERROR

# Only warnings
.\.claude\skills\scripts\logs.ps1 -only WARN
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.