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

37 KiB
Raw Blame History

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. EntityCulling (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
  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.)

  1. 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
  2. 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
  3. 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
  4. 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).
  5. 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)

  1. 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
  2. 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
  3. 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
  4. 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]
  5. 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

  1. 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
  2. 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
  3. 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.
  4. 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
  5. 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

  1. 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
  2. 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
  3. 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
  4. 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/
  5. 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
  6. 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

  1. 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
  2. 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
  3. 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]
  4. 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]
  5. 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]
  6. 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]
  7. 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

  1. 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
  2. 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
  3. 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 ItemEntitys, each costing an ItemRenderer submission and (with Better Leaves + FA) potentially full model evaluation for held-block mobs. [INFERENCE]
  4. 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:

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).