Wiki under construction. Many concepts here are from alpha 0.2 and may still change. The wiki will be finalised for version 1.0 — for now it's here to help closed testers and, later, early-access players find their way around. For the most up-to-date and accurate info, join the Discord — that's where changes are announced first and where you can ask directly.

Join the Discord for the latest info

Mod Packs

What a content pack can change — teams, drivers, sponsors, suppliers, circuits, the calendar — how extend and replace differ, and the full structure of the pack file.

On this page

A content pack is one file: a SQLite database sitting in your mods folder (%APPDATA%\TheUndercut\mods\ on Windows — see where the files go). It carries the rows and the logo images, so a pack is a single thing to share, back up or publish.

mods/
  my_pack.db     ← the whole mod

You do not need to know SQL to make one — the Mod Editor shipped with the game writes exactly this file. If you do want to open the file yourself — for bulk edits, or to generate a pack from a script — the SQL reference documents every table and column. This page documents what the file means, which is what you need whether you use the editor, a script of your own, or read someone else’s pack.

The golden rule of the format: every table and every column is optional. A pack that only renames two teams is valid. Anything you leave out stays procedural, and a pack authored for an older version still loads in a newer game.

The current format is v2. A pack records which version it was written in, and the game says so on the pack’s row when it only half understands one — you are never left wondering why part of a pack did nothing. The Mod Editor upgrades an older pack the moment you open it.


What is inside a pack

my_pack.db meta name · modes · scenario teams the grid drivers sponsors suppliers team name circuits calendar circuit name images PNG blobs logo name

Everything inside a pack is linked by name — there are no hidden ids.

TableHolds
metaThe pack’s own settings: its name, the section modes, the scenario, the starting year
teamsThe grid — identity, colours, car, budget, and (imposed packs) infrastructure and palmarès
driversDriver profiles — abilities, ceilings, growth curves, traits, portrait, salary, seat
sponsorsBrands available on the sponsor market
suppliersEngine, tyre and fuel makers
circuitsTracks imported from .circuit files — see circuit modding
calendarThe season’s rounds, in order
imagesThe PNG files the rows point at: logos and custom car sprites

extend or replace

Each section carries a mode, stored in meta as <section>_mode:

extend your entries first, the game still generates the rest yours generated

replace only your entries — nothing is generated for that section

extend is the default, and it is the base game’s own pattern: a static core plus procedural filler. replace is what you want for a full real-world season.

What replace means exactly depends on the section — worth knowing before you wonder why a supplier survived:

Sectionreplace does
teamsTrims the grid to your list — the grid ends up exactly as long as your team table
driversThe driver pool is only yours; nobody else is generated for your series
sponsorsThe sponsor market is only yours
suppliersOnly the categories you cover are replaced. A pack with two engine makers and no tyre maker keeps the generated tyre makers, because a season cannot be run without one
circuitsApplies to the world circuit pool — the venues future calendars are drawn from. replace means the world never drifts back to generated tracks; the calendar you build always races the tracks you placed on it either way

One thing replace does not do

A pack’s drivers fill your series. The world also runs ten non-playable championships, each with a grid to fill, and the game tops the driver pool up so their seats are not empty — which is why a pack with a full grid of its own can still be surrounded by generated free agents.

meta.active_series is the answer: list the championships the world should run (PFS is the playable one) and every other series is switched off. Untick everything but your own and your pack’s drivers are the only people in the world. Say nothing and every series runs, as before.


Two ways a pack starts a career

meta.scenario decides what happens when the player picks your pack.

ScenarioWhat the player gets
New Series (default)The player creates a new team joining the grid and plays the pre-season. Your teams are rivals.
ImposedThe grid is fixed as you authored it — every team staffed, equipped and signed. The player takes over one of your teams and the season opens at race 1, with no pre-season.

An imposed pack unlocks fields that make no sense otherwise, and that is the only difference in the format: infrastructure levels, team and driver palmarès, founding year, and the “signed to” bindings that pre-fill each team’s drivers, sponsors and suppliers. Use replace on teams for an imposed grid so only your teams race.


meta — the pack’s settings

