Other truck drivers
CBGenerated from the lorries actually around you. Nationality follows where you are driving: in Slovenia mostly Slovenians, then Austrians and Croatians, then the Polish and Lithuanian plates that run half the continent.
Roadfolks gives the traffic in Euro Truck Simulator 2 drivers who talk. It reads the vehicles around you out of shared memory, keeps each one as a tracked person with a nationality, a personality and a memory of you, and lets them speak over the CB, the phone, the radio or the passenger seat.
| Runs on | Windows, alongside Euro Truck Simulator 2 |
|---|---|
| Needs | ETS2LA with its game plugin, the SCS telemetry plugin, Python 3.11 or later |
| Dialogue by | A language model, through a chain of five providers |
| Voice by | Wingman AI: microphone, speech recognition, text to speech |
| Player languages | English, Slovenian, Croatian |
| Licence | MIT |
Nine kinds of speaker, on five channels. Every one of them is a person the simulation decided exists, not a line picked from a list.
Generated from the lorries actually around you. Nationality follows where you are driving: in Slovenia mostly Slovenians, then Austrians and Croatians, then the Polish and Lithuanian plates that run half the continent.
66 people written by hand, each with a route, a lorry, a reason to be on that road and a story that moves one beat per conversation. About one truck in six can be one, if their corridor covers the country you are in.
One burst out of a window and gone. They are never stored: a motorist who shouts once is not worth a database row.
30 invented stations that change when you cross a border, each in the local language. Traffic bulletins are built only from incidents the simulation actually saw.
Three speeding events inside fifteen minutes earns a stop, and the officer tells you which one. Speaks the language of the country you are in.
Stop within 6 km of a crossing and somebody asks for your documents.
Called out when the truck is damaged enough to need them.
They have a real destination on the map and they get out when you reach it. You can refuse the lift.
Knows the cargo, the deadline and the damage report before you say a word. When a written dispatcher fits your company, you get that person permanently.
| Channel | What it is | Used by |
|---|---|---|
| CB | Truck-to-truck radio. Short, clipped, and you cannot see who is speaking. | Other truckers, written characters |
| Horn | A car driver cannot call you, so they shout out of the window alongside. | Motorists |
| Phone | A call into the cab. You can answer it. | Your dispatcher |
| Cabin | Somebody in the passenger seat. | Hitchhikers |
| Radio | A broadcast. You listen; you cannot reply. | Radio presenters |
You press the push-to-talk key and speak. Wingman AI turns that into text and hands it to Roadfolks, which gives it to whoever is currently in range on that channel. You can also start a conversation rather than wait for one.
A car driver shouting through a window cannot hear an answer, and a radio broadcast is one-way. Everything else can be answered.
Ej, pazi malo! Vidiš da sam tu?
Sorry mate, didn't see you.
Is okay. You go Koper too? Big queue today.
Marko opens in Croatian because his English is 0.42 and the simulation knows it. He switches when you answer in English, and the reply is short and missing an article because that is what a 0.42 speaker sounds like. A Croatian voice reads it, so the accent is in the audio rather than spelled out in the text.
What is built and covered by tests today.
Eight of the written characters, in the browser. Dialogue only: no game, no voice, and nothing is remembered between visits.
The replies come from a model on Cloudflare Workers AI, using the same character sheets the mod uses. The demo is rate limited to six messages a minute per visitor and a fixed number a day for everybody together, so the free allowance survives.
Runs containers between Koper and Munich. Twenty-two years on the road. Loathes the Karawanken queue and says so every time.
Checking whether the demo is on.
Bojan answers in Slovenian and Marko in Croatian if you write to them in those languages.
The simulation decides the facts. The model only writes the words.
A model asked to invent an interesting trucker produces a different disposable person every time. Roadfolks never asks it to invent anything. It hands over a driver who already exists, an event that already happened and a grudge from last Tuesday, and asks for one line:
vehicle 1834, 12 m behind, followed you 4 min,
passed aggressively on the left, driver Marko,
Croatian, impatient, English 0.45, met once
before near Maribor | ETS2LA plugin | Traffic, parked vehicles and traffic lights, from three shared-memory blocks. |
|---|---|
| SCS telemetry plugin | Your position, job, cargo and the in-game clock. |
| Tracker | Keeps one vehicle as one track across the dropouts. |
| Event detector | 24 event types from geometry. No randomness, no model calls. |
| World engine | Who exists, what they remember, and whether anybody speaks at all. |
| Model router | One line, from the first of five providers that answers. |
| Wingman AI | Microphone, speech recognition, voice and playback. |
Two modules know the binary shared-memory layouts, and nothing else does. They are transcribed from ETS2LA's own C# readers: bare arrays of fixed records, with no header, no magic number and no write counter. The record arithmetic is a test. A wrong layout produces plausible-looking floats rather than an exception, so every vehicle is checked against NaNs and physical limits before it reaches the simulation.
When ETS2LA changes the layout, the fix is a new entry in the layout
table and a config change. roadfolks diagnose scores every
known layout against the real buffer, and
roadfolks diagnose --search finds the vehicle array with no
layout knowledge at all, by looking for a repeating record that holds a
position, a bounding box and a speed, then confirming the positions move
between two samples a second apart.
Story beats, relationships and memories are rows in SQLite, not context in a prompt. A restart does not lose them, and a player who talks constantly cannot rush somebody through a whole story in one afternoon.
Both game plugins are required. Neither one alone is enough.
| Component | Needed | Why |
|---|---|---|
| Euro Truck Simulator 2 | Required | American Truck Simulator is planned but the name pools and places are Europe-only today. |
| ETS2LA, with its game plugin | Required | Writes the three traffic blocks. No block holds your own position. |
| SCS telemetry plugin | Required | The only source of your own position. Without it the engine refuses to start. |
| Python 3.11 or later | Required | Windows. 3.11, 3.12 and 3.13 are tested in CI. |
| One model API key | Required for dialogue | Cloudflare Workers AI is the default. Without a key the lines are canned. |
| Wingman AI | Required for voice | Without it, Roadfolks still runs and the lines arrive over HTTP as text. |
The ETS2LA blocks contain traffic, parked vehicles and traffic lights. None of them contains your own position, which is why the SCS telemetry plugin is not optional. Without it the engine would have to measure every distance from the map origin, so it refuses to start instead.
About fifteen minutes on a Windows game PC.
Put the ETS2LA game plugin and the SCS telemetry plugin in
bin\win_x64\plugins inside the Euro Truck Simulator 2
folder. Create the folder if it is not there. Start the game once and
leave it running in a job.
git clone https://github.com/DavidKolsek/roadfolks-ets2 roadfolks
cd roadfolks
py -m venv .venv
.venv\Scripts\activate
pip install -e .
Use pip install -e ".[dev]" instead if you intend to run
the test suite.
setx CLOUDFLARE_ACCOUNT_ID "your-account-id"
setx CLOUDFLARE_API_TOKEN "your-token" setx keeps the variable after a restart, but it does not
affect the terminal you typed it in. Open a new terminal before the next
step. Other providers are in
docs/PROVIDERS.md.
roadfolks doctor
One line per part: Python, the content library, the config, the
database, the API keys, all four shared-memory blocks and the voice
skill. Every part that is not ready prints one instruction.
NOT READY stops the mod; MISSING costs a
feature. The game has to be running or the three game items fail.
roadfolks serve The world engine listens on port 8731 over HTTP and WebSocket.
Copy wingman-skill\roadfolks into the Wingman AI
skills folder and turn the skill on. Wingman owns the
microphone, speech recognition, the voices and playback; Roadfolks does
not reimplement any of that.
roadfolks demo Runs a whole encounter, with real dialogue, and prints each line beside the facts that produced it. Without an API key the lines are canned, which still proves the pipeline. The full first run on a game PC, with a check after every step, is in docs/GAME_PC.md.
About half a cent per hour of play, and usually nothing.
Each line is a small request: under 2,500 tokens in and usually under 80 out. Speech recognition runs on your own PC through Wingman. The voices use Edge TTS, which is free.
| Provider | Default model | Role |
|---|---|---|
| Cloudflare Workers AI | @cf/zhipu/glm-4.7-flash | Primary. Free allowance. |
| Groq | openai/gpt-oss-20b | Low latency. |
| Google Gemini | gemini-3.1-flash-lite | Free tier. |
| OpenRouter | openrouter/free | Zero cost. |
| OpenAI | gpt-5-nano | Paid fallback. |
The five are tried in order. A provider that hits its quota sits out for as long as it asks, or for a cooldown that doubles each time up to an hour. A refused key sits out for six hours and the log names the environment variable to fix. One success clears the record.
If every provider is out, the driver says something short and fixed rather than nothing. Silence caused by a fault would look exactly like silence by design, and nobody can debug that from inside the game.
roadfolks selftest before trusting
them, and roadfolks bakeoff to compare Slovenian and
Croatian output.
What is done, and what has not met the real game yet.
| Part | State | Note |
|---|---|---|
| Traffic tracking and event detection | Done | Tested offline against synthetic scenarios and recordings. |
| Characters, nationality, personality, memory | Done | |
| Silence budget and channel rules | Done | |
| Language policy and profanity levels | Done | |
| Content library | Done | 66 characters, 273 beats, 239 topics, 105 easter eggs, 109 places. |
| Radio, police, customs, hitchhikers, dispatcher | Done | |
| Provider fallback and quota handling | Done | No model ID has been called with a real key. |
| Shared-memory layouts | Done | Transcribed from ETS2LA's own C# readers, not guessed. |
| Shared memory against a running game | Not verified | Never run. First attempt is planned for 2026-09-20. |
| Event thresholds on real traffic | Not verified | Tuned on synthetic data only. |
| Heading calibration | Not verified | Decides whether “ahead” means ahead. Needs one drive. |
| Speech in and out through Wingman | Not verified | Never run against a live Wingman. |
| Live demo on Cloudflare | Not verified | Built and dry-run validated. Not deployed. |