Files
onion-mc/analysis/client-perf/research/r3-entity-animation.md
T
logan 611a1a5952 docs: client-perf analysis, bench harness and work journal
Everything the next agent needs to run the Phase 2 optimisation loop on a
machine that can launch the client:

- analysis/client-perf/: LEVERS (ranked levers + corrections), BENCH-MATRIX
  (world, scenes, config IDs, blocks B0-B14 with decision rules),
  PLAYER-TUNING, SPAWN-TUNING, research briefs, the jar scanner and its
  output, observed default configs, and proposed-configs/ (build.py
  generates tiers and bench variants and fails on unknown keys;
  apply_variant.py applies a variant and merges options.txt).
- analysis/client-perf/bench/onion-bench/: bench-world datapack (scene
  teleports, Create grid, mob pen, sound storm, 120 s teleport tour).
- analysis/audit/: the static recipe/dependency audit, including gen_fixes.py,
  which generates the shipped Paxi datapack and was never tracked.
- phase0/: per-machine measurement harness (Steam Deck, 7700K/1060,
  6700K/1080 Ti).
- .pi/journal.md: running work log; read it first.

All of it is packwizignored, so nothing here ships to players.
2026-10-14 18:15:32 -04:00

486 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Research: Entity & Animation Rendering Cost (client-side)
Scope: Minecraft 1.21.1 / NeoForge 21.1.251, Onion MC pack pins. Purely client-side
render/main-thread and heap cost of entity models, animations and dynamic lights.
Tags: **VERIFIED** = read in source/config code, **DOCUMENTED** = official
README/wiki/changelog, **COMMUNITY** = user reports/forums, **INFERENCE** = my reasoning.
---
## Summary
Entity/animation cost in this pack is dominated by three independent CPU-side pipelines
that **do not share configuration**: (1) EMF/CEM custom models driven by Fresh Animations
(`animationLODDistance`, `modelUpdateFrequency`), (2) GeckoLib 4.x models used by Mowzie's,
Fowlplay, dragons, etc. (no user-facing perf config in GeckoLib itself), and (3)
player-animation mods (Better Combat / playerAnimator / Emotecraft) layered on EMF. Only
pipeline (1) is throttled by the EMF knobs most guides mention; the biggest confirmed
per-mob cost multiplier is **Iris shadow-pass re-animation**, which EMF already skips by
default in this version. Dynamic lights (LambDynamicLights 4.8.x) are a separate risk
because each moving light source forces **chunk mesh rebuilds**, which is far more
expensive than animation math. Entity**Culling** (already in pack) and the vanilla
**Entity Distance** slider are the two levers that reduce the *number* of entities hitting
any of these pipelines, and are therefore the highest-leverage, lowest-risk changes.
---
## Findings
### A. EMF 3.x + ETF 7.x with Fresh Animations (+ All Extensions)
1. **EMF exposes exactly five performance-relevant settings.** From `EMFConfig.java`
(repo master = mod_version **3.3.11**; the pack's 3.3.9 is the same config surface):
`animationLODDistance` (int, default **20**, range 0–65), `retainDetailOnLowFps`
(default true), `retainDetailOnLargerMobs` (default true),
`animationFrameSkipDuringIrisShadowPass` (default true), and `modelUpdateFrequency`
(type `ETFConfig.UpdateFrequency`, default `Average`). `asmMaths` ("Compiled animation
math", default true) is the compiled-maths fast path. [VERIFIED]
https://github.com/Traben-0/Entity_Model_Features/blob/master/src/main/java/traben/entity_model_features/config/EMFConfig.java
2. **`animationLODDistance` is frame-skipping keyed to distance from the client player.**
Official tooltip: "Sets the distance at which animations will begin to skip frames,
lower the Level of Detail (LOD) … None = no frame skipping; 16 = will skip 1 frame for
every 16 blocks distance from player. Lower numbers mean more skipped frames and more
performance gain." Default is 20; 0 = the "None" entry on the slider. [DOCUMENTED —
mod lang file, same repo]
https://github.com/Traben-0/Entity_Model_Features/blob/master/src/main/resources/assets/entity_model_features/lang/en_us.json
The setting was introduced in the 1.3 changelog and the size-aware variant
(`retainDetailOnLargerMobs`) in the 2.0 changelog. [DOCUMENTED — CHANGELOG.MD]
https://github.com/Traben-0/Entity_Model_Features/blob/master/CHANGELOG.MD
3. **`retainDetailOnLowFps` and `retainDetailOnLargerMobs` deliberately soften the LOD
effect** (less skipping below 60 fps; less skipping on big mobs). Tooltips: "reduce the
Level of Detail (LOD) impact of the above setting according to the mobs size" / "…
according to your fps. Only applies when below 60 fps." Turning these **off** makes the
LOD slider do more work (more aggressive skipping). [DOCUMENTED — mod lang file]
https://github.com/Traben-0/Entity_Model_Features/blob/master/src/main/resources/assets/entity_model_features/lang/en_us.json
4. **`animationFrameSkipDuringIrisShadowPass` is the single most important EMF option and
is already ON.** Changelog 2.1.1: "added an optimization option that will skip
recalculating entity model animations during the iris shadow pass, on by default, and
**should always stay on**". With shaders, each animated model would otherwise be
animated a second time for the shadow pass. **Verify this is still `true` on all three
fleet machines** — it is the difference between 1× and 2× animation cost per frame.
[VERIFIED — config + DOCUMENTED — changelog]
https://github.com/Traben-0/Entity_Model_Features/blob/master/CHANGELOG.MD
5. **EMF 3.2+ already contains a large animation-speed fix.** Changelog 3.2: "significant
performance improvement for custom animations (**more than doubling frames** when many
animated entities are present)". The pack's EMF 3.3.9 includes this; do not "fix" FA
cost by downgrading. [DOCUMENTED]
https://github.com/Traben-0/Entity_Model_Features/blob/master/CHANGELOG.MD
6. **`modelUpdateFrequency` only controls *model refresh* (health/age/child-state
changes), not per-frame animation.** Tooltip: "Sets how often a mobs model will update
for changes like health & age. Never = never update, Slow = 3-5 seconds, Average =
about 1 second, Fast = less than a second, Instant = instant (possible lag with
hundred of mobs)". Default `Average`. Lowering it to `Slow`/`Never` is a cheap,
low-visual-impact win on busy farms/villager halls. [VERIFIED — config; DOCUMENTED —
lang file]
7. **Per-model opt-out exists** via `modelsNamesDisabled` (a `Set<String>` of
`<name>.jem`), exposed in the GUI as "Enable model" per .jem file. This lets you kill
the most expensive FA models (e.g. villager layers) without dropping FA globally.
[VERIFIED — config]
https://github.com/Traben-0/Entity_Model_Features/blob/master/src/main/java/traben/entity_model_features/config/EMFConfig.java
8. **`allowedCEM` gates which model namespaces EMF touches** (`All` / `Known only (mostly
vanilla/OptiFine)` / `Unknown only (mostly modded)` / `Off`). Setting it to
`Known only` stops EMF from building CEM models for modded mobs — useful if FA-derived
models on modded entities are the hot path. [VERIFIED — config]
9. **Measured Fresh-Animations cost is large and shader-amplified.** On the EMF issue
tracker, a user reported on 1.21.11 + Sodium/Iris: 50 cows on screen = 400+ fps (no
mods) → 110–130 fps with Fresh Animations → **30–40 fps with shaders + FA**; vanilla
animations on the same scene = 300–350 fps / 180–200 fps with shaders. The EMF author
replied the numbers are "more than I'd expect" but that FA "animations are just so
involved compared to vanilla" and you "aren't going to be easily pushing past 200 fps
with fresh animations on ever". A second reporter on 1.20.1 saw 165→40 fps with 30 cows
+ Beefier Bovine x FA + Complementary. The issue was closed as fixed in a later
release. [COMMUNITY — user reports on mod's own tracker; DOCUMENTED — maintainer reply]
https://github.com/Traben-0/Entity_Model_Features/issues/443
10. **Independent corroboration that FA + EMF/ETF drops FPS on villager-heavy scenes:**
easy-villagers #243 "Huge FPS drops with Fresh Animations and the mods needed for it
(EMF/ETF). Seems to be trying to run the animations even tho there's no animation
seen." [COMMUNITY]
https://github.com/henkelmax/easy-villagers/issues/243
11. **EMF recommends EntityCulling specifically for animation-heavy packs.** EMF README:
"Entity Culling … does wonders for reducing entity rendering lag, doing even more than
Sodium's included entity culling. This is very beneficial when using animation heavy
packs like Fresh Animations." [DOCUMENTED — official README]
https://github.com/Traben-0/Entity_Model_Features
12. **ETF: the cost-bearing knobs are the texture-update frequency and emissive/skin
toggles.** From `ETFConfig.java`: `textureUpdateFrequency_V2` (enum `UpdateFrequency`:
`Never` = -1, `Slow` = 80 t, `Average` = 20 t, `Fast` = 5 t, `Instant` = 1; **default
`Fast`**), `enableCustomTextures`, `enableEmissiveTextures`, `enableEmissiveBlockEntities`,
`emissiveRenderMode` (`DULL`/`BRIGHT`), `enableEnchantedTextures`, `enableArmorAndTrims`,
`enableBlinking`, `blinkFrequency` (150), `blinkLength` (1), `skinFeaturesEnabled`,
`skinTransparencyMode`, `use3DSkinLayerPatch`, `alwaysCheckVanillaEmissiveSuffix`,
`advanced_IncreaseCacheSizeModifier` (1.0), `enableFullBodyWardenTextures`,
per-entity override maps (`entityEmissiveOverrides`, `entityRandomOverrides`,
`entityEmissiveBrightOverrides`, `entityRenderLayerOverrides`, `entityLightOverrides`).
`UpdateFrequency` is a **tick delay** for re-evaluating random/variant properties, so
moving `Fast` (5 t, 4 Hz per entity) → `Average` (20 t, 1 Hz) cuts per-entity texture
bookkeeping 4×. [VERIFIED — source]
https://github.com/Traben-0/Entity_Texture_Features/blob/ETF-Main/src/main/java/traben/entity_texture_features/config/ETFConfig.java
13. **ETF rates misbehaving packs as a lag source.** README FAQ: "If you are experiencing
lag please check your most recent log file to see if any errors are being logged,
sometimes an incorrectly written properties file or missing textures may lag the
system." Relevant because FA All Extensions ships many `.properties` files — a single
mis-pathed texture can multiply cost. [DOCUMENTED]
https://github.com/Traben-0/Entity_Texture_Features/blob/ETF-Main/.github/README.md
14. **ETF emissive conflicts with Complementary shaders.** ETF FAQ: "Complimentary shaders
has its own in-built emissive textures that usually work fine but will conflict with
some resource packs. You can either disable Complimentary's emissives or ETF's
emissives to fix this." Relevant because the pack runs Complementary Reimagined r5.9.3.
[DOCUMENTED]
https://github.com/Traben-0/Entity_Texture_Features/blob/ETF-Main/.github/README.md
15. **Known pack-relevant interaction: ImmediatelyFast 1.6.14 vs FA All Extensions.**
ImmediatelyFast issue #180 (still open, last comment Dec 2025): ImmediatelyFast breaks
the custom models of Fresh Animations Extensions. The reporter's working set was
ETF + EMF + Embeddium(+extra) + FreshAnimations + FA+All_Extensions; adding
ImmediatelyFast broke entity rendering. Maintainer: "I added this as a low priority
issue to my todo list." The pack carries ImmediatelyFast 1.6.14 + FA All Extensions
1.8.1 — worth an A/B on entity visuals/cost. [COMMUNITY/DOCUMENTED — mod tracker]
https://github.com/RaphiMC/ImmediatelyFast/issues/180
16. **FA All Extensions is a bundle of official sub-packs** (details, creeper/spider
edits, emissive add-on, quivers, classic horses), i.e. it *adds* cost on top of base
FA rather than being neutral. [DOCUMENTED — mod description]
https://www.curseforge.com/minecraft/texture-packs/fresh-animations-extensions
### B. GeckoLib 4.x (Mowzie's, Fowlplay, dragons, Doggy Talents, etc.)
17. **GeckoLib is a library, and the pack's GeckoLib 4.9.3 has no end-user performance
config.** The official README documents no client perf options — its `wiki.geckolib.com`
is modder documentation (controllers, molang, render layers). Per-entity animation
cost is therefore set by each *consumer mod*, not by a config the pack can tune.
[VERIFIED — README has no config section]
https://github.com/bernie-g/geckolib
18. **Mowzie's Mobs genuinely requires GeckoLib 4.9.3 on 1.21.1 NeoForge** — reproduced in
a 1.21.1/NeoForge 21.1.248 + Mowzie's 1.8.2 + GeckoLib 4.9.3 report. So the pack's
GeckoLib load is not optional. [COMMUNITY/DOCUMENTED — mod repo issue]
https://github.com/BobMowzie/MowziesMobs-Public/issues/64
19. **Third-party GeckoLib optimizers exist and are directly relevant to 1.21.1 NeoForge.**
"GeckoLib Animation Optimizer" requires GeckoLib 4.9.0+ on 1.21.1 NeoForge; its
description claims configurable distance-based animation optimisation and camera
visibility culling enabled by default, block-occlusion culling and player optimisation
disabled by default, "fully client-side". "GeckolibBetterFPS" claims ~"25% faster
rendering of GeckoLib entities" and "reduces micro stutters when multiple GeckoLib
entities are present", but it is a MoePus mod historically targeted at 1.20.1 — check
1.21.1 build availability before proposing. [COMMUNITY — mod listings; treat the
percentages as vendor claims, not verified]
https://www.curseforge.com/minecraft/mc-mods/geckolib-animation-optimizer ,
https://modrinth.com/project/CZyWdBUo
20. **Important negative finding: EMF's animation LOD does NOT throttle GeckoLib.**
EMF only handles OptiFine CEM `.jem` models; GeckoLib renders through its own pipeline.
**INFERENCE**: the `animationLODDistance` lever benefits vanilla-mob/FA content only;
for GeckoLib-heavy scenes the only EMF-independent levers are EntityCulling, the
Entity Distance slider, and reducing the number of GeckoLib entities (spawn/mob count).
21. **Citadel (Alex's Mobs / Alex's Caves) is a different library from GeckoLib.** The
widely-reported Alex's Mobs perf complaints are about **server/world-gen and chunk
loading**, not client rendering — Citadel issue #156 is titled "Alex's Mobs X Citadel:
Slow Chunk loading", and r/feedthebeast discussion is about worldgen/chunky comparison.
A separate community "Alex's Mobs: Tweaks [Performance Optimization]" (AMT) addon
claims to "fix several expensive Alex's Mobs and Citadel hot paths". Treat client-side
Citadel cost as driven mainly by entity *count* and its own model complexity.
[COMMUNITY]
https://github.com/AlexModGuy/Citadel/issues/156 ,
https://www.curseforge.com/minecraft/mc-mods/amt
### C. 3D Skin Layers (1.11.3)
22. **3D Skin Layers already has a built-in distance LOD.** README: "The mod automatically
switches back to vanilla-style 2D rendering when players are more than **12 blocks
away**". The config option is "Level Of Detail Distance" — "The distance at which the
model will switch to a lower level of detail (vanilla 2d)". [DOCUMENTED — README;
VERIFIED — lang file]
https://github.com/tr7zw/3d-Skin-Layers ,
https://github.com/tr7zw/3d-Skin-Layers/blob/main/src/main/resources/assets/skinlayers3d/lang/en_us.json
23. **Per-limb and per-feature toggles let you buy cost back cheaply.** Lang keys observed:
"3D Hat", "3D Jacket", "3D Left/Right Sleeve", "3D Left/Right Pants", "3D Skulls",
"3D Skull Items", plus cost/quality knobs "Voxel Size", "Head Voxel Size", "Body Voxel
Height", "Torso Voxel Width", "Skull Voxel Size", "First Person Voxel Size", "Fast
Render" ("render the 3D models as fast as possible, this may cause some graphical
glitches with transparency"). [VERIFIED — lang file]
https://github.com/tr7zw/3d-Skin-Layers/blob/main/src/main/resources/assets/skinlayers3d/lang/en_us.json
24. **3D Skin Layers is explicitly integrated with EMF and with playerAnimator.**
Repo contains `EMFModelPartMixin.java`; README lists Player Animator as supported
("This means mods that use it like Better Combat and Emotecraft"). ETF in turn exposes
`use3DSkinLayerPatch` which is only shown when `ETF.SKIN_LAYERS_DETECTED`. So EMF/ETF,
3D Skin Layers and playerAnimator form one chained render path on players.
[VERIFIED — source files; DOCUMENTED — README]
https://github.com/tr7zw/3d-Skin-Layers/blob/main/src/main/java/dev/tr7zw/skinlayers/mixin/EMFModelPartMixin.java
25. **Compat/quality switches that trade correctness for cost:** "Compatibility Mode",
"Iris Compatibility Mode" ("fixes weird shadows/colors when using Iris shaders … Will
break the corner connections"), "Sodium Workaround". Only enable as needed. [VERIFIED —
lang file]
26. **Cost is bounded by player count, not mob count.** 3D Skin Layers only affects player
models/heads. On a 10-player server, worst case is 9 remote players within 12 blocks.
[INFERENCE]
### D. Player-animation stack: Better Combat + playerAnimator + Emotecraft
27. **Better Combat requires playerAnimator, and its animation code runs on *every*
player entity, not just yourself.** Its client package contains
`PlayerAttackAnimatable` and `CustomAnimationPlayer` under
`common/…/client/animation/`, i.e. it is a `Player`-model mixin path, and Better Combat
synchronises attacks so remote players' swings animate too (community reports of
multiplayer animation bugs confirm remote-player animation is rendered).
[VERIFIED — repo file tree; COMMUNITY — multiplayer reports]
https://github.com/ZsoltMolnarrr/BetterCombat/tree/1.21.1/common/src/main/java/net/bettercombat/client/animation
28. **Better Combat client-side cost knobs are few but real.** `ClientConfig.java` fields
include `isShowingWeaponTrails` (**default true** — the slash/trail particle system in
`client/particle/TrailParticles.java` and `SlashParticleUtil.java`),
`isSweepingParticleEnabled` (default false), `isShowingArmsInFirstPerson` (false),
`firstPersonAnimations` (TriStateAuto.AUTO), `legAnimationThreshold` (0). Turning off
weapon trails removes a per-swing particle + geometry cost without touching animation
math. [VERIFIED — source]
https://github.com/ZsoltMolnarrr/BetterCombat/blob/1.21.1/common/src/main/java/net/bettercombat/config/ClientConfig.java
29. **There is a first-class EMF ⇄ playerAnimator conflict, and a purpose-built fix.**
"Entity Player Compat" (MIT, client-side, published for **1.21.1 NeoForge/Fabric**,
requires EMF + PlayerAnimator) exists because EMF's custom player models and
playerAnimator both write player part transforms. It does per-part blending
("Automatically detects which specific body parts … are being animated by PlayerAnimator
and only pauses EMF animations for the specific parts currently in use"), a "virtual
follow" limb re-parenting system, and claims "high-performance tick-based caching …
does its work in a handful of hooks per frame." It explicitly lists Better Combat,
FA: Player Extension and GeckoLib/AzureLib armors as tested. [DOCUMENTED — mod page]
https://modrinth.com/mod/entity-player-compat
**INFERENCE**: without it, EMF will animate the player model *and* playerAnimator will
animate it again each frame — double work on every visible player, the exact class of
waste `animationFrameSkipDuringIrisShadowPass` was built to avoid. This is a strong
candidate lever for the 10-player use case.
30. **Emotecraft is built on playerAnimator and is client-side-required.** Emotecraft needs
the client half; the server half is optional, and features stay inactive without a
sync path. Emote animation is transient (only while an emote plays), so steady-state
cost is low; the risk is many simultaneous emotes near the player. [DOCUMENTED —
Emotecraft/playerAnimator listings]
https://minecrafthub.io/mods/emotecraft , https://minecrafthub.io/mods/playeranimator
31. **EMF has explicit Emotecraft integration** — changelog 3.0.7 added
`registerPauseCondition(Function<EMFEntity,Boolean> shouldPause)` to
`EMFAnimationApi` specifically so mods like EmoteCraft stop mixing in, and 3.3.4
"updated emote craft emote pausing support in EMF". So EMF+Emotecraft is a supported
path; the pack's EMF 3.3.9 is new enough. [DOCUMENTED — CHANGELOG.MD]
https://github.com/Traben-0/Entity_Model_Features/blob/master/CHANGELOG.MD
### E. LambDynamicLights 4.8.x on Sodium
32. **Dynamic lights cost is chunk rebuilds, not per-frame shading.** Official
"How does it work": "To apply the dynamic lighting we have to request the affected
chunks a rebuild to rebuild the lightmap, **which is the most critical part
performance-wise**. Rebuilding a chunk cost performances, that's why there's multiple
mode: FASTEST, FAST and FANCY. The fast modes will limit the update." The mod computes
dynamic light over a radius of 7.75 blocks, "which is still a lot" of touched chunks,
and hooks `WorldRenderer#setupTerrain` (or its Sodium equivalent) to schedule rebuilds.
[DOCUMENTED — official doc]
https://github.com/LambdAurora/LambDynamicLights/blob/1.21/HOW_DOES_IT_WORK.md
33. **Exact 1.21-branch config keys (this branch is `@version 4.8.0`, matching pack 4.8.11),
config file `config/lambdynlights.toml`:** `mode` (enum `off`/`fastest`/`fast`/`fancy`,
**default `fancy`**), `chunk_rebuild_scheduler` (`culling` **default** / `immediate`),
`adaptive_ticking.slow` (**5** chunks), `adaptive_ticking.slower` (**8** chunks),
`adaptive_ticking.background_sleep` (**true**), `light_sources.entities` (true),
`light_sources.self` (true), `light_sources.water_sensitive_check` (true),
`light_sources.beam` (true), `light_sources.guardian_laser` (true),
`light_sources.sonic_boom` (true), `light_sources.glowing_effect` (true),
`light_sources.creeper` (`simple`), `light_sources.tnt` (`off`), plus `debug.*`.
[VERIFIED — source]
https://github.com/LambdAurora/LambDynamicLights/blob/1.21/src/main/java/dev/lambdaurora/lambdynlights/DynamicLightsConfig.java
34. **The quality mode maps to a tick mode, not to radius.** `DynamicLightsMode` in the
1.21 branch: `FANCY → TickMode.REAL_TIME`, `FAST → TickMode.SLOW`,
`FASTEST → TickMode.SLOWER`, `OFF → REAL_TIME` (disabled). So `fastest`/`fast` throttle
**how often light updates are applied** (fewer chunk rebuilds/second), which is the
correct lever for stutter, and `fancy` gives real-time smoothness at full rebuild cost.
[VERIFIED — source]
https://github.com/LambdAurora/LambDynamicLights/blob/1.21/src/main/java/dev/lambdaurora/lambdynlights/DynamicLightsMode.java
35. **The 4.8.x line added two dedicated cost mitigations vs older guides.** `chunk_rebuild_scheduler`
(`culling` default vs `immediate`) and the adaptive-ticking distance pair
(`adaptive_ticking.slow` / `.slower`, in **chunks**) plus `background_sleep` under
`adaptive_ticking`. These are the 1.21-branch additions that the widely-copy-pasted
"Light Range / updateInterval / entitiesGlowing" advice (which cites keys that do not
exist in the 1.21 branch source) does not mention. [VERIFIED — source vs the third-party
guide] https://lambdynamiclights.com/configuring-lambdynamiclights-for-peak-performance/
36. **Per-category light-source toggles map to real feature costs.**
`light_sources.entities=false` removes all burning-mob/glow-squid/entity-carried-light
sources (the biggest moving-light population in a survival world);
`light_sources.self=false` removes the first-person player light;
`light_sources.beam`/`guardian_laser`/`sonic_boom`/`glowing_effect` cover beacon beams,
guardian beams, sonic booms and the Glowing effect. Disabling `entities` while keeping
`self` is the usual "I still want my torch to glow, but not 200 burning zombies"
compromise. [VERIFIED — source]
https://github.com/LambdAurora/LambDynamicLights/blob/1.21/src/main/java/dev/lambdaurora/lambdynlights/DynamicLightsConfig.java
37. **Sodium interop is explicit, not accidental.** `HOW_DOES_IT_WORK.md`: "we inject at
`WorldRenderer#setupTerrain` (`WorldRenderer#render` at `WorldRenderer#setupTerrain`
invoke **if Sodium is present**)". So LDD 4.8.x is Sodium-aware by design; the classic
"dynamic lights cause chunk rebuild stutter on Sodium" claim needs to be re-measured
on this version rather than assumed. [DOCUMENTED]
https://github.com/LambdAurora/LambDynamicLights/blob/1.21/HOW_DOES_IT_WORK.md
### F. EntityCulling (1.11.2) interplay
38. **Independently useful alongside Sodium's own culling.** README: "I have 'Use Entity
Culling' enabled in Sodium — does this still help? Yes! … Sodium performs basic
visibility checks based on loaded chunks, this mod goes further. It analyzes the
actual line-of-sight visibility, skipping entities that are within visible chunks but
not actually visible to the player." [DOCUMENTED — official README]
https://github.com/tr7zw/EntityCulling
39. **It has a client-side entity *tick* culling feature, not just render culling.**
`Config.java` (config version 9): `tickCulling` (**true**), with a separate
`tickCullingWhitelist`. This reduces main-thread entity tick cost — relevant to P2's
main-thread bottleneck. [VERIFIED — source]
https://github.com/tr7zw/EntityCulling/blob/main/EntityCulling-Versionless/src/main/java/dev/tr7zw/entityculling/versionless/Config.java
40. **Exact config keys/defaults** (`config/entityculling.json`): `tracingDistance` **128**
(path-trace range), `sleepDelay` **10**, `hitboxLimit` **50**, `captureRate` **5**,
`tickCulling` **true**, `skipEntityCulling` false, `skipBlockEntityCulling` false,
`blockEntityFrustumCulling` **true**, `forceDisplayCulling` false, `solidLeaves`
**false** ("treat leaves as solid blocks … help to increase the performance in
forested areas" — directly relevant with Better Leaves 9.6 in pack), `safeMode` true,
`renderNametagsThroughWalls` true, plus `entityWhitelist` / `blockEntityWhitelist` /
`tickCullingWhitelist`. [VERIFIED — source; DOCUMENTED — README for `solidLeaves`]
41. **Known interaction: client-side/mod "display" entities and far-bounds block entities
need whitelisting** — "Client-side entities, commonly used by magic mods for
animations, may not behave as expected. Whitelist the relevant entities via the config
screen for tick culling and/or entity culling … You'll also need to whitelist block
entities that render well beyond their normal bounds. Examples include the vanilla
beacon, pulleys from Create…". **INFERENCE**: relevant to this pack's Create/Flywheel
contraptions and Veil-based mods; verify no visual regressions before recommending any
change. [DOCUMENTED — README]
42. **Mild CPU trade-off on very weak CPUs.** README: "Consider [disabling] when playing on
a really old computer … When the CPU is already maxed out, there is no spare CPU time
to run the visibility calculations." None of the fleet's CPUs are in that class, but
the Steam Deck's shared power budget makes this worth watching. [DOCUMENTED — README]
43. **Author-provided test reference:** the README's comparison screenshot was captured
with "Sodium, Iris and ImmediatelyFast … alongside EntityCulling" — i.e. exactly the
pack's stack. [DOCUMENTED — README]
44. **Also provide a F3-adjacent debug toggle.** "In the controls menu, you can bind a
debug key to toggle the mod on and off on the fly" — this is the cleanest in-situ
benchmark control for entity cost. [DOCUMENTED — README]
### G. Entity-count drivers and the Entity Distance slider
45. **Clumps is a server-side aggregation mod, so its client benefit is indirect but real.**
"Clumps groups XP orbs together into a single entity to reduce lag when there are many
in a small area." On 1.17+ it is a **server** mod: "For a multiplayer world on 1.17 or
newer, the jar goes on the server rather than on each player's client." Fewer orb
entities on the server → fewer orb entities synchronised → less client render/tick and
(with LDD) fewer dynamic-light sources. Verify it is installed server-side.
[DOCUMENTED — mod listings]
https://modrinth.com/mod/clumps/versions , https://minecrafthub.io/mods/clumps
46. **The vanilla "Entity Distance" video setting is the bluntest client lever.** The
Minecraft Wiki's simulation-distance article states the client does not render entities
based only on Render Distance but on "both 'Render distance' and 'Entity distance'
video settings"; it is a percentage slider scaling entity render distance.
[DOCUMENTED — Minecraft Wiki]
https://minecraft.wiki/w/Simulation_distance
*(A community write-up explicitly frames it: "This setting directly impacts client-side
performance … Setting the rendering distance to its maximum allows all entities to be
visually displayed at the full extent of their tracking distance.")* [COMMUNITY]
https://www.curseforge.com/minecraft/mc-mods/entity-distance-1-12-2
47. **Item entities are the other unbounded count driver.** No mod in the pack aggregates or
culls dropped items; a farm/hopper overflow or an explosion drops hundreds of
`ItemEntity`s, each costing an `ItemRenderer` submission and (with Better Leaves +
FA) potentially full model evaluation for held-block mobs. [INFERENCE]
48. **EMF/ETF+FA cost scales with *visible* model count, which EntityCulling and Entity
Distance both reduce.** Since `animationLODDistance` skips frames as a function of
distance from the player, `Entity Distance` and the LOD slider are multiplicative:
shrinking entity distance removes far models entirely, and the LOD slider makes the
remaining middle-distance models cheaper. [INFERENCE]
---
## Sources
Kept:
- EMF `EMFConfig.java` (master, v3.3.11) — authoritative list of every EMF config key and
defaults. https://github.com/Traben-0/Entity_Model_Features/blob/master/src/main/java/traben/entity_model_features/config/EMFConfig.java
- EMF `lang/en_us.json` — exact tooltip wording for `lod`, `low_fps_lod`, `large_mob_lod`,
`update`, `asmmaths`. https://github.com/Traben-0/Entity_Model_Features/blob/master/src/main/resources/assets/entity_model_features/lang/en_us.json
- EMF `CHANGELOG.MD` — 3.2 "doubling frames", 2.1.1 Iris shadow skip, 1.3/2.0 LOD
history, EmoteCraft integration. https://github.com/Traben-0/Entity_Model_Features/blob/master/CHANGELOG.MD
- EMF README — FA confirmed supported; EntityCulling recommendation.
https://github.com/Traben-0/Entity_Model_Features
- EMF issue #443 — quantified FA/shader cost, maintainer response.
https://github.com/Traben-0/Entity_Model_Features/issues/443
- ETF `ETFConfig.java` — all ETF keys incl. `textureUpdateFrequency_V2` enum ticks.
https://github.com/Traben-0/Entity_Texture_Features/blob/ETF-Main/src/main/java/traben/entity_texture_features/config/ETFConfig.java
- ETF README — emissive/Complementary conflict, "lagging" FAQ.
https://github.com/Traben-0/Entity_Texture_Features/blob/ETF-Main/.github/README.md
- LambDynamicLights `HOW_DOES_IT_WORK.md`, `DynamicLightsConfig.java`,
`DynamicLightsMode.java` (1.21 branch = v4.8.0, matching pack 4.8.11) — chunk-rebuild
cost model and exact keys/enums.
https://github.com/LambdAurora/LambDynamicLights/blob/1.21/HOW_DOES_IT_WORK.md
- EntityCulling `Config.java` + README — exact keys/defaults, tick culling, `solidLeaves`,
whitelist caveats. https://github.com/tr7zw/EntityCulling/blob/main/EntityCulling-Versionless/src/main/java/dev/tr7zw/entityculling/versionless/Config.java
- 3D Skin Layers README + `lang/en_us.json` + repo tree — 12-block LOD default, per-limb
toggles, EMF/playerAnimator integration.
https://github.com/tr7zw/3d-Skin-Layers/blob/main/src/main/resources/assets/skinlayers3d/lang/en_us.json
- Better Combat `ClientConfig.java` + client package tree — weapon trails default, animation
is per-Player.
https://github.com/ZsoltMolnarrr/BetterCombat/blob/1.21.1/common/src/main/java/net/bettercombat/config/ClientConfig.java
- Entity Player Compat mod page — EMF⇄playerAnimator conflict and its fix, 1.21.1 NeoForge.
https://modrinth.com/mod/entity-player-compat
- GeckoLib README — confirms absence of user perf config.
https://github.com/bernie-g/geckolib
- Minecraft Wiki (simulation distance) — Entity Distance affects client entity rendering.
https://minecraft.wiki/w/Simulation_distance
Dropped:
- `bravith.com`, `mythiq.net`, `skinmc.net`, `9minecraft`, `modbay`, `minecrafthub`,
`modrinth.com/mod/geckolib-animation-optimizer` (404) — SEO/aggregator pages; superseded
by the GitHub source I read directly. Used only where no primary source exists (GeckoLib
optimizer, Clumps, Emotecraft) and flagged as vendor/community claims.
- `lambdynamiclights.com/configuring-…` — cites config keys (`updateInterval`,
`lightSourceRenderRange`, `entitiesGlowing`) that **do not exist** in the 1.21-branch
source; treated as unreliable, kept only as an example of bad advice.
- Reddit threads on FA cost — replaced by the two mod-tracker issues which are primary and
quantified.
- ImmediatelyFast issue #180 — kept as a *caveat* only, not as an entity-cost source.
---
## Top levers (ranked)
| # | Lever | Expected impact | Fleet machine | Risk | Confidence |
|---|---|---|---|---|---|
| 1 | Confirm `animationFrameSkipDuringIrisShadowPass=true` in EMF on all 3 machines | **High** when shaders on (halves animation work) | P0, P2 (also P1) | None (default; wrong value is the bug) | High — VERIFIED default + maintainer "should always stay on" |
| 2 | Install **Entity Player Compat** (EMF+playerAnimator bridge) for the Better Combat / Emotecraft / FA-Player path | **High** on player-dense scenes; removes double animation of every visible player | P0, P2 | Med — third-party mod, unofficial fork; test for arm/armor desync | Med — DOCUMENTED mod page; mechanism plausible but percentage unverified |
| 3 | Lower EMF `animationLODDistance` 20 → 8–12 | **Med–High** in mob/animal areas | P0, P2 (CPU-bound); P1 mild | Low — visible low-framerate animations up close | High — VERIFIED semantics; magnitude needs A/B |
| 4 | Iris shader choice: shaders + FA is the dominant cost (issue #443: 110–130 → 30–40 fps) | **High** | P0 (RDNA2 iGPU) most, P1 (VRAM) too | Med — visual (loss of shaders on Deck) | High — consistent across two independent reports |
| 5 | LambDynamicLights `mode` `fancy` → `fast`/`fastest` on the CPU-bound boxes | **Med–High** where fires/burning mobs/held torches are common | P2 (main-thread bound), P0 | Low — slightly less responsive light | High — VERIFIED tick-mode mapping |
| 6 | LambDynamicLights `light_sources.entities=false` (keep `light_sources.self=true`) | **Med** in busy survival areas | P2, P0 | Low–Med (losing burning-mob glow) | High — VERIFIED key exists |
| 7 | EMF `modelUpdateFrequency` `average` → `slow`/`never` | **Med** in villager halls/farms | P0, P2 | Low | Med–High — VERIFIED key; magnitude unmeasured |
| 8 | Vanilla **Entity Distance** slider 100% → 75–80% | **Med** everywhere, scales all pipelines | All three, esp. P0 | Low | Med — documented mechanism, pack-specific magnitude unknown |
| 9 | ETF `textureUpdateFrequency_V2` `fast`(5t) → `average`(20t) | **Med** with random/variant packs | P0, P2 | Low — slower variant swaps | Med–High — VERIFIED ticks |
| 10 | GeckoLib Animation Optimizer (needs GeckoLib ≥4.9.0) | **Med** if GeckoLib mobs are common | P0, P2 | Med–High — third-party, can break animations | Low — vendor claim only, no independent test |
| 11 | Better Combat `isShowingWeaponTrails=false` | **Low–Med** | P2, P0 | Low (visual) | Med — VERIFIED key/default; magnitude small |
| 12 | Reduce 3D Skin Layers "Level Of Detail Distance" below 12 / disable 3D Skulls | **Low** (≤9 players, tightly bounded) | P1 VRAM-mostly | Low | Low–Med |
| 13 | EntityCulling `solidLeaves=true` in forested bases (Better Leaves present) | **Low–Med** in forests | All | Med — leaves stop occluding incorrectly / leaves may hide entities visually | Med — DOCUMENTED option, no pack-specific measurement |
| 14 | Verify Clumps is deployed **server-side** | **Low–Med** on XP-heavy scenes | All (indirect) | Low | Med — DOCUMENTED placement requirement |
---
## Open questions to verify by benchmark
1. **Is `animationFrameSkipDuringIrisShadowPass` actually `true` in the shipped `emf.json`/config?**
Cheapest possible check; if a pack preset or copy flipped it, every shader scene is
paying 2× animation.
2. **What is the real fps delta from EMF `animationLODDistance` 20 vs 8 vs 0-on vs LOD-off**
on a fixed FA mob cluster (e.g. 30–50 animals) on P0 and P2? Issue #443 gives the
magnitude for the FA/shaders *combination* but not for the LOD slider alone.
3. **Does Entity Player Compat measurably help on the 10-player server**, and does it break
FA: Player Extension or armor alignment? Requires ≥2 players within view, attacking.
4. **LambDynamicLights `fancy` vs `fast` chunk-rebuild count** — use the mod's own
`debug.display_dynamic_lighting_chunk_rebuild` and `debug.active_dynamic_lighting_cells`
options (both exist as keys) to count rebuilds per second, then correlate with 1% lows.
Also test whether `chunk_rebuild_scheduler=culling` is genuinely better than `immediate`
on Sodium 0.8.13.
5. **Do the LambDynamicLights `adaptive_ticking.slow`/`.slower` distances (5 / 8 chunks)
default interact badly with shaders?** Not covered by the mod docs beyond the tick-mode
description.
6. **GeckoLib entity share:** measure with a profiler how much main-thread time GeckoLib
models occupy on P2 (Mowzie's boss fights, Fowlplay birds, dragons). If it is <2 %,
GeckoLib optimizers are not worth the risk.
7. **ImmediatelyFast 1.6.14 vs FA All Extensions 1.8.1 (issue #180)** — does the pack
exhibit it? A/B entity visuals with ImmediatelyFast disabled.
8. **ETF emissive vs Complementary Reimagined built-in emissives** — which to disable, and
does disabling one measurably reduce frame time or just fix z-fighting?
9. **`solidLeaves` under Better Leaves 9.6** — measure in forested areas and inspect for
entities disappearing behind custom leaves.
10. **Entity Distance slider calibration** — find the % where mobs stop being visibly
affected at the pack's server view-distance 8 with Distant Horizons mandatory.
11. **Heap/GC effect on P2 (only ~8 GB free):** quantify the RAM cost of FA + FA All
Extensions + Best Leaves textures and EMF's model cache; test whether ETF
`advanced_IncreaseCacheSizeModifier` changes GC pause frequency (it trades RAM for CPU,
likely the wrong direction on P2).