Getting started

Content tags and distributions

The closed vocabulary that says what a mod, a feature or a scene contains, and the distribution profiles (Steam, Underlives.com) that decide where it ships.

warning

Format in progress, engine in build (2026-10-25). The tags and the two files below are read by the engine being built; today's game ignores them, the validator and the packaging will not. Write them now, they will not change.

The game exists in more than one distribution: a Steam build, with what Steam accepts, and a full build on the hub and underlives.com. What goes where is carried by the data, checked by the validator, and never kept as a hand-written list of mods.

The vocabulary

ul_Base/Content/content_tags.json holds the closed list, each tag with its doc. A mod may add a tag (a new entry in its own Content/content_tags.json); nobody removes one.

Tag Covers
sexual Explicit sex on screen, or a mod whose subject is sex (a brothel, a strip club, swinging, porn work).
nonconsent Sexual acts without consent, or sexual pressure on someone who cannot refuse: drugged, unconscious, blackmailed, captive.
incest Sexual or romantic acts between relatives.
violence Physical harm shown or dealt: fights, beatings, weapons, abuse, killing.
drugs Drug use, dealing or spiking shown.
bestiality Sexual acts with animals.
gore Mutilation, corpses or wounds in detail.
fantasy Creatures, magic, horror, time loops: outside the realistic town. Not sensitive by itself; every build keeps it.

An element without a tag is for everyone. The children rules (the engine's own, Reference/CHILDREN_POLICY.md in the game repository) are not a tag: the engine enforces them in every distribution, and no profile lifts them.

Where a tag goes

On How Example
The whole mod MODULE_CONTENT: tag, tag in the .ulmod MODULE_CONTENT: violence, drugs
A feature The fourth field of its MODULE_FEATURE line MODULE_FEATURE: the_wife | Taking the debtor's wife | on | nonconsent, sexual
A scene content = { … } at the top of the scene table content = { "drugs" }
An action content = { … } in the .ulaction content = { "drugs" }
An asset pack content in its manifest a clothing pack of fetish wear: { "sexual" }

An element's tags are the union of its own, its feature's and its mod's. So a mod carries the union of everything in it, and a scene that goes further than the rest of the mod carries the difference itself: ul_Debts is violence throughout, and the one scene where a collector drugs the debtor adds drugs on that scene.

The scene grain is what makes a partly touched mod shippable: the mod stays, the scenes that carry a refused tag go.

What implies a tag

Some things a scene does say what it contains without anyone writing a tag. The implies table of content_tags.json maps them to tags, and the validator reads it:

Key Means Implies
witness.<type> The scene records this witness act type its tags: sexual_assault → nonconsent, sexual; assault → violence; drug_deal → drugs; body_disposal → violence, gore…
call.Game:Sex, call.Game:startSexScene A sex scene plays sexual
call.Game:TalkNonConsensual, call.Actor:setForcedParticipant The sex scene is forced nonconsent, sexual
call.Actor:knockOut, call.Actor:die Someone is knocked out or killed violence
effect.sex, effect.sex.forced The effects of a table scene sexual; nonconsent, sexual

A scene that implies a tag its mod does not carry is a validator error: the author either adds the tag or takes the act out. A scripted scene (script, or a legacy RUN function) is read for its calls; a table scene for its effects. The full table has one line per witness act type of ul_Base and of every shipped mod.

Distributions

ul_Base/Content/distributions.json: steam with name and deny, full with an empty deny.

Profile Refuses
steam (Steam) nonconsent, incest, bestiality
full (Underlives.com) nothing

deny lists the tags a build refuses. The Steam list follows Steam's adult-content rules of the day and is data, not code: it changes in this file, never in the engine.

What the engine and the tools do with it

  • Packaging. release.ps1 -Distribution steam leaves out a mod whose own tags hit the deny list, and from a partly touched mod removes the features, scenes and actions that carry a refused tag. Before packaging, the validator checks that what remains stands: no kept scene points at a removed one, a quest with a removed step is removed whole.
  • Runtime. The build's distribution is read-only (Game:distribution() → "steam" or "full"). Refused elements are not disabled, they are absent from the disk.
  • The Mods menu. A mod installed from the hub into a Steam build with a refused tag does not load; the list shows it as Blocked with the reason ("carries nonconsent, refused by this distribution"), like a missing requirement today.
  • The hub. Shows each mod's tags and its compatibility per distribution, and refuses a publication without tags when the validator infers some.
  • The validator (Tools/ModLint/) checks the vocabulary (an unknown tag is an error), the implies rules, and that a scene's own content is a subset of what the vocabulary knows.

This is not a player setting or a parental filter. The Peaceful / Balanced / Dark world profiles are a game setting; the distribution is a fact of the build.

A complete example

ul_Debts: loan sharks, collectors, beatings, one feature that goes further, one scene where a debtor is drugged before a "lesson".

iniMODULE_UNIQUEID: ul_Debts
MODULE_NAME: Debts
MODULE_REQUIREMENTS: ul_Base
MODULE_CONTENT: violence
MODULE_FEATURE: loan_sharks | Loan sharks | on
MODULE_FEATURE: bookie | The bookie | on
MODULE_FEATURE: the_wife | Taking the debtor's wife | on | nonconsent, sexual

The one scene that goes further than the mod (Scenes as tables):

luareturn {
	id = "ul_db_press_lesson",
	feature = "loan_sharks",
	content = { "drugs" },
	beats = { --[[ … ]] },
}

What each build does:

Build ul_Debts ul_db_press_lesson feature the_wife
full loads plays on
steam (deny nonconsent, incest, bestiality) loads: violence and drugs are accepted plays left out of the package

Change the steam profile to deny drugs and the same data gives: ul_Debts loads, ul_db_press_lesson is left out too, and the validator first checks nothing kept still points at it.

A mod whose subject is refused is simply absent from that build: ul_Incest (sexual, incest, nonconsent) does not exist in the Steam package, and a Steam player who installs it from the hub sees it Blocked in the Mods menu with the reason.

Shipped mods today

The inventory of 2026-10-25 tagged 73 of the 166 shipped ul_* mods (Reference/CONTENT_TAGS_INVENTORY_2026-10-25.md in the game repository): every tagged mod carries a MODULE_CONTENT: line, and the report names the scenes that carry the strongest tag inside mixed mods, which is where the scene-level content goes as those mods are converted to tables.