Repository navigation
Releases
Elder ENB 1.0.0-rc.5 (staging, attribution complete)
Attribution completion. Same build as rc.4 plus author lines on three shader headers that had none.
Staging build. Not tested in-game yet. Nexus will be the official release.
What changed since rc.4
Three files in Optional-EotE-Compositor/ carried no author line while every file beside them did: Helper/EotE_Tonemappers.fxh, Helper/EotE_ThemeSystem.fxh, and enbglobals.fxh. Silence about authorship in a folder where other files name their sources reads as third-party code, and these are first-party.
Every file in that folder now names an author or its references. Each line follows its own file's header convention rather than one style imposed across all three.
Bytecode is unchanged. These are comments, verified by compiling before and after.
Why they were missing until now
Earlier notes, and the handoff lineage those notes came from, described an "ENB of the Elders base preset" as an upstream third party whose stack Elder adapted. That was wrong: the preset is the author's own work. I held off filling in the three blank author lines while the record said otherwise, because asserting authorship a record does not establish is worse than recording that it is unknown.
The author confirmed it, so the gap closes. The handoff package's HANDOFF.md and MANIFEST.md have been corrected as well, and both quote the old wording and date the correction rather than rewriting it silently.
What is genuinely third-party is unchanged and still credited at the code that uses it: Boris Vorontsov for the ENBSeries framework, kingeric1992 for the adaptation auto-exposure and ALF lens flare, LonelyKitsuune / Skratzer for the bloom, sunsprite and ADOF bases, AMON ENB / Reforged for underwater, and Ottosson, Hill, Sobotka, Lottes, Therrien, Jimenez and Karis for individual techniques.
Everything else, unchanged from rc.4
The runtime plugin publishes a per-frame pulse, and the compositor's dither reads it so the pattern advances instead of sitting still. Only install Optional-EotE-Compositor/ if you already run the EotE preset: it is one of nine .fx files, and copying it over a different preset replaces that preset's main compositor. Users of other presets should read Docs/PRESET-INTEGRATION.md and make the same two edits to their own enbeffect.fx.
Without the plugin the dither is simply static, exactly as it was.
Verification
Native suite 17 passing, root suite 10 passing. The archive is deterministic across two runs and the shipped compositor compiles from the extracted archive layout with no external include path.
Not covered: the live SE, AE and ENB 0.504 acceptance gates, and whether the banding improvement is visible on a real monitor. Nobody has looked at this in game yet.
ElderENB-1.0.0-staging.zip sha256 125b57bc39fcaa5347872baec3a021429e011accfa7838d13e04ee9766ce744a
Elder ENB 1.0.0-rc.4 (staging, compositor ships)
The pulse-reading compositor now ships, so the dither improvement is installable rather than described.
Staging build. Not tested in-game yet. Nexus will be the official release.
What changed since rc.3
rc.3 added a shader that consumes the frame pulse, but Elder shipped no .fx files, so nothing in the archive actually read it. The compositor is now in the box.
Optional-EotE-Compositor/ contains enbeffect.fx and the five headers it includes. Two Elder changes: the runtime parameter is declared, and the interleaved-gradient-noise dither it already had is advanced by the frame counter so the pattern moves instead of sitting still.
Read this before installing it
Only install this folder if you already run the EotE preset.
The EotE stack is nine .fx files and this is one of them. Copying it into an enbseries folder belonging to a different preset replaces that preset's main compositor, which changes your whole look rather than just its dithering. That is why it is a separate opt-in folder and not under Root/.
If you use any other preset, read Docs/PRESET-INTEGRATION.md and make the same two edits to your own enbeffect.fx. It is about ten lines.
Without the runtime plugin the shaders still work and the dither is simply static, exactly as it was.
An authorship correction
Earlier notes and the handoff lineage described an "ENB of the Elders base preset" as an upstream third party whose stack Elder adapted. That is wrong, and the author has confirmed it: the EotE preset is his own work. The shader header and PROVENANCE.md are corrected.
What is genuinely third-party is unchanged and still credited at the code that uses it: Boris Vorontsov for the ENBSeries framework, kingeric1992 for the adaptation auto-exposure and ALF lens flare, LonelyKitsuune / Skratzer for the bloom, sunsprite and ADOF bases, AMON ENB / Reforged for underwater, and Ottosson, Hill, Sobotka, Lottes, Therrien, Jimenez and Karis for individual techniques.
PROVENANCE.md ships inside the compositor folder rather than staying in the repository, so the attribution travels with the files.
Verification
Native suite 17 passing. The archive is deterministic across two runs, and the shipped compositor compiles from the extracted archive layout with no external include path. With the plugin absent the dither offset is exactly zero and the output is bit-for-bit what it was, checked by compiling both: 44,936 bytes of bytecode with the wiring against 44,592 without.
Not covered: the live SE, AE and ENB 0.504 acceptance gates, and whether the banding improvement is visible on a real monitor. Nobody has looked at this in game yet.
ElderENB-1.0.0-staging.zip sha256 ae577eea8f7b1e6fcfdb89eda018bc03ecaacf298af51622fcfe7a7204788e59
Elder ENB 1.0.0-rc.3 (staging, dither consumes the pulse)
A shader now consumes the runtime frame pulse, so this build changes pixels.
Staging build. Not tested in-game yet. Nexus will be the official release.
What changed since rc.2
rc.2 wired the runtime to publish a per-frame pulse, and nothing read it. This adds the first consumer.
ENB writes eight bits per channel. A smooth gradient quantised at eight bits bands, and Elder's output bands worst exactly where it matters: night skies, fog, and the shadow rolloff the tonemap toe produces. ElderTemporalDither.fxh adds a sub-quantum offset before that write, which breaks a band edge into interleaved pixels of the two neighbouring levels. The eye reads that as the value in between.
What the pulse actually buys
The offset alone needs no runtime at all. A static ordered dither already removes banding, by averaging over space: sixteen neighbouring pixels land on both levels in the right proportion. That costs spatial detail, because the correct value only exists across a 4x4 block.
Advancing the pattern every frame recovers the value by averaging over time instead, at a single pixel. Nothing is traded away. That is the whole reason the pulse is worth publishing, and it is what the test asserts: one pixel visits more than one output level across four frames, and its temporal mean lands within half a level of the truth, where the undithered value never moves at all.
Without the plugin the effect still works, as a static dither. The shader never depends on the bridge being there.
Honest scope
This removes an artefact. It does not add a look. Elder is still not a preset that regrades your game, and if that is what you want, this is not that yet.
Two flaws the tests caught
The obvious Bayer normalisation carries a DC bias. Values 0/16 through 15/16 have mean 0.46875 rather than 0.5, so every offset was pulling about 0.03 of a quantum darker across the whole image. Centring the cell removes it exactly.
Rotating the pattern by offsetting screen coordinates does not work, and it fails quietly. Which cells a pixel visits then depends on where it sits: at pixel (9,5) the four phases gave 0.125, 0.3125, 0.1875 and 0.25, every one below the threshold, so a value halfway between two levels rounded down on all four frames and never dithered. The rotation is in value space now, which is position independent by construction.
Verification
Native suite 17 tests passing. The dither has its own suite plus a WARP parity probe: the shipped HLSL runs on a software device and is compared value by value against a C++ reference across every cell and every phase, because the Bayer table exists in both languages and duplicated constants drift. Parity is mutation-verified, changing one table entry in the HLSL alone fails it.
Not covered: the live SE, AE, and ENB 0.504 acceptance gates, and whether the banding improvement is visible on a real monitor. Nobody has looked at this in game yet.
ElderENB-1.0.0-staging.zip sha256 bff4f3c7cf4c79b5bc5ae625595ebb5b8bb923395ed9b43aa7b0a64683ab17ce
Elder ENB 1.0.0-rc.2 (staging, payload wired)
Transactional ENB profile and preset engine, a five-tier quality contract, and a runtime plugin that publishes live frame state to the shader stack.
Staging build. Not tested in-game yet. The Nexus upload will be the official release.
What changed since rc.1
The rendering payload is wired. In rc.1 the ENB callback was a deliberate no-op; the plugin attached, reported host status, and did nothing else. It now publishes a per-frame pulse the shader stack can read.
Every BeginFrame the plugin measures the frame, publishes through the neutral core, applies Elder's publication policy, and writes the result to three shader files as ElderRuntimeFramePulse: a wrapped frame counter, the frame delta in seconds, and the output dimensions. ElderRuntimeParameters.fxh ships alongside it and declares the symbol, with ElderRuntimeBridgeLive(), ElderRuntimeDeltaSeconds(), and ElderRuntimeOutputSize() as the reader surface.
What it still does not do is change the image. No shipped shader consumes the pulse to alter output. The bridge is built and running; what sits on top of it is the next piece of work. Installing this will not make your game look different, and that is stated on the mod page too.
Three behaviours that look like bugs and are not
A first frame publishes inactive. It has no previous timestamp, so its delta is unmeasured. Guessing one would put a fabricated pulse in front of shaders before anything real had been measured.
The inactive payload is written, not skipped. On a withheld or rejected pulse the plugin writes zeroes rather than leaving the last live value in place. Skipping the write would leave a stale live pulse visible after the bridge went away, which is the single failure this path exists to prevent.
An absurd frame delta is rejected rather than clamped. A debugger break or a long loading screen produces a delta the core refuses, and that frame publishes inactive.
Verification
Native suite 15 tests passing, root suite 10 passing. The frame driver is a pure unit with its own tests, deliberately kept out of the callback that runs on the render thread inside a live frame.
Both of its load-bearing contracts are mutation-verified: removing the first-frame guard fails the suite, and reporting a zero-size inactive payload fails it too.
Also in the box, unchanged from rc.1: five quality-tier preset trees at 50 INI files, byte-identical across two generations, and the native colour pipeline schema.
Not covered: the live SE, AE, and ENB 0.504 acceptance gates, which are game-bound and unrun, and any visual validation, since nothing consumes the pulse to change output yet.
Diagnostics
ElderEnbRuntimeFrameProbeV1 reports the published frame count, so a reader can tell a bound plugin from one that is actually driving frames. Added alongside the existing ElderEnbRuntimeProbeV1 rather than changing its signature.
License
MIT. Prior shader-author attribution in the headers is not waived by it.
ElderENB-1.0.0-staging.zip sha256 2f99fa1d7b640798cbec9367947d408740175da780dc62793fad02fcd1203781
Elder ENB 1.0.0-rc.1 (staging)
Transactional ENB profile and preset engine, with a native colour pipeline and a five-tier quality contract.
Staging build, and the least finished of the three. Read the next section before installing anything. The Nexus upload will be the official release.
The honest state
Elder's rendering payload is not wired. The runtime plugin attaches to ENB, resolves the host, and reports status so a diagnostics reader can confirm it is live and bound. Its render callback is a deliberate no-op. From the source:
Elder's rendering payload is not wired yet; the callback is a safe no-op so the plugin never destabilises a live ENB frame while attached.
So this archive will not change how your game looks. It is here so the preset trees, the quality contract, and the native schema can be reviewed, not because Elder is ready to use.
What is in the box and is real
Five quality-tier preset trees, 50 INI files, ten per tier: nine .fx.ini plus elder-quality.ini for performance, balanced, quality, ultra, and cinematic. Generated from a single canonical manifest (config/quality-tiers.csv) with fixed per-tier sample counts for AO directions and steps, SSR steps, DOF rings, bloom radius, lens ghosts, and room-light refinement. Generation is deterministic: the gate generates twice and compares sorted paths and bytes.
The native shader schema: generated ElderNativeParameters.fxh, a compiled reference object, the parameter manifest, and the default profile.
The runtime plugin, with the caveat above.
Verification
Native suite: 14 tests passing. Quality presets: five directories and exactly 50 INIs, byte-identical across two generations. The archive itself is deterministic, with fixed ZIP timestamps and a SHA-256 sidecar, verified byte-identical across two runs.
Not covered: the live SE/AE and ENB 0.504 acceptance gates, which are game-bound and unrun, and any visual validation at all, since there is no rendering payload to validate.
Attribution
Prior shader-author credits are preserved in the shader headers and Docs/NOTICE.md, and are not waived by the licence. No third-party shader source, decompilation output, or ENB binary is redistributed here.
Requirements
Skyrim SE or AE with ENBSeries. The runtime plugin pins enb-runtime-core at 543392f.
License
MIT. See Docs/LICENSE.
ElderENB-1.0.0-staging.zip sha256 94efc3301b22a4d1c46bb73c9c8baf010b599d2f01613db47f689491f3785285