KeyValueDefault
nameShown in the pack pickerthe file name
authorFree text—
schema_versionWhich version of the pack format this file was written in (current: 2)1
min_game_versionGame build the pack needs. An older game says so on the pack’s row instead of loading it half-applied—
scenarionew_series · imposednew_series
start_yearCalendar year of season 1 — a pack can open in any era1990
teams_mode, drivers_mode, sponsors_mode, suppliers_mode, circuits_modeextend · replaceextend
active_seriesChampionships the world runs, comma-separated (PFS,PF2)absent = all of them
rulesSeries rule-set ids, comma-separated (points scale, the 107 % qualifying rule)the game’s defaults

teams

A row with no name is skipped. Teams are applied to the grid in order, so the first row is the first team.

ColumnMeaningLeave it out
idStable key. Every binding in the pack points at it, so a team can be renamed without losing its drivers, sponsors and suppliersthe display name is used instead
nameTeam name — what the game shows everywhererequired
countryCountry name or ISO codegenerated
budget_tiersmall · medium · large — the behaviour profile: AI cash reserves, infrastructure cap, prestige, R&D ambitionderived from the budget
budget_musdStarting cash, in millions0 = the tier’s own amount ($40M / $60M / $90M)
reputation0–1000 = generated
color1, color2, color3#RRGGBB — the three livery zonesleft empty = keep the generated livery
car_index0–11, which side-view car modelleft empty = keep the generated model (0 is a real model, so it cannot mean “unset”)
car_imageName of an images row: a custom side-view sprite replacing the modelbuilt-in model
liveryTop-down livery pattern worn in live races255 = the game picks
suitRace suit worn by the team’s drivers255 = per driver
logoAn images row name, or a number (one of the game’s shipped logos), or a path relative to mods/a procedural mark from the team name
infra_engineering … infra_academyThe nine department levels (academy caps at 3, the rest at 10). In an imposed grid these are the team’s base car strength0 = generated
career_wins, career_titles, best_championship, founding_yearAll-time record shown on the team profile at season 10 = default (founding year 1990)
historySeason-by-season rows, season:position:wins, joined by ;none

drivers

A row with neither first nor last name is skipped.

ColumnMeaningLeave it out
idStable key for this row—
first_name, last_name—one of them required
codeThree letters, unique across the pack — the game indexes drivers by code and silently renames a clashbuilt from the surname
countryCountry name or ISO codegenerated
age1–55. Under 16 is mod-only: a child prospect ages every season, stays hidden from Scouting until 14, and cannot be seated before the series allows (18 in the PFS)25
intelligence, pace, consistency, adaptability, stamina, aggressivityAbilities, 1–2010
pot_* (same six)Each stat’s ceiling. Never applied below the ability itself0 = generated
curve_* (same six)The stat’s growth shape with age — see below255 = that stat’s default shape
traitsThe game’s own trait format, kind:tier pairs — author it in the editorgenerated
fameStarting renown 0–100. A starting value: the game can still move it0 = worked out from the abilities
salaryAsking salary, per season500000
face_sheet, face_index, helmet_index, helmet_hue_0/1/2Portrait and helmet255 = generated
team_idSeat this driver at that team at season 1, by the team’s stable id — the binding the game resolves first—
teamSame, by the team’s display name. Used when there is no team_idfree agent
roleprimary · secondary · reserve — the seat is the car: primary drives car 1, secondary car 2primary
contract_yearsContract length in seasons0 = 2
career_starts, career_wins, career_podiums, career_titles, best_finishPalmarès shown from season 10 = none

Growth curves

Each ability develops with age on one of five shapes. The game always had them, one hardcoded per stat; a pack can assign any shape to any stat.

CurveImprovesDeclinesDefault for
Early peakfast to 26, slowly to 30, then neverfrom 30Pace
Physicalto 28, then neverfrom 28Stamina
Cerebralalways, slowing after 30 then 38neverIntelligence, Adaptability
Experienceto 30, half-speed to 34, then neverfrom 34Consistency
Youthonly to 24from 28Aggressivity

The curve is the shape, not the speed: how fast a stat closes the gap to its ceiling remains a property of the stat.


sponsors

