Mod authoring
Folder layout
Section titled “Folder layout”Every mod is a directory next to its manifest:
my-chat-theme/ mod.yaml assets/ icons/ chat_icon.png config.json # created/updated by Carbon when settings changemod.yaml: required manifest (apiVersion: carbon.mods/v1).assets/: files referenced bysourcepaths in operations.config.json: leave this to Carbon unless you are debugging; the app writes user settings here.
Install community mods from the Carbon desktop app (Mods → Install Folder or Install Zip). They are stored under <Carbon root>/mods/<id>/. Built-in mods live in the repo at project/builtin-mods/<id>/ and ship inside the app binary; your toggles and config.json for built-ins go to bin/configs/mods/<id>/.
Minimal mod (single file swap)
Section titled “Minimal mod (single file swap)”apiVersion: carbon.mods/v1id: my-silent-oofname: Silent Oofauthor: your-nameversion: 1.0.0description: Replaces the death sound with silence.tags: - soundspriority: 5operations: - type: replace-file target: content/sounds/oof.ogg source: assets/oof.oggDrop a silent oof.ogg at assets/oof.ogg, enable the mod, and launch.
Mod with settings
Section titled “Mod with settings”Use settings for UI controls and reference keys in operations:
apiVersion: carbon.mods/v1id: my-spinnername: Spinner Colorauthor: your-nameversion: 1.0.0description: Recolor the loading spinner.tags: [ui, loading]priority: 6settings: - key: color type: dropdown label: Spinner color default: blue options: [blue, pink, white]operations: - type: replace-file target: ExtraContent/textures/ui/loading/circle_dark.png source: assets/{color}/circle_dark.png - type: replace-file target: ExtraContent/textures/ui/loading/circle_light.png source: assets/{color}/circle_light.pngConditional operations
Section titled “Conditional operations”when and unless take a setting key (booleans for toggles):
settings: - key: useCustom type: toggle label: Use custom cursor default: false
operations: - preset: cursor source: assets/cursors/{cursor}.png unless: useCustom - preset: cursor source: "{customCursor}" when: useCustomPreset-based mods
Section titled “Preset-based mods”When you replace many related files, use a preset operation instead of listing each Roblox path. Carbon expands presets at launch (see project/carbon/Mods/ModPresetRegistry.cs).
Start with the Preset operations guide, it documents:
- The full preset catalog (
cursor,menu-icons,sounds,skybox,fonts, …) - Required folder layouts (for example
assets/sky/{name}/cubemap+dynamic) - How Menu Bar Pack settings in the app map to
config.jsonand amenu-iconsmerge
Quick copies:
# Top menu bar: match filenames in project/builtin-mods/menubar-pack/assets/menu/operations: - preset: menu-icons source: assets/menu/{theme} mode: merge# Sky: needs cubemap/ and dynamic/ subfolders (see skybox-pack)operations: - preset: skybox source: assets/sky/{preset} mode: merge# Sounds: filenames must match Roblox (action_jump.mp3, etc.)operations: - preset: sounds source: assets/sounds mode: mergeThe built-in mods catalog links each shipped mod to these patterns.
Authoring tips
Section titled “Authoring tips”idmust be unique, lowercase, and hyphenated. Carbon uses it as the stable mod identifier.priority: bump it when your mod needs to win over another mod on the sametarget.- Match Roblox paths exactly. A wrong
targetoften fails quietly. Compare with built-in mods that touch the same UI. - Ship
@2x/@3xvariants when you replace UI PNGs that Roblox ships at multiple resolutions. - Test in small steps: one
replace-file, confirm in-game, then grow the mod.
Sharing
Section titled “Sharing”Zip the mod folder (mod.yaml + assets/). You can omit config.json unless you want default settings baked in. Share on Discord or GitHub; recipients install through the desktop app.
For every field, see the mod.yaml reference.