RLS Studios
ProjectsPatreonCommunityDocsAbout
Join Patreon
BeamNG Modding Docs

Guides

Reference

Server CommandsGE UtilitiesGame Engine MainNavigation GraphScreenshot CaptureServerServer ConnectionSpawnpoint ManagerSimulation TimeVehicle SpawningSuspension Frequency Tester
Gameplay AchievementGameplay CityDiscoverForce FieldGarage ModeMarker InteractionParking SystemGameplay Playmode MarkersGameplay PoliceGameplay RallyGameplay Rally LoopGameplay Raw POIsGameplay Skidpad TestSpeed Trap LeaderboardsSpeed Traps and CamerasGameplay StatisticsTaxi Ride SystemTraffic SystemVehicle PerformanceWalking
Rally Audio ManagerRally Camera Path PlayerRally ClientRally Cut CaptureRally EnumsRally Extension HelperRally GeometryRally ManagerRecce ManagerRecce AppRecce SettingsRally Settings ManagerSnap-to-RoadTraffic Exclusion ZonesRally UtilityRally Vehicle CaptureRally Vehicle Tracker
Rally CodriverRally Mission SettingsRally PacenotePacenote GeneratorPacenote WaypointNotebook PathStructured Pacenote DataSystem PacenotesWaypoint Types

UI

Resources

BeamNG Game Engine Lua Cheat SheetGE Developer RecipesMCP Server Setup

// RLS.STUDIOS=true

Premium Mods for BeamNG.drive. Career systems, custom vehicles, and immersive gameplay experiences.

Index

HomeProjectsPatreon

Socials

DiscordPatreon (RLS)Patreon (Vehicles)

© 2026 RLS Studios. All rights reserved.

Modding since 2024

API ReferenceGE Extensionsgameplayrallynotebook

Pacenote Generator

Simplified corner detection system that generates pacenotes from driveline points. Analyzes road geometry using circle-fitting to identify direction changes, then groups consecutive nodes into corners

Simplified corner detection system that generates pacenotes from driveline points. Analyzes road geometry using circle-fitting to identify direction changes, then groups consecutive nodes into corners with simplification passes.


Public API

FunctionSignatureReturnsDescription
M.detectCorners(pointList, params?)tableDetects corners from driveline points; returns corner descriptors

Default Parameters

M.defaultParams = {
  lookAheadContext = 7,          -- Nodes to look ahead/behind for direction
  straightThreshold = 5.0,       -- Degrees below which is "straight"
  mergeDistanceThreshold = 0.2,  -- Meters threshold for merging straights
  maxSimplifyIterations = 10     -- Max simplification passes
}

Internals

Key Local Functions

FunctionDescription
circleCenterAndAngle(p1, p2, p3)Fits circle through 3 points; returns center and arc angle
computeNodeData(route, params)Annotates nodes with direction, angle, radius, center
computeCornerData(corner)Aggregates length and angle from corner's nodes
splitRouteIntoCorners(route)Splits at direction changes into corner segments
simplifyConsecutive(corners)Merges consecutive corners with same direction
simplifyStraightsExtendNext(corners, threshold)Extends straights by absorbing inline next nodes
simplifyCorners(corners, params)Iterative simplification loop

Corner Detection Pipeline

  1. Convert: Input points → route array with pos and id
  2. Annotate: For each node, look ±context nodes, fit circle, compute:
    • direction: "" (straight), " right", or " left" (via cross product sign)
    • angle: arc angle (0 if below straightThreshold)
    • radius: distance from point to fitted circle center
  3. Split: Create new corner segment whenever direction changes
  4. Simplify: Iteratively merge straights that extend along a line + consecutive same-direction corners

Output Format

{
  {
    pos = vec3,        -- first node position (corner start)
    posEnd = vec3,     -- last node position (corner end)
    direction = string, -- "" | " right" | " left"
    angle = number,    -- total arc angle in degrees
    length = number,   -- total corner length in meters
    nodes = table      -- array of annotated route nodes
  },
  ...
}

Direction Detection

Uses 2D cross product (Z component) of consecutive segments:

local cross = (p3z - p2z):cross(p2z - p1z).z
-- cross > 0 → right, cross < 0 → left

How It Works

  1. Caller provides array of driveline points (with .pos property or as vec3)
  2. Points are converted to route nodes and annotated with geometry data
  3. Route is split into corners at each direction change
  4. Simplification merges inline straights and consecutive same-direction corners
  5. Returns array of corner descriptors used by notebook to create pacenotes

Adapted from geometry.lua but simplified to focus only on corner detection without velocity/severity calculations.


Usage Example

local generator = require('gameplay/rally/notebook/pacenoteGenerator')

-- Detect corners from driveline points
local corners = generator.detectCorners(drivelinePoints)

-- With custom parameters
local corners = generator.detectCorners(drivelinePoints, {
  lookAheadContext = 5,
  straightThreshold = 3.0,
  mergeDistanceThreshold = 0.5,
  maxSimplifyIterations = 15
})

-- Use results to generate pacenotes
for _, corner in ipairs(corners) do
  if corner.direction ~= "" then
    -- Create pacenote for this corner
  end
end

See Also

  • Rally Codriver - Related reference
  • Rally Mission Settings - Related reference
  • Rally Pacenote - Related reference
  • Gameplay Systems Guide - Guide

Rally Pacenote

Core class representing a single pacenote in a rally notebook. Manages note text (freeform + structured), waypoints (corner start/end), audio compilation, validation, debug drawing, trigger types, and

Pacenote Waypoint

Class representing a waypoint within a pacenote. Each pacenote has typically two waypoints: a Corner Start (CS) and Corner End (CE). Waypoints define 3D positions with normals for intersection planes

On this page

Public APIDefault ParametersInternalsKey Local FunctionsCorner Detection PipelineOutput FormatDirection DetectionHow It WorksUsage ExampleSee Also