1.0.0
Compatibility
Changes
Changelog
All notable changes to Potassium are documented here. This project follows Keep a Changelog and uses semantic versioning.
[1.0.0] - 2026-11-11
Stage 1 foundation for the visibility engine. Internal scaffolding only — no user-facing change.
Added
- New Minecraft-free
client.visibilitypackage, unit-tested independently of the game:VisibilityResult—VISIBLE/OUTSIDE_FRUSTUM/OCCLUDED/TOO_DISTANT/UNKNOWN. Only proven-hidden results may suppress drawing;UNKNOWNalways renders.VisibilityCategory—TERRAIN,BLOCK_ENTITY,ENTITY,PARTICLE,TRANSLUCENT,CUSTOM, each with independent counters.FrustumVisibility— a decision wrapper over the renderer's own frustum (supplied through an interface; no second frustum implementation). Invalid bounds or a missing frustum yieldUNKNOWN.ConservativeBounds— over-estimating particle bounds (rotated-quad diagonal, velocity/stretch, slack). Bad input returns "no bounds" so the caller renders.VisibilityStats— per-category plain-long counters (render-thread only).particle.ParticleClassifier— class-keyed, cached classification. Only the particle classes Potassium already treated as optional areAMBIENT; everything else, including modded particles, isCONSERVATIVE.
- 23 new pure-logic checks for the foundation (103 pure-logic checks total; 216 including regression).
Notes
- These classes are not yet wired into any mixin. No config keys were added and no in-game rendering, culling, or performance behaviour changes in this version — runtime behaviour is identical to 1.1.0. This is groundwork for the upcoming particle-frustum and terrain-visibility stages.
configVersionremains 2. Seedocs/STAGE1_V12_REPORT.mdfor the audit and the remaining plan.
Stage 1 improvements to the existing conservative culling. Verified in-game (standalone) on Minecraft 26.3.
Changed
- Entity culling order. Cheapest rejections run first (supported type before anything else), then the cache is consulted using the entity's own bounding box, and the renderer is only resolved when a fresh visibility test is needed. Renderer eligibility is cached per renderer class, never per instance. Ineligible entities are remembered as visible so they stop paying for renderer lookups.
- Allocation-free raycasting.
Occlusionno longer callsLevel.clip/ClipContextand no longer creates aVec3per sample. It uses an immutable fraction table (SamplePoints) and a bounded voxel traversal (VoxelRay). One small per-test tracer owns its mutable block position, so nothing mutable is shared. Partial shapes (slabs, fences, stairs) are still clipped exactly, so rays still pass through real gaps; anything unloaded or unverifiable fails open (renders). - Tiered sampling with best-first ordering. Centre ray first, then corners nearest the camera, then face centres for large/near boxes. Hidden still requires every sample of the tier to be blocked.
- Predictable raycast scheduler (
RayBudget). New per-frame cap (maxRaycastsPerFrame, default 64) on top of the existing per-window cap, with priority shares (near > approaching > large block entity > normal > distant). Budget exhaustion returns INCOMPLETE: the object renders and is retried within about a frame; it is never cached as hidden. - Adaptive cache lifetimes (
CacheLifetimes). Derived from the existingrecheckIntervalMs/beRecheckIntervalMs, so existing configs keep working: moving hidden 40 ms, static hidden 150 ms, moving visible 50 ms, static visible 150 ms, block entities 100-200 ms. Adaptive pressure only lengthens visible results; hidden results are never extended. - Movement thresholds.
cameraMoveThresholdandentityMoveThreshold(default 0.05 blocks) replace exact-equality invalidation for hidden results. Set both to 0 for the strict 1.0.0 behaviour. Entity-box size changes, terrain revisions and expiry still invalidate. Camera rotation is not an invalidation input because visibility is tested from the camera position, not the view direction. - Cache expirations are now counted separately from capacity evictions.
Added
- Stats: cache expirations, entity / block-entity invalidations, budget-incomplete tests.
PureLogicTests: Minecraft-free tests (scheduler, sampling tables, lifetimes, and a 20,000-world differential test of the voxel traversal against a dense-sampling reference).
Compatibility
configVersionis deliberately unchanged (2). New keys are additive, so a 1.1 config still loads in 1.0.0 (unknown keys are ignored) instead of tripping 1.0.0's "newer config" safe-defaults path.
First public release. Client-side performance mod for Minecraft 26.3 (Fabric, Java 25).
Added
- Conservative entity occlusion culling — skips rendering terrain-occluded entities using bounded raycasts and cached visibility. Only a limited set of vanilla mob types are occlusion-culled; other entities are left alone. Defaults to visible and under-culls rather than risk hiding something you can see.
- Chest block-entity culling — chests, trapped chests, and ender chests only; other block entities are untouched.
- Bounded LRU visibility caches with per-entry TTL sweeps and invalidation on camera, model, and terrain changes (no full-map "thundering herd" clears).
- Raycast workload budget — occlusion checks are capped per time window so worst-case CPU work stays bounded.
- Optional particle budget (a soft cap, not a hard wall) and optional distance-based particle culling, both configurable and disableable.
- Hardware detection + five profiles — Compatibility, Balanced, Performance, Maximum Performance, and Custom. A starting profile is suggested from GPU/system info as a heuristic, not a measured FPS guarantee. Automatic selection can be disabled.
- Optional adaptive workload management (off by default) — adjusts only Potassium's own optional work (particle budget, raycast budget, recheck interval) to help hold a target FPS. Suspends in menus, while paused, and when the window is unfocused.
- Unfocused-window throttle — optional background FPS cap to save CPU/GPU and power.
- FPS counter (color-coded, top-left, hidden with F1/F3) and an optional right-aligned detailed diagnostics HUD.
/potassium statsand/potassium stats resetclient commands. The required Fabric API modules (fabric-command-api-v2,fabric-api-base) are bundled in the jar, so only Fabric Loader is needed at runtime.- Real frame-time diagnostics — rolling frame window with average FPS, worst frame, and
spike count; true 1% and 0.1% low FPS (shown as
n/auntil enough frames are sampled); JVM process CPU usage, allocation rate, and garbage-collection counts/time. - Sodium integration — Potassium options appear in Sodium's config screen when Sodium is installed, with truthful tooltips.
- Mod compatibility handling — detects Sodium, Lithium, Iris, EntityCulling, ImmediatelyFast, and Sodium Extra. Potassium's occlusion culling disables itself when Iris or EntityCulling is present to avoid conflicting visibility/shader decisions.
- Config schema versioning (v2) with safe fallback to conservative Compatibility defaults on a corrupt or unreadable file; all budgets/limits clamped to safe ranges.
Safety guarantees
- Never changes resolution, render distance, or simulation distance.
- Never silently changes shader settings.
- Never alters world simulation or gameplay, and never disables important rendering.
- Quality reductions are never presented as "free" optimizations.
Known limitations
- Occlusion uses finite sampling, so it under-culls rather than risk popping visible entities.
- With Iris or EntityCulling installed, Potassium's occlusion culling steps aside.
- GPU utilization is not measurable from the JVM and is reported as
n/a; GC collector time is labeled as collector time (not pause time); cache memory is a JVM-layout estimate. - No benchmarked speedup is claimed. Controlled, repeatable benchmarks are in progress; any
gain depends on hardware, world, and settings. Use
/potassium statsto measure locally.
Requirements
- Minecraft 26.3, Fabric Loader >= 0.19.3, Java >= 25. Client-side only.
License
MIT. Author: Doveblond.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:zPIpacEu:zKSgjVHM"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:zPIpacEu:zKSgjVHM"
}