ColumnMeaningLeave it out
nameBrand name — required—
sectorautomotive, technology, energy, finance, luxury, fashion, telecom, beverage, insurance, aviation, industry, retailgenerated
originCountry name or ISO codegenerated
budget1–10 — what the deal is worth5
prominence1–10 — how often the brand appears and how hard it is to land5
color#RRGGBB—
logoAn images row name, or a path relative to mods/a procedural logo
team_id / teamImposed grids: sign this brand to that team at season 1 — by stable id, or by nameopen market
idStable key for this row—

suppliers

A row whose category is not one of the three is skipped entirely — that is the one hard requirement in the table.

ColumnMeaningLeave it out
nameRequired—
categoryengine · tires · fuelrow skipped
origin, color, logoAs for sponsorsgenerated
budget, size1–105
power, reliability, endurance, potential, performance, heat, efficiencyTechnical stats 1–10 under their real names — only the ones its category has (see below)0 = generated
stat_a … stat_dThe same four values in generic slots, kept for older game builds. A named column wins over its generic slot0 = generated
money_per_gpDeal value in $/GP. Positive = partnership (they pay you), negative = client (you pay them)0 = generated
contractpartnership · client — wins over the sign of money_per_gp when both are setthe sign decides
durationContract length in seasons0 = generated
team_id / teamImposed grids: a list — Scarlet:partner; Azure:customer; Emerald — one supplier can back several teams, each at its own level. One partner per supplier; one supplier per category per teamopen market
idStable key for this row—
Categoryslot Aslot Bslot Cslot D
enginepowerreliabilityendurance (shown, not simulated)potential (shown, not simulated)
tiresperformanceendurancereliabilityheat
fuelefficiency———

Two things a pack deliberately cannot set:

  • Engine architecture (V8/V10/V12) is not stored on the supplier — the game looks the name up in its world manufacturer pool. A name that pool does not know falls back to V10.
  • Hidden tyre traits are seeded from the brand name and the season, so renaming a tyre maker rerolls them.

circuits and calendar

These two build a season. Circuits come from the Circuit Editor: the editor saves a .circuit file, and the Mod Editor imports it into the pack.

Each circuit carries an id, and a calendar round points at it with circuit_id (its name still works as a fallback).

circuits holds the track itself — its name, place, target length, visual preset, character, the drawn centre line, and the optional start/finish and pit markers. calendar holds the rounds, in order: each round is either a circuit round (naming one of your tracks) or an auto round (a generated track of a given character and length).

A pack carrying a calendar replaces the season with it. A pack carrying circuits but no calendar puts its tracks into the world pool and lets them take the season’s rounds.

Two fields are recorded for reference but not simulated: a circuit’s year, and its downforce / tire_wear / overtaking ratings — in play those three are derived from the track’s character.


images

name (the key rows point at) plus the PNG bytes. Logos are authored at 195×195; a custom car sprite is a side view facing right on a transparent background, 256 px tall. The game unpacks them to mods/.cache/ on first use.


What always stays generated

SectionA pack overridesThe game keeps generating
TeamsName, country, reputation, budget, behaviour profile, colours, car, livery, suit, logoBudget evolution, roster behaviour, and (outside imposed) infrastructure
DriversName, code, country, age, the six abilities and their ceilings, curves, traits, portrait, helmet, salary, fameAmbition, season objectives, hidden personality
SponsorsName, sector, colour, budget, prominence, origin, logoContract terms, market behaviour
SuppliersName, category, colour, budget, size, origin, logo, technical stats, deal termsMarket behaviour, hidden tyre traits

Traps worth knowing

  • Bindings follow the id, not the name. A driver, sponsor or supplier points at a team’s stable id, so renaming the team keeps them, and two teams may share a name (only the reading suffers — standings and news then show it twice). A pack written before ids existed, or hand-written with names only, still resolves by name and keeps the old behaviour: rename the team there and the driver joins the free-agent pool instead. Opening the pack in the Mod Editor once upgrades it.
  • Two drivers per team, one per seat. A team with two primary drivers leaves car 2 empty, and a car with no driver does not start. The editor’s Audit tab exists mostly for this.
  • Driver codes must be unique. A clash is renamed at load, silently, and everything keyed by code follows the rename.
  • The pack file must stay where it is. Logos and custom car sprites are read from it; a career started with a pack that later disappears loses them.
  • A pack applies at career creation only. Editing a pack never changes a career already under way — start a new one to see the change.