BeamNG.Earth
A 1:1 scale streamed Earth for BeamNG.drive: real elevation and satellite imagery, floating origin, LOD streaming from a companion server
Build and calculate points for custom Warhammer 40k and Horus Heresy armies with 19 factions and detailed unit data
AI summary · README
GamesTypeScript · JavaScriptGitHub @RigzarOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
An army list builder for a custom Warhammer 40,000 / Horus Heresy ruleset, covering 19 factions with full unit data, weapons, options, archetypes, legacies, traits and psychic disciplines.Read the full README ↗An army list builder for a custom Warhammer 40,000 / Horus Heresy ruleset, covering 19 factions with full unit data, weapons, options, archetypes, legacies, traits and psychic disciplines.
React · TypeScript · Vite · Zustand · Tailwind CSS
git clone https://github.com/Rigzar/custom40k-builder.git
cd custom40k-builder
npm install
npm run build # verify — must pass with zero TypeScript errors
npm run preview # serve the built app at http://localhost:4173
Do not use
npm run dev— always usenpm run buildto verify correctness andnpm run previewto test the built output.
custom40k-builder/
├── src/
│ ├── components/ # React UI components
│ │ ├── LandingPage.tsx # Faction selection + Developer Update announcement
│ │ ├── UnitCard.tsx # Individual unit card (options, armory, traits)
│ │ ├── ArmyConfig.tsx # Archetype / Legacy / Traits panel
│ │ ├── ArmoryModal.tsx # Armory item picker
│ │ └── PrintView.tsx # Printable army sheet
│ │
│ ├── engine/ # Game logic (points, validation, rules)
│ │ ├── points.ts # Points calculation — base cost + options + traits + armory
│ │ ├── resolver.ts # Unit profile resolution — marks, variants, archetypes, FACTION_RESOLVERS dispatch
│ │ ├── validators.ts # Army-wide validation — slot limits, archetype constraints, engagement limits
│ │ ├── keywords.ts # Keyword-derivation seam — armour/mark gating, Ordo/Legacy unlock helpers
│ │ ├── equipMods.ts # Parses stat/ability text out of an armory item's description
│ │ ├── transportGate.ts # "Low Move, no transport" selection-gate helper
│ │ ├── archetypes/ # Archetype rule registry — base.ts (ArchetypeRule shape) + index.ts (all archetypes) + per-faction subfolders
│ │ ├── codex_<faction>/ # Per-faction engine module (one per faction): keywords, legacies, traits, slots, special-abilities, weapon-abilities, resolver, digest.md
│ │ ├── legacies/ # Legacy-gated discipline/prayer rules (index.ts dispatcher + per-faction files)
│ │ ├── resolvers/ # FACTION_RESOLVERS implementations (injected abilities per faction)
│ │ ├── traits/ # Per-faction Army Trait effect tables
│ │ └── validators/ # Per-faction validation add-ons
│ │
│ ├── data/
│ │ ├── loaders.ts # Assembles FactionData from per-faction folder files
│ │ ├── changelog.ts # Version history (English)
│ │ ├── known-issues.ts # Bug and limitation tracker
│ │ └── rules-model/ # Per-faction keyword/rules digest (<faction>.md) — audit reference, not loaded by the app
│ │
│ ├── store/
│ │ └── army.ts # Zustand store — army state and actions
│ │
│ ├── types/
│ │ ├── data.ts # Unit, Weapon, OptionGroup, FactionData, OptionEffect…
│ │ ├── army.ts # RosterEntry, ArmyState, TraitSelection…
│ │ ├── unit-types.ts # Canonical UnitType union (Infantry, Bike, Jump Pack Infantry…)
│ │ └── keywords.ts # ChaosMark, ArmourKeyword, MARK_GLYPHS typed constants
│ │
│ └── i18n/
│ └── index.ts # UI translation strings (EN / DE / ES)
│
├── data/
│ ├── parsed/ # ← FACTION DATA — one folder per faction (all 19 factions)
│ │ ├── chaos_space_marines/
│ │ │ ├── units/ # one .ts file per unit, by slot
│ │ │ │ ├── hq/ troops/ elites/ ...
│ │ │ │ └── index.ts # assembles { faction, slot_to_units, units }
│ │ │ ├── armory/
│ │ │ │ ├── general.json # General armory
│ │ │ │ ├── mark_khorne.json
│ │ │ │ └── legion_*.json # One per legacy (Black Legion, Iron Warriors…)
│ │ │ ├── psychic/
│ │ │ │ ├── pacts.json
│ │ │ │ └── prayers.json
│ │ │ ├── archetypes.json # { archetypes[], legacies[], traits[] }
│ │ │ └── animosity.json # { animosity, allied } — only CSM/CD (marks)
│ │ ├── space_marines/ (same structure, no marks)
│ │ ├── chaos_daemons/
│ │ ├── ... (16 more factions, same units/ + armory/ layout)
│ │ ├── _supplements/ # horus_heresy.json, escalation/…
│ │ └── _scratch/ # Parser audit files — never loaded by the app
│ │
│ └── source/ # Original HTML source files used for auditing
│ ├── Chaos Space Marines ENG/
│ └── ... (one folder per faction)
│
├── Codex/ # Canonical rules sources (not pushed) — Core Rules/Missions .txt, one .ods per faction
│
└── scripts/
├── _html2txt.cjs # Strip HTML source to readable text for auditing
├── _scan_mojibake.cjs # Detect encoding artifacts in JSON/TS files
├── _normalize_unit_types.cjs # Cross-faction unit_type casing normalizer
└── _scan_cost_bugs.cjs # Scan for pricing bugs (per-model, fill-model)
Each faction lives in data/parsed/<faction>/. The loader in src/data/loaders.ts assembles the
individual files into the FactionData shape the engine expects.
units.json — core unit data:
{
"faction": "chaos_space_marines",
"slot_to_units": { "HQ": ["Chaos Lord", ...], "Troops": [...] },
"units": {
"Chaos Lord": {
"name": "Chaos Lord",
"slot": "HQ",
"models": [{ "name": "Chaos Lord", "points": 65, "min": 1, "max": 1, "stats": { "M": "6\"", "WS": "2+", ... } }],
"equipped_with": "Every model is equipped with: Bolt pistol; Power sword.",
"weapons": [...],
"option_groups": [
{
"header": "May replace Power sword with:",
"constraint": { "type": "one" },
"choices": [{ "name": "Power fist", "points": 10 }],
"inline_pts": null,
"per_model": false,
"variant_link": null,
"is_unique_per_army": false
}
],
"abilities": ["..."],
"unit_type": "Character Model",
"is_character": true,
"is_vehicle": false,
"is_psyker": false,
"champion_has_armory": false,
"has_veteran_abilities": true
}
}
}
Every faction uses a
units/folder, not a singleunits.json— the JSON shape above shows the logical structure, but on disk it's split into one.tsfile per unit (units/<slot>/<unit>.ts, each exporting aUnit), with per-slotindex.tsfiles that the faction's top-levelunits/index.tsassembles into the same{ faction, slot_to_units, units }shape. The unit object fields are identical — only the on-disk layout differs.
archetypes.json — Army Customisation data:
{
"archetypes": [{ "name": "Legionnaire Warband", "desc": "Full canonical rule text..." }],
"legacies": [{ "name": "Legacy of the Warmaster", "desc": "...", "armory_key": "Black Legion" }],
"traits": [{ "name": "Siege Experts", "desc": "...", "pts_unit": "5", "pts_char": "0", "pts_monster": "5", "pts_veh": "5" }]
}
armory_keymust match the key insrc/data/loaders.tsfor that faction'sarmory_legionsobject. If they diverge the legacy armory tab will not appear.
| Field | Type | Notes |
|---|---|---|
unit_type | string | Must use Core Rules canonical spelling — see src/types/unit-types.ts |
option_groups[].per_model | boolean | Set true when header says "for +X points per model" (inline options) |
option_groups[].effect | OptionEffect | Structured rule change: stat_mod, adds_unit_types, set_unit_type, grants_abilities |
armourKeyword | string | Innate armour class — drives ᵀ/ᴳ armory gating |
pts_monster / pts_veh | string | Shared "Monstrous Creatures & Vehicles" column — must be equal |
⚠️ This workflow is Alpha. The goal is to automate it, but it is not yet fully automatic.
The maintainer can review faction data directly from the canonical Google Sheets source by pasting the sheet URL. The process:
Codex/core_rules_text.txt, missions_text.txt) before a fix is appliedIf you have the source data for an unaudited faction, open a GitHub Issue with the link or paste the data — that immediately unblocks a full audit. See OPEN_QUESTIONS.md for the current list of open items.
Each archetype, trait, and legacy in the engine files has the canonical rule text as a comment directly above its code block:
// SOURCE — Siege Experts:
// "The unit gains the 'Sunder(1)' ability for all ranged attacks."
// COST: 5 | 0 | 5
'Siege Experts': [
{ type: 'weapon_ability', name: 'Sunder(1)', weapon_type: 'ranged', applies_to: 'all' },
],
This makes it immediately visible if the code drifts from the rule. When the two diverge, fix the code — not the comment.
See CONTRIBUTING.md for the full guide. Short version:
npm installnpm run build — must pass with zero TypeScript errorsOpen data/parsed/<faction>/units/<slot>/<unit>.ts, compare it against your copy of the rules, and fix whatever is wrong. See CONTRIBUTING.md for the fields to check and the file templates for adding missing armory/psychic/archetype files.
If you find an error but are not sure how to fix the JSON, open a GitHub Issue using the Data correction template.
If you know the game and can answer an ambiguous rule, check OPEN_QUESTIONS.md — answering a rules question directly unblocks an engine implementation. Use the Rules question issue template on GitHub.
src/engine/ — see CONTRIBUTING.md for the engine file mapsrc/components/src/store/army.tsnpm run build is the gateSee the Changelog button in the app, or read src/data/changelog.ts / src/data/known-issues.ts directly.
Open questions and help-wanted items: OPEN_QUESTIONS.md.