heuristic): a candidate needs a real station AND to persist across
confirmScans scans before it shows. Raised minScore 30→40.
BaseFinderModel: online logistic regression over an 11-dim feature vector
per candidate. User labels via a clickable [Yes]/[No] chat prompt
(RUN_COMMAND sentinel intercepted+cancelled in PacketEvent.Send — never
hits the server); once ≥15 labels, P(base) gates visibility. Weights +
dataset persist to basefinder-model.bin (streamed BinaryConfiguration),
IO/training off-thread on a ProfileThread.
Compiles on 1.21.4-fabric + 1.21.8-fabric (ClickEvent version split).
config — Fastutil primitive-list getters + use in BaseFinderModel mistake67
details
Every getList gains a factory overload + a fastutil variant (getIntArrayList/getLongArrayList/…/getBooleanArrayList) alongside the boxed convenience method, mirroring the existing getFloatList shape. Section delegates added. BaseFinderModel loads via getFloatArrayList/ getIntArrayList with primitive access (no boxing on the load path).
hud — Per-axis anchor positioning + reposition all modules mistake67
details
Root cause of both HUD bugs was persisting position as a single top-left fraction with no anchor: right/bottom intent was lost on save and resize re-derived the edge heuristically.
HudModule: persist a per-axis anchor (NEAR/CENTER/FAR) + gap-fraction
instead of pos.fx/fy. deriveAnchor on deliberate moves (drag release,
arrow, snap, reset); applyAnchor on resolve/resize and each fastTick when
not dragging (FAR/CENTER track the live size). scaleToResolution now
deterministic from the stored anchor (drops the bindAxis heuristic).
Legacy pos.fx / pos.x still read.
Arraylist: draw side follows anchorX()==NEAR, not a re-derived left-edge;
removed the manual posX writeback (FAR anchor pins the right edge against
the live width) → no more left-flip after restart / content resize.
Reposition all HUD module constructor defaults to the user's arranged
layout (converted from config anchor+gap at 1130x686). Keystrokes+Cps
share BOX_W so they pair as a stacked column.
Apply via R in the HUD editor. Compiles on 1.21.4 + 1.21.8.
ai — Hybrid CVAE engine — server online, dev-addon models offline mistake67
details
Runtime AI modules (CrystalAura, AuraCvae, AnchorMacro, TriggerCvae, AimCvae) used NetworkCvaeEngine, which only works with a live server session — in dev / offline there was no inference at all.
Add a CvaeEngine interface (NetworkCvaeEngine now implements it) and a HybridCvaeEngine that routes: server when SessionManager.canReachInference(), else an addon-supplied local engine via the LocalCvae/LocalCvaeProvider SPI. The runtime stays ONNX-free — the dev addon that ships the models registers the provider on enable.
addon — Fold CVAE lab into acfingerprint + local inference provider mistake67
details
The CVAE model stack (generators, OnnxEngine, models, CvaeLabModule) now lives in the acfingerprint dev addon instead of a separate cvae addon. Renames the addon's off-thread guard CvaeEngine -> CvaeRunner (the runtime SPI interface now owns the CvaeEngine name) and adds AddonCvaeProvider, which builds a local ONNX-backed engine per model key and registers into the runtime LocalCvae registry on addon enable — so dev/offline runtime AI modules fall back to these bundled models. AcFingerprintAddon now also registers CvaeLabModule.
Removes the standalone cvae addon (settings + runClient addon lists).
Models stay dev-only (this addon) + server; the runtime ships ONNX-free and the local fallback is gated to non-injected dev builds, so customer models never leave the server.
ai — AcFingerprint as runtime module, classifier on server + dev addon mistake67
details
Applies the model-module split to the AC fingerprinter: the module now lives in the runtime (client, customer-facing, ONNX-free) instead of the dev addon, and its classifier model stays server-side + in the dev addon — never in the runtime jar.
Runtime AcFingerprintModule: feature extraction stays; inference goes through
HybridCvaeEngine ("acfingerprint" key) — server when a session is live,
dev-addon classifier when offline (dev-only gate). Registered in ModuleManager.
Server InferenceService: ClassifierBundle (features [1][F] -> probs [1][C]),
carried by the existing generic InferenceTransaction; classifier_nn.onnx added
to server resources.
Addon: OnnxClassifier + an "acfingerprint" spec in AddonCvaeProvider supply the
local classifier; the addon keeps the model + CVAE lab and no longer registers
the AC module.
Verified in dev: 75 modules (AcFingerprintModule now runtime-registered), addon loads clean, no duplicate.
Wayla: shows the block (name + registry id) or entity (name + health)
under the crosshair via mc.hitResult, in a rounded panel; collapses to
zero size when nothing is targeted. Registered in ModuleManager.
Coordinates: gate the dimension portal-link on !onlyY — with only-Y there's
no X/Z to convert, so the N/OW conversion is dropped.
hud — WAYLA draws block icon / TargetHUD-style entity mistake67
details
Living entity under the crosshair → avatar + name + distance + smoothed health bar (mirrors TargetHUD, player preview while editing). Block → its item icon + name (+ registry id). Collapses to zero size otherwise.
hud — TargetHUD latches last target until dead/despawned or >10 blocks mistake67
details
Previously the panel vanished the instant the combat target cleared. Now it persists the last living target and only drops it when the entity dies/is removed or moves past 10 blocks (distinct from Wayla, which follows the live crosshair).
finder — Shared scan + rich features + multi-class model; structure mask mistake67
details
Unifies the BaseFinder / StructureLocator stack (core ~90% scope):
FinderScan: one shared crafted BlockSearch + a single block-entity pass, producing a 40-dim
feature vector per candidate chunk — block-entity counts (§1), block composition / man-made ratio
(§2), chest clustering + geometry (§3), global coords (§6). Owns the block-weight/veto tables
Deferred (documented in the plan): hybrid pretrained ONNX prior blend (needs a trained model + a batch/sync inference path — the single-slot async engine doesn't fit N-candidate classification), farm detection (§4) and new-chunk/temporal (§5), structure subtype label classes.
on CategoryDef; getEntries/valueOf/ordinal -> CategoryRegistry all/get/index.
finder — FinderCore — shared sites/dedup/dataset/labeling + structure prompts mistake67
details
Shared pipeline behind BaseFinder + StructureLocator: candidate → site dedup (structure-mask grouped else large-radius super-cluster, different types never merge → nested-safe), the on-device FinderModel (macro .bin) gating at site level (one waypoint per structure), the fine-grained FinderDataset (JSONL, dev-only) for a future ONNX model, and a two-step label prompt over the ~23-class FinderLabel taxonomy (base/farm/natural + exact vanilla structure types).
FinderLabel: 23-class taxonomy; macro() collapses to the 5-class .bin model.
FinderDataset: append-only finder-dataset.jsonl, one row per member chunk, streamed off-thread.
StructureMask.Type → FinderLabel (seeds the prompt); StructureLocator.registerStructure feeds sites.
StructureLocator detections are pre-typed but NOT auto-labeled — they prompt on sight so the user
confirms/corrects the type (labeling reads accumulated features at click time).
BaseFinder thinned to drive FinderCore; the old per-chunk model/labeler moved into the core.
finder — Loose finding + SERVER_SPAWN label; trim BaseFinder settings mistake67
details
Finding now stays deliberately loose and leans on FinderCore site dedup (anti-spam) + the model rather than hand-tuned geometry — once the ONNX is trained it can gate on the model alone.
Drop the geometry/threshold settings (minScore, minFunctional, confirmScans, planarity, verticality,
Add a SERVER_SPAWN label class (macro NOT_BASE) + a [Spawn] prompt button — a server hub/lobby is
player-built but not a raidable base, so it trains as a reject yet stays a distinct, filterable class.
finder — Trial-chamber + mineshaft detection, structure multiselect, fast label cmd mistake67
details
StructureLocator now scans the overworld too: trial chamber (trial_spawner/vault/breeze exclusive,
copper-bulb + tuff-brick palette refines) and mineshaft (cave spider exclusive, or the rail+cobweb
combo only mineshafts generate). Both feed StructureMask + FinderCore like the existing structures.
New ListSetting "Structures" — multiselect which structures to detect (fortress/bastion/
end_city/trial_chamber/mineshaft); each scan + its BlockSearches gate on it.
SUPER_RADIUS 64→96 so a sprawling village stays one site.
Faster dev labeling for the /locate + /tp workflow: `/aurora bflabel ` labels the nearest site
without the chat prompt (FinderCore.labelNearest); FinderLabel.parse accepts names + short aliases
(fortress/trial/monument/mansion/outpost/spawn).
finder — One-click [Yes] to confirm a pre-typed structure label mistake67
details
A structure detection prompts with its type pre-filled ("trial chamber? at x,z"). Add a leading [Yes] button that labels it directly as the suggested type, so confirming a correct detection no longer means digging through the [Struct…] submenu.
finder — [TP] button in the label prompt mistake67
details
Add a [TP] button that runs the real /tp to the site's coords (keeps current Y) so the labeling workflow can jump to a detection before confirming it.
Dev labeling loop for the many-worlds workflow: `/aurora bfauto ` sends /locate structure, intercepts the reply, parses the coords, /tp's there, waits for the finder scan, then labels the nearest site with the mapped fine class. ~18 structures mapped (trial, mineshaft, village, fortress, bastion, monument, mansion, outpost, city, stronghold, desert, jungle, igloo, hut, portal, shipwreck, trail, endcity). One command per structure per world replaces the manual locate+tp+label steps.
finder — Dungeon detection (spawner + chests) as a labelable POI mistake67
details
Add a DUNGEON class + detection: StructureLocator flags every overworld mob SPAWNER (one dungeon per spawner, deduped within MERGE_DIST), gated by the new Detect.DUNGEON target. Plain "spawner" is removed from the FinderScan veto (only worldgen-exclusive blocks like trial_spawner/vault still veto) so the dungeon's chest gives the site crafted features to label + train on. A mineshaft-corridor spawner can be retyped MINESHAFT from the prompt.
finder — Ancient-city detection (reinforced deepslate + sculk) mistake67
details
Add ancient city to StructureLocator's overworld scan: reinforced_deepslate is city-exclusive and sculk catalyst/shrieker mark the deep dark, so any of them triggers an Ancient City pin (wide 160-block bbox for the sprawl). New Detect.ANCIENT_CITY target + StructureMask.Type; feeds the mask + FinderCore like the other structures.
math — Striped-lock concurrent primitive collections + wire hot paths mistake67
details
Add a small family of thread-safe primitive collections in dev.aurora.math.list, built like ConcurrentHashMap (N independent fastutil segments, each under its own monitor) so concurrent access scales without boxing the key/element the way a Map/Set would:
Single-key ops are atomic on their segment; bulk ops (size/iterator/forEachEntry/ entrySet) are weakly consistent per-segment snapshots (never throw CME), matching ConcurrentHashMap semantics. Maps add remove(k,value) atomic, removeIfKey(pred), and forEachEntry(primitive callback) so hot reads avoid key boxing entirely.
Wire the client concurrent hot paths that previously used boxed ConcurrentHashMap: - WorldSystem.pendingScan (Long->LevelChunk) and BlockSearch.byChunk (Long->long[]): off-thread scan writes + render-thread reads, now key-boxing-free. The per-frame inRange() read and the drain loop use forEachEntry; pruneRetained uses removeIfKey. - BedrockCrackerModule.survivors (Set, mutated by parallel workers) -> LongConcurrentOpenHashSet.
Int variants (IntConcurrentOpenHashSet, Int2ObjectConcurrentOpenHashMap) ship for completeness; their candidate call sites are server-side (SessionRegistry.killedLicenses, admin SSE emitters) which don't yet depend on :util:math/fastutil — not wired here.
addons — Per-license opt-in — user chooses which addons to download mistake67
details
Addons are no longer force-delivered to every entitled client. They are now opt-in per license (default: none):
License gains a nullable `addon_optin` CSV column (+ LicenseCodec round-trip,
backward-compatible decode for pre-existing cached blobs).
AddonStore.resolveAll takes the enabled-name set and skips any addon not
listed; AuthService parses license.addonOptin and short-circuits when empty.
Dashboard (/dashboard) gains an "Addons" section: checkboxes for each active,
non-dev addon, htmx-posting to POST /me/addons (MeController), which whitelists
names against the active catalog, stores the CSV, and invalidates the license
cache so auth re-reads at next login.
devaddon is hard-excluded from the selectable set (dev-only model carrier).
DB migration: `ALTER TABLE licenses ADD COLUMN addon_optin TEXT` (applied on VPS).
modules — Port 20 features from mods.txt (combat/inventory/HUD) mistake67
details
Add InventorySystem (SystemManager.inventory()) as the shared choke point for container-menu slot ops (swap/offhand/quick-move) via handleInventoryMouseClick, one-click-per-tick gated.
New modules, all registered in ModuleManager, combat swaps reuse the shared humanized RangeSetting jitter (AITiming/RandomizationProfile):
Drop *.aurora.kts / *.kts files in aurora/scripts/ to hook client events with a small DSL (name, onEnable/onDisable, onTick, onRender2D/3D, onPacketReceive/onPacketSend) and direct client API access (mc/player/world/renderer/config/chat via InstanceAccessKt). Scripts compile once at startup via the Kotlin Scripting API and register their listeners; reload without restart via F6 keybind or `.scripts reload`.
Per-script teardown uses the existing event-bus container model (ScriptEventHolder with fixed nullable @LinkEvent Listener fields → subscribe/unsubscribe by owner) — no api change needed.
The Kotlin compiler/host (~40MB) is downloaded on-demand into aurora/libs (SHA-1 verified against Central) and appended to the game classloader; kotlin-reflect is bundled in the skeleton since the stdlib reflection factory resolves at launch. Compile classpath is assembled at runtime from CodeSource anchors (dev) / a temp jar rebuilt from the in-RAM runtime (prod).
ModuleMounter exposes runtimeResources() + appendLibraries() via AuthBoot; ScriptManager wired into AuroraClient postInit/shutdown.
modules — Group C batch 1 — AutoRun, NoJumpDelay, ScrollTweaks mistake67
modules — Group C — SnapTap (null movement) mistake67
details
Last-pressed of an opposing movement pair wins; the older key is suppressed so counter-strafing registers instantly instead of cancelling to zero. Press order tracked from KeyboardEvent; suppression applied in LocalPlayerMixin's aiStep isDown redirect (before the real-down check). 1.21.4 path; 1.21.8 Input record wiring is a follow-up.
Compiles clean on 1.21.4-fabric.
client — Wire all client events into the scripting DSL mistake67
details
Extend the .kts DSL beyond tick/render2D/render3D/packets to the full client event set: onWorldTick, onRenderEntity, onRenderBox, onKey, onMouse, onAttack, onDeath, onMotion, onUseBlock, onConfigLoad, onConfigSave. Cancellable events (attack/key/mouse/motion/useblock/ packets) expose the live event so scripts can e.cancel().
AuroraScript now collects simple-event handlers in a Class->handlers map (multiple handlers per event, easy to extend); ScriptEventHolder wires one uniform @LinkEvent field per event via a reified fan-out helper, keeping per-script subscribe/unsubscribe teardown. Verified end-to-end in dev (runActiveClient): all 17 hooks compile, load, and enable clean.
modules — Group C — Freecam (detached camera) mistake67
details
Camera flies free with WASD/jump/sneak while the real body stays put. CameraMixin.setup TAIL overrides the camera position with the module's fly coords; LocalPlayerMixin suppresses the player's movement/jump/sprint keys while enabled so the body never moves. Rotation stays shared with the mouse. 1.21.4 path (body suppression via the isDown redirect); 1.21.8 Input-record wiring is a follow-up.
Compiles clean on 1.21.4-fabric.
modules — Group C — FreeLook (decoupled camera rotation) mistake67
details
Mouse rotates the camera while the body stays facing where it was (movement follows the frozen body). MouseHandlerMixin redirects the LocalPlayer.turn call in turnPlayer into the module's camera-rotation accumulator; CameraMixin.setup applies it via setRotation. Distinct from Freecam (position vs rotation detach). 1.21.4 path.
Compiles clean on 1.21.4-fabric.
modules — Group C — Scaffold (rename LegitScaffold + auto-place) mistake67
details
Rename LegitScaffold -> Scaffold and add a Mode setting: Sneak (the original legit edge-shift), Place (auto-place the held block under the feet, edge-sneak kept on), Tower (place under feet while holding jump to rise). Placement goes through InteractionSystem.place (one raw action/tick, no prediction bounce).
Compiles clean on 1.21.4-fabric.
modules — Group C — PingSpoof (delayed keep-alive) mistake67
details
Delays the client's ServerboundKeepAlivePacket reply by a configurable ms so the server-measured latency (shown in tab) reads higher. Re-injected replies are tracked in a passthrough id set so they're not re-delayed. Scheduler owned by the module (created on enable, shutdown on disable). Cosmetic ping spoof only.
Compiles clean on 1.21.4-fabric.
modules — Group C — MultiKey (alt keys for vanilla actions) mistake67
details
Bind an alternate key that mirrors a vanilla keybind (jump/attack/use/sprint/ sneak). While the alt key is physically held, the target KeyMapping is forced down (PRE) and released (POST) — a true hold, so sprint/attack behave normally. KeySetting per action, -1 = unbound.
Completes Group C. Compiles clean on 1.21.4-fabric.
scaffold — View-line place targeting from bridging-mod mistake67
details
Port bridging-mod's PathTraversalHandler targeting into Place mode: walk the reach line from the eye, take the first air cell that has a view-aligned solid face to build off (validSides = directions whose normal opposes the view), and place against that face — real directional bridging instead of only dropping a block under the feet. Tower mode keeps the under-feet column place. Still one gated place() per tick.
Compiles clean on 1.21.4-fabric.
freecam — Independent look + momentum model from MinecraftFreecam mistake67
details
Freecam now decouples camera rotation from the body (mouse diverted into the module like FreeLook, applied via CameraMixin.setRotation) so the body stays frozen in position AND facing while the view flies and looks freely. Movement follows the camera yaw with the MinecraftFreecam motion model: sprint 1.5x, diagonal normalisation, separate vertical speed. 1.21.4 path.
Compiles clean on 1.21.4-fabric.
autotool — Rate weapons by real attack damage mistake67
details
Replace the hardcoded Mace>Axe>Sword class order with the item's actual main-hand ATTACK_DAMAGE modifier (via the ATTRIBUTE_MODIFIERS component), the metric Fabric-Autoswitch uses. Now respects tiers and damage-boosting components (netherite axe 9 > sword 8 > mace 7 …) instead of guessing by class. Tool selection keeps getDestroySpeed; still one selectSlot per humanized delay.
Compiles clean on 1.21.4-fabric.
client — Register ServiceRegistry + EventSystemPort as interface keys mistake67
details
client-api Phase 0: expose the DI registry and the event bus by their api interfaces (ServiceRegistry, EventSystemPort) in the service registry, so addons/scripts can resolve them by contract instead of the concrete ServiceManager/EventSystem. Concrete keys stay for impl callers that use implementation-specific methods. No behavior change.
autototem — Scan the whole inventory, not just the hotbar mistake67
details
Match better-auto-totem: pull a totem into the offhand from anywhere in the inventory (slots 0-35) instead of only the hotbar, via a SWAP-to-offhand click (button 40) with the correct menu index. Still gated (one click/tick) and humanized-delayed.
Port shieldbreaker's detection: require the target to be actively using a SHIELD item and — crucially — facing us (horizontal relative dir · target look < 0.5), since a shield only blocks within a front cone. Replaces the coarse isBlocking() check, so we no longer axe-swap when already behind their guard.
Compiles clean on 1.21.4-fabric.
modules — Align batch 1 to real mod sources mistake67
details
Faithful behavior ports (actions still gated, one-per-tick, humanized delays): - AutoRun (Emonadeo/AutoRun): cancel on manual back/left/right input with an activating guard; suppress auto-jump while active. - ScrollTweaks (MicrocontrollersDev): add reverse + prevent-overflow + skip-empty options matching the mod's config. - InventorySort (ClientSort): comparator = creative-search-tab order → count desc → id, empties last; pre-sort quick-stack merge pass; unchanged one-click/tick driver. - Nametags "Name pain" (namepain): smooth green→red name lerp vs 3 buckets. - HitRange (uku3lig/hitrange): color the box by in-reach (3.0) vs out-of-reach. - FuelInfo (Luligabi1/FuelInfo): show smeltable-item count from the fuel slot + cook %. - PearlDetector (Tektonikal): skip own pearls (getOwner), optional ding on new pearl.
Compiles clean on 1.21.4-fabric.
modules — Align batch 2 to real mod sources mistake67
details
Crosshair (custom-crosshair): Shape enum (cross/plus/dot), gap + thickness
settings, center dot; kept target recolor.
ReachDisplay (reach-display/player-reach-display): measure to the target
hitbox nearest point and latch the reach on the actual attack (CombatStats
lastEntityHit), hold ~2s, instead of jittering every frame.
MaceOptimizer (maceoptimiser/mace_optimizer): gate the mace swap on the real
smash predicate (descending, fallDistance>1.5, !fallFlying, target on ground).
FastXP (fast-xp/auto-fast-xp): proper Mending enchantment detection with
heuristic fallback; round-robin over all damaged mending pieces.
MultiKey (multi-key-bindings): extend alt-key mirroring to movement/drop/
swap-hands/inventory keys too.
HotbarOptimizer left as our layout rearranger (real Dokko mod is a slot re-sync tool, a different feature). Actions stay gated/one-per-tick; delays humanized.
Compiles clean on 1.21.4-fabric.
elytraswapper — Full-inventory swap from source mod mistake67
details
Port ElytraChestplateSwapper faithfully: search the whole inventory (main → offhand → hotbar) for the elytra/chestplate, pick the swap direction from what's worn on the chest slot, and run the vanilla three-click armor swap (pickup source → place chest slot 6 → place back). Chestplate detection uses the EQUIPPABLE component (chest slot). Clicks are queued and drained one gated click/tick — no same-tick burst — replacing the hotbar-only single SWAP.
Compiles clean on 1.21.4-fabric.
pearloptimizer — Client-side pearl prediction (real feature) mistake67
details
Reimplement PearlOptimizer as the actual cutebow Pearl Optimizer feature — client-side throw prediction — instead of the quick-select stand-in. On a local pearl throw, EnderpearlItemMixin spawns a ClientPearl (a ThrownEnderpearl with a negative entity id) that flies immediately, removing the throw-to-render latency. ClientWorldMixin.addEntity suppresses the real server pearl owned by the player so only one is ever shown; the predicted pearl removes itself on client-side impact. PredictedPearls owns the buffer, negative-id allocation, cooldown and clear. Moved to the optimizations package. 1.21.4 mappings.
Reimplement PotionOptimizer as cutebow's real Potion Optimizer feature — client-side throw prediction — instead of the quick-select stand-in. On the outgoing use-item packet for a splash/lingering potion, spawn a ClientPotion (negative id, correct potion colour via setItem, thrown at the vanilla -20° pitch) so the arc renders with no latency; ClientWorldMixin.addEntity now also suppresses the real server potion owned by the player. Triggered off the packet rather than a potion-item mixin to stay version-robust. Moved to the optimizations package.
Replicate the visual side of LukenSkyne/Minecraft-Ping-Wheel: raycast where you look (entity or block, up to a Range), then render an in-world ping as a screen-projected marker — scaled by distance (2/dist^0.3, closer = larger), labelled with its distance, following a pinged entity, and clamped to the screen edge when off-view. Screen projection is done in the R3D pass (world PoseStack) and the draw deferred to the 2D pass, mirroring Nametags. Local/visual only — no team net-sync. Replaces the waypoint-pin stand-in.
Compiles clean on 1.21.4-fabric.
fuelinfo — Also show remaining smelt time mistake67
details
Add a "Time:" line to the furnace tooltip alongside the fuel-item count, matching the real FuelInfo mod's timer: remaining ticks on the item currently cooking plus a full cook for every other item in the input slot, divided by the level tickrate and formatted mm/ss. Reads the menu's cook/lit sync data via a new AbstractFurnaceMenuAccessor.
The custom crosshair was drawn on top of the vanilla one (double crosshair). GuiMixin now cancels Gui.renderCrosshair while the Crosshair module is enabled (1.21.4 path). The crosshair itself is more detailed: shapes dot/plus/T/circle, an optional dark outline for contrast on bright terrain, plus the existing length/gap/thickness/center-dot/target-colour options.
Compiles clean on 1.21.4-fabric.
fuelinfo — Faithful port of Luligabi1/FuelInfo algorithm mistake67
details
Match the original mod's exact fuel + timer computation (Apache-2.0, attributed): consumed fuel ticks (data[0] + currently-burning item) with blast/smoker special-furnace /100 vs /200, plus fuel-slot burn duration → item count; timer from cook progress (data[3]-data[2]) + remaining input stacks over the level tickrate. SHIFT shows the raw item count / current-item time only. Adds a recipeType accessor to detect special furnaces.
Compiles clean on 1.21.4-fabric.
client-api — Scaffold public interface module (contracts) mistake67
details
client-api Phase 1 (additive slice): new :client-api module (dir client/api) holding the impl-free contracts addons + scripts compile against — ClientModule (extends Toggleable), ModuleRegistry, Notifier, and the ClientApi entrypoint that resolves everything through the bound ServiceRegistry.
Plain MC-free JVM module for now (depends only on :feature:service:api + :feature:module:extension:api); the MC-typed surface (events, RendererPort, AuroraScript DSL) relocates here in a later slice. Nothing consumes it yet — purely additive, no impl/addon files touched. Builds standalone.
multikey — Copy the real mod — vanilla Key Binds screen, not a module mistake67
details
Reimplement multi-key-bindings faithfully instead of the Aurora module: bind EXTRA physical keys to any vanilla KeyMapping via a "+" button on each row of the vanilla Key Binds screen (KeyBindsListKeyEntryMixin) — click it, then press the key/mouse to add (press an already-bound extra to remove; Escape cancels, KeyBindsScreenMixin does the capture). Extra keys drive their action through KeyMappingMixin (KeyMapping.set → held state, click → on-demand count). Bindings persist to config/aurora-multikey.txt (MultiKeyBindings / MultiKeyCapture). Removes the MultiKey module + its ModuleManager registration.
Compiles clean on 1.21.4-fabric. The Key Binds screen mixin (KeyEntry shadows / render / children override) applies against 1.21.4 internals — verify in-game.
Consume :client-api from the mod: compileOnly in the runtime, JIJ'd (implementation+include / jarJar) in the skeleton so its contracts are on the game classloader. AuroraClient now binds ClientApi to the live service registry at init and registers NotifierImpl (delegates to Notify) under the Notifier interface — so addons/scripts can call ClientApi.notifier() without importing dev.aurora.util.Notify.
ModuleRegistry wiring deferred (ModuleManager is under concurrent edit). All four variants compile.
client-api — Implement ModuleRegistry, Module is a ClientModule mistake67
details
Module now implements the slim client-api ClientModule contract (it already had name()/description() + Toggleable, so zero new methods; dropped the clashing category() from ClientModule). ModuleManager implements ModuleRegistry, delegating register(ClientModule)/unregister to the existing register(Module) path. AuroraClient registers ModuleManager under the ModuleRegistry interface.
Addons/scripts can now: ClientApi.modules().register(myModule) where myModule extends the runtime Module base — no dev.aurora.impl.* import needed. All four variants compile.
client-api — IDE script-definition marker for autocomplete mistake67
details
Add META-INF/kotlin/script/templates/dev.aurora.clientapi.script.AuroraScript to the client-api module so IntelliJ discovers the AuroraScript .kts template. This works now (unlike the earlier same-module attempt): the template lives in :client:api, a dependency of the project, and IntelliJ scans module dependencies for script-definition markers, then applies the definition to standalone .kts project-wide — giving scripts full autocomplete + type inference. README updated with the one-time reload/invalidate steps.
Add the fishing-rod bobber cast from maDU59/ptp ProjectileInfo — its own launch vector + spawn offset, GPD physics order, water-aware — completing the per-item 1:1 port (only crossbow-multishot omitted; needs a version-fragile enchant lookup). ProjInfo/Trajectories compile clean on BOTH 1.21.4-fabric and 1.21.8-fabric (verified: 0 errors in trajectories on either variant); uses only stable APIs + literals, so no stonecutter conditional needed.
scripts — .kt authoring harness for reliable autocomplete mistake67
details
IntelliJ's custom-.kts resolution keeps failing for this multi-module Gradle setup (the definition/marker in the client-api dependency isn't picked up). Ship ScriptDraft.kt instead: an ordinary Kotlin class extending AuroraScript in a source root, so the editor gives full autocomplete + type inference for the DSL. Write the logic in its init { } block, then copy the body into a *.aurora.kts. The class is never instantiated/registered — no runtime effect.
bettercam — OLD hurt-cam type (betterhurtcam 1:1) mistake67
details
Add the distinctive BetterHurtCam feature our port lacked: the OLD hurt-cam type — zero the hurt direction (LivingEntity.hurtDir) in GameRenderer.bobHurt via a WrapOperation so the tilt always shakes the same way (classic, non-directional) instead of pointing at the damage source. Complements the existing disable (NoHurtCam) + strength (tiltStrength) which already match the mod's toggle + multiplier. require=0 so it's optional per MC version. Compiles clean on both 1.21.4-fabric and 1.21.8-fabric.
crosshair — More shapes (square/triangle/arrow) from CCM style set mistake67
details
Match wjbaker Custom Crosshair Mod's style variety: add SQUARE, TRIANGLE, and ARROW (corner-bracket reticle) to the existing DOT/PLUS/T/CIRCLE, with a small Bresenham line helper for the diagonal edges. Keeps gap/thickness/outline/ center-dot/target-colour + the vanilla-crosshair hide. Compiles clean on both 1.21.4-fabric and 1.21.8-fabric.
GuiMixin now @WrapMethod's Gui.renderCrosshair: when the Crosshair module is on
it draws ours in place of vanilla's (correct layering, no double crosshair,
respects hideGui/perspective automatically) and calls the original otherwise.
Works on both 1.21.4 and 1.21.8 (same renderCrosshair signature) — dropped the
1.21.4-only guard and the separate R2D listener; the module exposes draw(g).
DRAWN shape: a fully hand-drawn pixel crosshair, pixels persisted as a string,
edited in a new CrosshairEditorScreen (zoomed grid, click a cell to toggle,
saves on close). Opened via the module's Edit key.
Compiles clean on 1.21.4-fabric and 1.21.8-fabric.
reachdisplay — 1:1 Player-Reach-Display port (displayMode + keep/reset) mistake67
details
Match kikijiji/Player-Reach-Display 1.21.8: eye->clamped-bbox hit distance (already present), plus DisplayMode (NUMBER_ONLY/WITH_BLOCKS/WITH_M), keepLastHitDistance vs resetAfterSeconds latch, and idle "0.00" render. Stable APIs only — no 1.21.4/1.21.8 conditional needed. Both variants 0 errors.
namepain — 1:1 Name Pain port — health-tinted vanilla name labels mistake67
details
Port naqaden/Name Pain: recolour the vanilla entity name label (text + plate) by the entity's health, lerping nameMax/plateMax (full) -> nameMin/plateMin (near death) via the reference labelPalette math. Applied in EntityRendererMixin.renderNameTag with a WrapOperation on Font.drawInBatch: faded SEE_THROUGH pass -> {textFaded, backColor}, NORMAL front pass -> {textColor, 0}. Entity recovered per-instance via a new WorldSystem state->entity map (entityForState). renderNameTag/drawInBatch are identical mojmap on 1.21.4 and 1.21.8 — no conditional. Both variants 0 errors.
Rewrite PearlDetector to match the reference mod: enlarge thrown ender pearls (pearlScale) and render them fullbright, plus a sound the moment a pearl spawns within [minDistance, maxDistance] of the eye (age<1, once per pearl). Scale + light applied in new ThrownItemRendererMixin (WrapOperation on PoseStack.scale, getBlockLightLevel->15), pearl identified via WorldSystem state->entity map + EntityType.ENDER_PEARL — version/loader-agnostic, no pearl-class import (fixes the old 1.21.8-breaking ThrownEnderpearl import). skipOwn retained. Client-only, no packets. Both variants 0 errors.
scrolltweaks — Match microcontrollers/ScrollTweaks — add Disable, faithful defaults mistake67
details
Add disableScroll (block hotbar switching by scroll) to complete the real mod's option set (disable / reverse / preventOverflow). Default skip-empty (an Aurora extra) to OFF and only intercept the scroll when a tweak is active, so with defaults the wheel behaves exactly like vanilla. selectSlot still routes through the action gate. currentSlot already dual-version (getSelectedSlot/selected). Both variants 0 errors (verified in isolation; tree also has unrelated broken staged files from a concurrent session).
autorun — Faithful emonadeo/autorun port — multi-direction latch mistake67
details
Rework AutoRun to match the reference: latch whatever movement direction(s) are held at toggle (forward if none) and drive all four movement keys, not just forward. Add alwaysSprint + activate/deactivate chat message, and flip auto-jump to ENABLE-while-running (restore on disable) to match the mod (was suppressing). activating-guard + opposite-axis physical-override cancel ported 1:1. Drives the vanilla key-mappings directly — real movement, no packets, works on 1.21.4 and 1.21.8 (Input record reads the same keys). Both variants 0 errors.
shieldbreaker — Faithful ahmet/shieldbreaker port — reactive axe-swap mistake67
details
Rewrote from an autonomous auto-attacker (fired every tick on any shielded LivingEntity in the crosshair) to a 1:1 reactive port of ahmet/shieldbreaker: it hooks the player's OWN attack via AttackEvent and only assists when you attack a shielding player.
Target must be a Player, alive, non-spectator, actively using a SHIELD, and
facing us (horizontal look·relative < 0.5 cone — source isBlockedByShield).
attackDelayTicks setting (default 2, range 0-15); preDelay = delay/4.
preDelay <= 0 (incl. default): swap to the hotbar axe now and let the vanilla
attack proceed this tick with the axe held; restore the slot after delay ticks.
preDelay > 0: cancel the vanilla attack, wait preDelay ticks for the swap to
land, then fire the attack ourselves (raw, gate-claimed) and restore.
Swap goes through interaction.selectSlot and the re-attack through interaction.attackEntity, so a tick still costs at most one inventory packet + one action packet — never two actions. Dual-version via currentSlot() conditional (getSelectedSlot 1.21.8 / selected 1.21.4). Both variants compile clean.
Switchback: record the slot held before the swap; when you stop swinging, wait
switchbackDelay (default 1) ticks then restore it. Retries if the inventory gate
is busy that tick so the restore never silently drops (uses selectSlot's bool).
Don't switch in creative by default (instabuild) — toggle to re-enable.
Optional don't-switch-while-sneaking.
Selection still happens on the rising edge only (never mid-dig, never interleaved with the attack/dig packet); the swap is an inventory packet, so a tick still costs at most one inv + one action. Dual-version currentSlot() conditional. Both compile.
Our ElytraSwapper already matched saphjyr/ElytraChestplateSwapper2's core 1:1 (same scan order main->offhand->hotbar, worn-based direction, three-click armor swap) but was AC-safer: the source fires all three PICKUP clicks in one tick, we drain one gated click per tick. The one behavioural gap was the trigger — the source swaps on each key PRESS (SwapKeyBinding, default GRAVE), while ours only swapped on module enable (so re-swapping meant toggling off/on).
Extracted the swap into doSwap() and bound it to a momentary swap KeySetting (default GRAVE_ACCENT, like the source), guarded by enabled(). Each press now swaps while the module stays on. Both variants compile.
Our InventorySort already matched terminalmc/ClientSort's default CREATIVE order (creative search-tab position, then desc count, empties last) plus the stack-fill merge pass, drained one gated click per tick (AC-safe vs ClientSort's atomic payload/burst). The scope was the gap: it only sorted the player main inventory, while ClientSort sorts whichever inventory the cursor is over.
Now sorts every menu slot backed by the hovered slot's Container, so it works on open chests / barrels / shulkers as well as the player inventory (falling back to the player main slots 9-35 when nothing is hovered). Added an AbstractContainerScreen accessor for the protected hoveredSlot; clicks now go through clickSlot on the open containerMenu (was inventoryMenu-only), and the sort planning is parameterised over a target slot-index list. Version-agnostic (getContainerSlot / hoveredSlot identical on 1.21.4 and 1.21.8). Both variants compile.
New module (kept the existing swap-based MaceOptimizer, a different mod). Faithful port of cutebow/MaceOptimizer's client-side smash predictor: on a mace hit the vanilla predicate says will smash (MaceItem.canSmashAttack), immediately play the smash sound (GROUND if the target is grounded, else AIR) and spawn the impact + ring particles locally, then suppress the duplicate smash sound the server echoes back (within 14 ticks and 25 blocks^2 of the prediction). 4-tick prediction cooldown, exactly as the source.
New module (the existing FastXP is a different mod: mending-repair via hotbar round-robin, kept as-is). Faithful port of modid/fast-xp + itamio/auto-fast-xp: while right-click is held and a throwable is in hand, re-use it every throwDelay ticks. fast-xp throws any ProjectileItem (default), auto-fast-xp only XP bottles — covered by the "XP bottles only" toggle. Main hand takes priority, then offhand. throwDelay default 2 (fast-xp's default), range 1-20.
Each throw is the tick's single gated action (interaction.useItem), so a busy tick just skips — never two actions in a tick. keyUse.isDown + ProjectileItem + swing are all version-stable, no stonecutter conditionals. Both variants compile.
clickcrystal — Port itzispyder/ClickCrystals click-crystal — left-click places crystals mistake67
details
New module. While you hold attack with an end crystal in hand and look at a crystal base (obsidian/bedrock with a free space above), left-click places a crystal there instead of mining. Faithful to the source's click-crystal bind (intercept the dig, place a crystal on that block).
Adapted to our action rules: the source cancels the START_DESTROY_BLOCK and places inline; we split it so PacketEvent.Send only CANCELS the dig (no reactive send in a Send listener) and the placement runs from the tick loop via the gated InteractionSystem — one place per tick, never a dig + place together. Version-stable API (ServerboundPlayerActionPacket, Blocks.OBSIDIAN/BEDROCK), no stonecutter conditionals. Both variants compile.
Ports the intent of luavixen/lupin-mace3d (a 3D model for the Mace) in an architecture-correct way for Aurora, without copying that mod's all-rights-reserved code or model/textures.
Because the runtime jar is loaded in RAM, MC's resource manager can't see its assets — so the model ships in the on-disk bootstrap resource pack instead. On 1.21.4 and 1.21.8 the item-model definition at assets/minecraft/items/mace.json points the vanilla Mace at a custom model; assets/aurora/models/item/mace_3d.json is ORIGINAL placeholder geometry (a simple handle + head, vanilla mace texture) meant to be replaced. No mixin, no version conditional — the resource pipeline handles both variants.
To finish: drop your own model geometry into mace_3d.json and your textures under assets/aurora/textures/item/ (update the "textures" keys to point at them).
projectileaim — Client-side analog of bizcub/auto-aim — ballistic bow aim-assist mistake67
details
bizcub/auto-aim is a datapack, not a Java mod: its working part /damages entities within 2 blocks of a flying arrow (server-only), and its "real-aim" rotation set is unfinished scoreboard-math WIP. A client can't apply /damage, so the faithful analog is aim, not auto-hit.
ProjectileAim solves the launch angle for the held projectile weapon and rotates toward it so shots land. Reuses ptp's ProjInfo launch physics (per-item speed / gravity / drag / step order) to simulate the arc, scans launch pitch for the flattest angle that hits the target's height, aims yaw straight at it, and drives the shared RotationSystem (SERVER-only = silent by default). Engages only while actually using the projectile (drawn bow/trident, loaded crossbow, right-click held on a throwable) and only for a target in range within the FOV cone. Optional velocity lead. Reuses TargetSystem.select for target picking. Version-stable API, no stonecutter conditional. Both variants compile.
Reviewed our Crosshair against custom-crosshair-mod + the crosshair-indicator mods and closed most of the gap. Added:
Transform: scale, rotation, offset X/Y (applied around centre; PoseStack on 1.21.4 /
Matrix3x2fStack on 1.21.8 via stonecutter conditional).
Separate colours: base colour, outline colour, dot colour (were hardcoded).
Center dot on any shape (dot_enabled), its own colour.
Rainbow cycling (speed configurable).
Dynamic attack-cooldown gap spread (dynamic_attackindicator): gap widens toward
at 0% charge, closes at 100% via getAttackStrengthScale.
Per-type target highlight: hostile / passive / player colours (was one red flag).
Conditional visibility: hide with HUD (F1), hide in third-person, hide while scoping.
Version-stable except the pose transform (conditional). Both variants compile.
Still not ported (documented gaps): width/height split (scale covers it), adaptive/invert colour (needs a framebuffer read), and the bow/projectile/item-cooldown/tool-damage ring indicators.
Add new shader files for visual effects including glow, smoke, and glass mistake67
Add Handoff documentation for dual-version mod porting process (#2) mistake67
Enhance object pooling and improve event handling in rendering mistake67
Implement object pooling for MutVec3d and optimize rendering performance with caching mistake67
Implement ConfigurationSection interface and enhance serialization methods mistake67
Improve Configuration serialization mistake67
Update serialization methods to use ConfigurationSection + Change ColorSetting to int color mistake67
Introduce OptionalFloat and FloatSupplier classes for enhanced float handling mistake67
Implement ActionBus for managing action priorities and locks mistake67
Enhance WindLaunch module with improved jump timing and refill prevention mistake67
Enhance ShieldBreaker and AutoSwitch modules with improved target detection and state management mistake67
Implement event-driven attack handling in ShieldBreaker and AutoSwitch modules mistake67
Redesign plan/addon system with per-license entitlement grants mistake67
details
Plans now bundle addon products (join table + bundleAllAddons flag for Developer-tier); addons are priced SKUs (AddonProduct) purchasable separately from a plan; per-license entitlement moves from a single addonOptin CSV to license_addons grant rows with independent expiry (PLAN-sourced follow the base license, PURCHASE-sourced carry their own). AuthService resolves effective addons as the union of active grants and the license's plan bundle. Admin gains addon-product CRUD, plan bundle editing, and per-license grant management; the member dashboard's addon section becomes read-only (entitlement is staff/plan driven, not self-opt-in).
Plan-scoped optional addons with combo discount pricing mistake67
details
Plans gain an explicit "optional addons" list (distinct from bundled free addons) plus a bundleDiscountPercent — the landing shows each purchasable extra's own price and, when 2+ are offered together, a combo price (sum minus discount). Staff can now grant multiple addons to a license in one submission (shared source/expiry) to mirror a combo purchase; entitlement itself is unaffected — the discount is display/staff-pricing only, no payment integration.
Plan choice-pool addons — pick N free of a pool mistake67
details
Plans can now offer a "pick N free" pool distinct from unconditional bundled addons and paid optional extras — e.g. Starter lets you choose 1 of {Survival, Crystal} at no cost. Staff pick the free one(s) when creating/editing a license (validated server-side against the plan's pool, capped to its free-pick count); the unchosen pool member stays purchasable like any optional addon, discounted by the plan's existing combo %. Landing shows the pool with each item's discounted "add it too" price.
Make choice-pool upsell price staff-editable, suggest weighted avg mistake67
details
Plan gains an explicit choiceUpsellPriceCents staff sets on the plan editor; the landing uses it verbatim. When unset it falls back to a price-weighted average of the pool (Σprice²/Σprice) instead of a plain mean — weighting each item by its own price pulls the fallback toward the pricier pool member, which the plain average undercorrected for. The admin form shows that computed average as a hint next to the price field so staff has a starting point.
Hide addon-detail fields when "Bundle ALL addon products" is checked mistake67
details
Included/choice/optional addon pickers and their discount/price fields are already ignored server-side once bundleAllAddons is true — hide them client-side too so staff isn't editing dead fields. Toggles on checkbox change and re-syncs after htmx panel swaps.
Addon bundles — special packages sold/granted as one unit mistake67
details
New AddonBundle SKU (+ AddonBundleItem members), independent of Plan and its addon relations (included/optional/choice-pool). New "Bundles" tab in Catalog with create/edit + member picker. Staff can grant a bundle to a license in one submission — it expands to individual license_addons rows for each member (same source/expiry), so entitlement resolution never needs to know bundles exist.
Fixed a pre-existing gap while wiring this in: grantsResult() (the htmx swap after add/remove) never populated purchasableProducts, only detail() did — harmless before since th:each tolerates a null collection, but adding a th:unless="...isEmpty()" check for bundles throws on null. Both paths now share addGrantFormContext().
Hide addon-detail fields when "Bundle ALL addon products" checked mistake67
details
Follows the existing syncLifetime() delegated-listener pattern: toggles display:none on .addon-detail-section blocks (included/choice/optional pickers + bundle discount field) within the checkbox's form whenever .bundle-all-toggle is checked, resynced on htmx:afterSettle so it stays correct across panel re-renders. The catalog.html hook classes landed via a concurrent commit; this is just the toggle logic.
Dedicated /pricing page; live upsell hint; addon jar-link indicator mistake67
details
New public /pricing page (nav link added): full plan detail (edition/
addon products + addon bundles in one place, all previously missing
from the compact landing teaser (which now links out to it). No
checkout — same Discord/`/me` CTA as everywhere else.
The choice-pool "add another" price hint (price-weighted avg) now
recomputes live client-side as staff checks/unchecks pool addons in
the plan form, instead of only reflecting whatever was last saved.
AddonProduct (SKU) and Addon (jar) are linked only by matching name,
with nothing surfacing that link before now — a typo silently shipped
a product no client would ever receive. Products tab gains a name
autocomplete (datalist of uploaded jar names) and a "Linked jar" /
"no jar" badge per row.
Mutually exclusive plan-addon groups + live upsell placeholder mistake67
details
An addon could previously be included AND in the choice pool AND optional at once, all three purchase paths contradicting each other. Checking a box in included/choice-pool/optional now disables it in the other two (client-side, per plan form); server-side reconcile enforces the same precedence (included > choice > optional) at save time regardless of JS. The "add another" price suggestion (price-weighted avg) now also writes into the price input's placeholder live, not just a separate hint line, so staff sees the number right where they'd type an override.
Auto-detect mixin config from uploaded jars instead of manual entry mistake67
details
Staff had to retype the mixin config filename by hand on every addon upload even though it's already inside the jar. Reuse the same convention the client's dev-addon mount already scans for (top-level *.mixins.json entries — ModuleMounter.scanMixinConfigs) at upload time in both AddonStorageService and ReleaseStorageService: blank field → auto-detect from the jar just written; a typed value still overrides for non-standard layouts. Runtime releases pick this up too even though their admin form never exposed the field.
Auto-fill addon-product display name from the SKU name field mistake67
details
Split on hyphens, capitalize each segment's first letter, join with a space ("crystal-pvp" -> "Crystal Pvp", "survival" -> "Survival"). Only fires while Display name is still empty, so it never overwrites a manually-typed value. Delegated listener so it survives the Products tab's htmx panel swaps.
AddonProduct.requiresAddonName lets one addon require another already be on the license before it can be granted — checked in LicenseController.addGrant against existing non-expired grants union'd with the current submission batch (so granting both together in one go still works). Blocked attempts are skipped (not partially granted) with a staff-visible notice; admin product form gets a "Requires addon" picker + a resolved-name column showing it.
Show dependent addons attached to their requirement on public pages mistake67
details
An addon with a requirement (e.g. "Seed Finding" requiring "Survival") used to show as its own flat line in Included/Choice-pool/Optional, misleading since it may not actually be delivered (entitlement now enforces the dependency at grant time). Suppress it from the flat list and render it inline next to whichever list its requirement lands in instead — "Survival (+ Seed Finding)" — on both the landing teaser and the full /pricing page.
Graphify mistake67
Implement seamless crystal prediction and enhance inventory action handling mistake67
Integrate Discord IPC for real-time presence updates and add JitPack repository mistake67
Implement Discord bot with message listener and IPC integration mistake67
Enhance message handling in BotListener to filter bot messages and add reply functionality mistake67
Port bactromod features (Fog, ItemScale, pumpkin-blur, riptide-shield fix, boat-map), add system-overrides browser, fix hand-swap/slider bugs mistake67
details
New Fog module (per-fog-type toggles, default off) + FogRendererMixin
New ItemScale module (dynamic per-item first-person scale) + ItemScaleScreen
Splits game-mode-specific modules out of the monolithic client:client runtime into separate purchasable addons, mirroring the existing seedfinding/survival addon pattern. Core keeps only shared HUD/VISUALS/UTIL/SYSTEMS modules.
ProjectileAim + their mode/blatant/cvae helper subpackages
Mace: MaceSwap, WindLaunch
HitBox's core render-mixin hooks (entity render dispatcher/renderer) moved into the Combat addon's own mixin package instead of a core-side interface, so core has zero dependency on addon module classes and addons keep full ownership of their mixin logic.
Also fixed pre-existing folder/category mismatches: Clicker and AutoSwitch were BLATANT/OPTIMIZATIONS-categorized code living under those folders but declared UTIL — moved to util/. BetterCam was OPTIMIZATIONS-folder but VISUALS-flavored — recategorized and moved. All 12 VISUALS-category modules lived under render/ with no dedicated folder — split into a new visuals/ package so folder and category always agree.
deploy.sh now deploys crystal/combat/mace alongside seedfinding/survival; devaddon stays excluded (pre-existing guard — ONNX models must never reach customers).
catalog — Description on addon + bundle cards, admin-editable mistake67
details
AddonProduct + AddonBundle: new nullable `description` column (ALTER-ADD migration).
Admin catalog: description textarea on both create + edit forms (AddonProductController
/ AddonBundleController accept it; row views carry it for prefill).
Public cards: pricing shows the addon description (falls back to the generic blurb when
unset) + bundle description; landing shows the shown-bundle description. Hidden when blank.
landing — Living aurora-curtain hero backdrop mistake67
details
Add a Canvas aurora behind the landing hero — green/cyan/violet ribbons drifting via layered sine fields + additive blend + blur, over the existing brand-page night bg (transparent canvas, ambient only). Absolute + top-anchored + 100vh so it scrolls away with the hero instead of bleeding behind content sections, masked to fade before the fold; z-index below content. Reduced-motion paints one still frame. Reuses the existing --au-grad palette; adds a soft glow to the gradient headline. Additive — touches only landing.html + landing.css.
Restructure the public landing while keeping the aurora identity: - Keep the centered/symmetric hero; add a soft scrim + brighter lead so the copy reads over the aurora ribbons; seamless palindrome shimmer on the accent word. - Move the real in-client ClickGUI (fragments/clickui) up as a showcase right under the hero. - Replace the bento + AI band with three alternating feature rows; keep the copy vague (benefit bullets, no module names or bypass mechanics). - Keep loaders/versions, data-driven pricing tiers and bundles unchanged.
dashboard — Unify the member/admin shell — gradient nav marker, coherent frame mistake67
details
Finish the shared dashboard shell (same page for /me and admin panes): gradient active-marker on the member category nav, centered status LEDs, coherent card radii on the profile + nav cards. Builds on the profile/tier/ops2 restyle so the member account, ClickGUI, Overview and admin panes all sit in one cohesive aurora frame. CSS-only, bindings untouched.
Replace the left sidebar with a horizontal tab bar (category tabs + profile
chip on the right) and full-width content; dropped the Account/Manage group
labels. All htmx/sec bindings on the tabs preserved.
Account pane rebuilt to the approved mockup: full-width license hero (plan
name + subscription LED + stat strip), a 2-column grid for downloads /
add-ons / bundles / linked accounts, and a full-width Manage-plan block.
Channel select, addon toggle, bundles JSON and subscription flows unchanged.
client — Personal AI adaptation — behavior profiling + nav core mistake67
details
Phase-1 personal adaptation: an invisible off-thread system that observes movement/camera/input and builds a per-player behavioural profile, kept as a labelled multi-player dataset.
HitProfile lets AimAssist/KillAura/RotationProfile pick weighted hit points (head/torso/etc) with per-point jitter/miss chance instead of a single scalar pitch range, edited via a new SideScreen (HitPointScreen) opened from all three modules against the same shared profile.
Also generalizes the AimAssist override pattern (local-setting + Overrides.bind/pick) into reusable RotationOverrideBundle / TargetOverrideBundle / CombatOverrideBundle, applied to KillAura (new: full rotation-override parity) and TriggerBot (moved Cooldown/MissChance/Filter overrides up from per-mode duplication).
util — Make Enum2*Map implement java.util.Map like fastutil does mistake67
details
Fastutil's primitive collections implement the standard JDK interfaces (boxing only at that boundary); the Enum2*Map family was standalone-only, which stops it from being passed anywhere a Map is expected. All 8 now implement Map: primitive put/get/remove/containsKey/forEach still avoid boxing entirely, the new Object-typed Map methods box only when called through that interface. keySet()/values()/entrySet()/equals/ hashCode/toString delegate to a materialized EnumMap snapshot (not a live view). Renamed the primitive forEach to forEach (forEachInt, ...) since it's otherwise ambiguous against Map's default forEach(BiConsumer) for any method-reference/lambda call site.
client — Drive AITiming CVAE pace from HUMAN click-rate mistake67
details
Complete the Phase-1 adaptive-output pass ([#1](https://github.com/Mustache-Client/aurora/issues/1)). Split applyToHumanization: - applyRotationSmoothness: HUMAN camera speed -> RotationProfile.smoothness (per-frame easing = turn-speed proxy; unchanged behaviour). - applyAiPace: HUMAN click-rate -> AITiming.speed shared CVAE pacing. A faster natural clicker drifts the generated dt toward a quicker pace; floored at 0.6 so adaptation alone never reaches blatant cheat-pace (the user's Speed setting still bounds it). Set as a +/-0.02 band around the eased target so the generator keeps jitter.
Both ease at EASE=0.10 per drain (drift over sessions), gated by the `adapt` setting (default off).
RotationProfile.noise (aim wobble) is a final immutable Range -> not drivable without touching the shared combat file; deferred.
Turn the nav core's computed routes into real humanised movement (Phase-2 #2).
nav/PathExecutor: main-thread walker. goTo(x,y,z) computes the route (bounded
node cap) and tick() follows it one waypoint at a time — faces each via
RotationSystem.request (the smooth aimer eases the yaw like a human turn) and
drives PositionSystem.request(vel, NORMAL, collide=true) so it clamps walls and
auto-steps 1-block rises. Ground speed is paced by the player's own measured
movement style (BehaviorSystem.embedding()[MOVEMENT_SPEED], 0.14..0.28 b/t).
Jumps on grounded step-ups; advances on arrival; stop()/arrived() end it.
SystemManager: tick nav.tick() BEFORE movement.position().update(e) so the
requested velocity is consumed the same tick; accessor nav().
impl/module/behavior/AutoWalk (UTIL): dev trigger — paths to the block you're
looking at, auto-toggles off on arrival/lost-route. Registered in ModuleManager.
Compiles; in-world verification pending (aim at a spot, toggle AutoWalk, watch the player walk there without phasing walls).
client — PathExecutor moves via vanilla input (simulation), not raw velocity mistake67
details
Rewrite the executor to press the vanilla movement keys (keyUp / keySprint / keyJump) and let the game's own travel() physics carry the motion, instead of setting raw velocity. Collision, wall-slide, 1-block auto-step, friction and acceleration now come out exactly vanilla — smooth and anti-cheat-safe (server sees ordinary key-driven walking, no illegal deltas). Body yaw is eased toward the waypoint via RotationSystem(BOTH) so the walk curves in; sprint gates on the player's measured movement style. Keys released on stop/arrival.
groundspoof (spoof onGround in the outgoing move packet) noted as a follow-up — would need a move-packet mixin, no hook exists yet, and vanilla-physics movement doesn't need it to be smooth.
client — AutoWalk moves via legit input (keyPresses), anti-cheat-safe mistake67
details
Replace the velocity override (same PositionSystem path Flight/Speed use — the server sees a teleport vs the empty input packet and flags it) with real input. PathExecutor now only sets a forward/jump/sprint intent; LocalPlayerMixin folds it into ClientInput.keyPresses + forwardImpulse via an @Inject right AFTER the vanilla input.tick() in aiStep. That record is what travel consumes AND what sendPosition ships as the ServerboundPlayerInputPacket, so the server simulates the same walk — legit, no flags. Confirmed in-world ("è legit"). No keybind is mutated, so the player's own WASD stays free.
Earlier failures were wrong injection points (aiStep HEAD / KeyMapping.isDown / a separate ClientInput.tick mixin that never took); the surviving spot is post-input.tick in the always-applied LocalPlayerMixin.
Movement still rough (corner overshoot, no accel/stop easing) — quality follow-up stands, but it's legit input now, not a flagged velocity hack.
client — AutoWalk movement polish — string-pull, sprint-gate, stuck-recovery mistake67
details
String-pull: skip ahead to the farthest waypoint reachable in a straight,
same-level, body-clear line (walkableLine samples passable feet+head + solid
floor). Kills the zig-zag on diagonal runs → smoother turns.
Sprint-gate: drop sprint when the turn from the current heading exceeds 45°, so
the walk doesn't overshoot corners.
Stuck-recovery: when distance to the waypoint stops shrinking, escalate —
jump at 12 ticks (missed step-up), re-path once at 30, abort at 70.
WorldBlockSource is lazily built (resolving SystemManager.world() in the field
initializer NPE'd — the executor is constructed as a SystemManager field before
client — Action capture — attack/use/switch into the behavioural profile mistake67
details
Close the biggest replication gap: actions were only ever modelled as raw click/key aggregates. Capture three action signals on the MC thread, labelled HUMAN/HEURISTIC/GENERATED like motion: - attack: left-click while the crosshair is on an entity (vs a block break), - use: right-click (use/place), - switch: selected-hotbar-slot change (detected in BehaviorSystem.update — the mouse listener can't see scroll/number-key switches). Counters drain each cycle → FeatureExtractor rates → three new PlayerProfile features (ATTACK_RATE / USE_RATE / SWITCH_RATE, appended after KEY_RATE so the embedding layout stays stable). Physical → HUMAN for now; source-labelling automation-driven actions is a follow-up. Persisted automatically (serialize iterates Feature.VALUES). Embedding is now 12-dim.
First step of the roadmap's data layer (A). Next: temporal windows (B).
client — Temporal windows — sequence capture for the generative feed mistake67
details
Aggregates (EMA) throw away order, so they can fingerprint a player but can't reproduce HOW they move. Add fixed-length temporal sequences alongside: - MotionFrame: compact per-tick frame (horizSpeed, turnMag, sprint/sneak/jump), packed to 3 floats. - TemporalWindow: LEN=40 frames (~2 s at 20 tps), immutable, flattens to a float list for persistence / model input. - PlayerProfile: a bounded newest-wins reservoir (16 windows) per InputSource, addWindow/windows accessors, persisted as _win list-of-float-lists. - BehaviorSystem.drain: accumulate the batch's ordered frames per source and cut a tumbling window every LEN frames into the profile.
Aggregates stay the fingerprint; windows are the generative feed (per labelled source, so HUMAN windows drive replication). Roadmap data layer step B.
E — movement finish: ease the final approach (walk, don't sprint, within 2.5 blocks of the goal so we settle on the block) and don't sprint while descending >1 block (less ledge overshoot).
F — goal modes on AutoWalk: Coords (path to a set X/Y/Z) and Follow (look at an entity to lock it, then chase — re-paths every 20 ticks / on arrival, stops within 2.5 blocks, ends when the target dies/leaves), alongside the default crosshair-block mode. NumberSetting X/Y/Z + Boolean Coords/Follow.
client — AutoWalk goToSafe — snap goal to a standable Y (coords/follow) mistake67
details
Coords with a wrong height found no route (the exact block wasn't standable). Add PathExecutor.goToSafe: scan the (x,z) column for the nearest standable spot (feet+head clear, solid floor) to the requested Y and path there; if the column isn't standable at all, reach it at whatever floor the pathfinder finds (Navigator.pathToColumn → Goal.xz). Coords + follow now use goToSafe, so a rough Y still routes. Digging-to-goal (baritone-style) is deferred — needs break-block actions + anti-cheat handling (Phase-3).
client — Safe reversible adaptation (G) mistake67
details
Make the profile→humanisation nudge safe to enable: - Maturity gate: only adapt once the HUMAN vector has warmed up (obs >= WARMUP_OBS), so knobs never drift from a cold/noisy profile. - Snapshot + restore: capture the user's original RotationProfile.smoothness and AITiming.speed before the first nudge; restore them exactly when adapt is turned off (handled in setAdapt and in the per-tick update transition). Adaptation is now fully reversible — the user's tuning is never silently lost.
The "learns your style" seam, option (a): ProfileConditioning.condition(seed) prefixes a CVAE seed matrix with the current player's HUMAN embedding as leading rows, so a retrained server model could condition generation on the player.
Deliberately NOT wired into NetworkCvaeEngine.poll: prepending rows the current Tier-S model doesn't expect would change the seed shape and break decode (-> skeleton mode) for the combat modules using the CVAE today. Kept a pure, verified-shape helper with no callers; wire it in behind a capability flag ONLY once the server model reads the prefix. Server-retrain is the blocking dependency (D, the replication driver, is blocked on the same).
client — Fold action edges into motion frames (temporal windows carry actions) mistake67
details
Temporal windows held movement only. Tag each MotionSample with the tick's action edges (attack = entity left-click, use = right-click) via pending flags the next motion sample consumes, and pack them into MotionFrame bits 3/4. Windows now keep action + motion together in order — the sequence a generative/replay model needs to reproduce not just how you move but when you hit/use.
Roadmap A/B enrichment (least-complex first).
client — Mimic — local replicator of your recorded look style (D-lite) mistake67
details
The generative model is server-blocked, so replicate the player from data we already have. Frames now carry the personal camera signature — signed per-tick dYaw/dPitch (added to MotionSample/MotionFrame; window STRIDE 3→4) — not just a turn magnitude.
New Mimic module (UTIL): samples the active player's HUMAN TemporalWindows and replays them — integrates the recorded signed deltas into a moving look target driven through RotationSystem (humanised, server-consistent) and swings on attack frames. The client looks/flicks like YOU, from real captured sequences, no model. Needs data: play with Adaptation on first so HUMAN windows populate.
Movement-trajectory replay is a follow-up (frames hold scalar speed, not a path). Roadmap D-lite done; full D (goal-directed generative behaviour) still needs the server model.
client — Mimic replays movement cadence too (jump/sneak/sprint), not just look mistake67
details
Deepen the replicator: while the player is actually walking, overlay their recorded jump/sneak/sprint rhythm from the sampled HUMAN window. Mimic sets a movement-cadence intent (gated on the player moving so there are no idle hops); LocalPlayerMixin folds it into ClientInput.keyPresses right after input.tick — the same anti-cheat-safe path the nav injector uses. Movement direction stays the player's; Mimic only layers the on/off texture. Camera signature (prior commit) + cadence now = a fuller "moves like you" overlay from real captured data.
client — PathExecutor.followPath — humanise any external planner's route (Track B seam) mistake67
details
The licence-free core of Track B (H): PathExecutor.followPath(waypoints) walks a path computed by an external planner (baritone) through the exact same humanised pipeline as our own A* — string-pull, sprint-gate, stuck-recovery, legit keyPresses input, Mimic cadence overlay — so a robotic external route comes out human and anti-cheat-safe. Keeps GPL/baritone entirely out of the core: the future isolated baritone addon is just a thin caller of this seam.
New GPL-isolated addon `client/addons/baritone` that uses the standalone baritone mod purely as a PLANNER and walks its route through Aurora's humanised executor — so baritone's strong pathfinding drives movement that looks human + anti-cheat-safe, and no GPL code touches the core.
BaritoneNav module: setGoalAndPath(goal) → once baritone has a path, snapshot
ML retrain infra (ml/): PyTorch CVAE matching the server ONNX contract (encoder x,c->mu,logvar; decoder z,c->win; norm.json), per-key specs, base-cond derivation ported 1:1 from InferenceService, --personal conditions on the 12-dim HUMAN PlayerProfile embedding (COND = base_cond + 12). Synthetic path + onnxruntime contract check run end-to-end (killaura/crystal/anchor, cond 20/18/18).
Serving side, backward-compatible + gated: - InferenceTransaction.Request carries an optional embedding (appended; empty = base). - InferenceService.infer(...,embedding); ModelBundle splits baseCond/embDim, appends the embedding to the trailing cond slots for personal models. Base models unchanged; personal load opt-in via AURORA_PERSONAL_MODELS env. - SessionManager.requestInference(...,embedding) overload (bootstrap stays profile-agnostic); NetworkCvaeEngine passes SystemManager.behavior().embedding() unconditionally (server ignores it for base models).
Retrained personal .onnx are a hot-swap into server/auth/.../resources/models/.
behavior,ml — Rich dataset recorder + .ads->npz importer for human replication mistake67
behavior,server — MimicAI — execute the server mimic model (roadmap D-full) mistake67
details
Closes the generative loop: the auth server serves the full-body "mimic" model and the client actuates its output as legit input.
Server (InferenceService): load "mimic" (W=100, CH=16, embedding-conditioned when AURORA_PERSONAL_MODELS lists it); signed denormalize (movement/view deltas keep their sign — no max(0) clamp) + buildMimicSteps returns the raw window frame-by-frame.
command — Local chat command system (prefix .) + tab-complete; drop Mimic mistake67
details
New client-side command framework (dev.aurora.impl.command), modelled on the Paradise/ThaSup UX but Mojmap-native. Lines starting with '.' are intercepted in ChatScreenMixin, dispatched via CommandManager, and never sent to the server. TAB completes the command/argument; a grey ghost hint previews the top suggestion.
nav,antiafk — Backend-adaptive .goto/.follow + waypoint Goto; AntiAFK ai mode; drop AutoWalk/MimicAI mistake67
details
Mimic (D-lite) becomes AntiAFK's 'ai' mode (like AimAssist/TriggerBot modes): replays the player's own recorded HUMAN motion windows as a humanised anti-AFK fidget (look signature via RotationSystem + walk cadence via LocalPlayerMixin). Simple mode = the old yaw jitter. AntiAFK now mode-based (antiafk/{AntiAfkMode,SimpleAfk,AiAfk}).
Waypoints module: an 'Open GUI' ActionSetting (second entry point besides the radial).
.goto cross-dimension: a waypoint in another dimension parks the goal (no auto portal
traversal yet) — NavRouter.park; the user crosses over and runs '.goto resume', which
fires once they're in the goal's dimension.
BaritoneHumanizer redesign: fix the two robotic tells. Set baritone freeLook=true so it
releases the visible camera (pathing unaffected — movement still uses its motion rotation),
and drive the camera ourselves along the route: aimed a few nodes ahead (look-ahead,
scaled by camera-speed when personalize is on), eased through the humanised RotationSystem,
with a little natural jitter. So baritone looks down its path and eases into turns instead
of snapping and staring at the goal. Rides baritone's onTick bus; antiCheat stays on.
Compiles client + baritone addon; addon jar installs to run.
command — Suggestion dropdown list (MC/baritone-style) for local commands mistake67
details
The inline ghost hint only previewed one entry. Add a real dropdown above the chat input listing the matching commands/arguments (placeholders like shown greyed), ↑/↓ to move the selection, TAB to complete the highlighted one, ghost still previews it inline. Typing just '.' lists every command. Drawn on ChatScreen render RETURN.
handshader — Migrate all single-mode hand effects to macOS-safe PostChain mistake67
details
Port stripes/chroma/smoke/snow/glow/glass/balatro to the same vanilla PostChain path that fixed solid: In + native depth (use_depth_buffer -> DepthSampler) inputs on minecraft:main, full-frame depth-masked mix (no discard), straight blit back to main. No raw GL, no framebuffer feedback loop -> renders correctly on macOS core profile.
Fixed the two pre-existing untested postchains (smoke, balatro): they used the wrong
and bound depth as a second colour input; both now use the In/InSampler + Depth/DepthSampler
convention with real depth.
Colours marshalled as split R/G/B scalar floats, booleans as 0/1 floats (postchain 1.21.4
uniforms are scalar only). Time auto-fed; per-effect speed folds into it.
HandShader.draw single-mode now dispatches every Mode through ShaderManager.*Post; the old
raw-GL two-pass path is gone. Dual-mode still on raw-GL (next).
All 7 verified rendering on macOS.
handshader — Dual-mode via sequential PostChain stacking (macOS-safe) mistake67
details
Dual-mode was still on raw-GL renderToTexture/renderBlend, which stayed black on macOS for the same effects single-mode did. Replace it: draw effect1's PostChain, then stack effect2's PostChain on top (each depth-masked to the hand). effect2 blends over effect1 by its own alpha.
handshader — Add smokeAlpha parameter for customizable smoke opacity mistake67
randomization — Implement dynamic function cycling in RandomizationVisualizerScreen mistake67
randomization — Add local randomization override and visualization support in KillAura mistake67
hud — Add Scoreboard and TabList modules for repositioning vanilla UI elements mistake67
command — Implement CommandTrie for efficient command autocompletion mistake67
command — Implement CommandTrie for efficient command autocompletion mistake67
command — Optimize CommandTrie for memory allocation and performance mistake67
command — Optimize CommandTrie for memory allocation and performance mistake67
build — Add unoptimized Baritone libraries for Fabric and Neoforge mistake67
render — Implement PathRendererMixin for enhanced navigation rendering mistake67
render — Refactor NavRender integration for improved path rendering mistake67
nav — Enhance NavRouter and GotoCommand for improved goal management mistake67
nav — Implement navigation commands and path management for baritone integration mistake67
patch — Add MOVE operation support and integrity probing for patch management mistake67
patch — Implement MoveOperation detection and handling for patch management mistake67
baritone — Add pause command to freeze current task without cancellation mistake67
backtrack — Implement backtracking module for delayed packet handling during combat mistake67
settings — Add suffix support to NumberSetting and RangeSetting for enhanced value display mistake67
backtrack — Enhance target mode handling and add suffix support to range and delay settings mistake67
smoothaim — Add pitch jitter visibility control and enhance hit goal handling mistake67
renderer — Update renderOutline method to use Vector3d and optimize corner handling with Pools mistake67
renderer — Update renderOutline method to use Vector3d and optimize corner handling with Pools mistake67
arraylist — Optimize per-row metric handling by using persistent arrays mistake67
dataset — Implement passive collection of unlabeled rows and switch to CSV format mistake67
finder — Streamline labeling process and enhance hinting for site identification mistake67
finder — Enhance hinting with one-click RUN_COMMAND and streamline button interactions mistake67
dataset — Implement passive dataset uploads for BaseFinder candidates and behavior frames mistake67
dataset — Implement passive collection and upload of real interaction data for killaura and anchor actions mistake67
theme — Implement UI scale adjustments for improved high-DPI support mistake67
ui — Unify uiScale handling across screens and improve rendering consistency mistake67
inventory — Route inventory actions through ActionPipeline for improved click handling mistake67
action — Route inventory click actions through ActionPipeline for improved execution order mistake67
stronghold — Enhance low-confidence fit handling and beacon update logic mistake67
accessibility — Add access widener and configuration for Minecraft versions 1.21.11 and 26.2 mistake67
version — Update active version to 1.21.11 and refactor resource location handling mistake67
compatibility — Update version checks for Minecraft 1.21.11 and 26.2 mistake67
version — Update active version to 26.2 and refactor plugin handling mistake67
Shape (sealed interface: Quad/RoundedQuad/Circle/Outline/Line/Text/ CenteredText/Texture) + ShapeQueue mirror BridgeBase's AbstractRenderer push/add/pop/instant contract, but need no per-version backend since every Shape variant dispatches onto the already version-agnostic RendererPort primitives. Investigated migrating existing HUD call sites onto it; found RendererPort already eliminated real cast noise there (zero casts in Watermark/FpsDisplay/etc — remaining casts are all structurally-required mixin trampolines or vanilla API-boundary casts), so left as an available primitive rather than force a no-benefit migration.
version — Update active version to 26.2 and refactor plugin handling mistake67
render — Implement real GPU text on 26.2 mistake67
details
26.2 removed Font.drawInBatch()/Minecraft.renderBuffers() and Tesselator-based mesh submission, so both of the client's text paths were left as documented no-ops and every component rendered without its labels.
Route both through the GpuBuffer/drawFromBuffer immediate path Renderer_26_2 already uses for its other primitives:
Renderer_26_2.Text now lays vanilla text out with Font.prepareText and pushes
the resulting TextRenderables through GpuImmediate, batching consecutive
same-RenderType runs so glyph/effect order is preserved.
FontRenderer's custom TTF atlas branch emits the same glyph quads as the
1.21.11 branch, submitted via the new Renderer_26_2.immediateDraw entry.
cosmetic — Drive wing and pet animation from player motion mistake67
details
Wings and pet animated off sin(System.currentTimeMillis()), so they moved identically standing still and sprinting, ran faster at higher framerates, and had no inertia. CosmeticMotion replaces the clock with four smoothed, bounded drive terms, adapted from PrismClient's cloak physics minus the cloth simulation:
Source: velocity and yaw turn rate resolved into body-local space, so a cosmetic
trails when you run forward and swings when you strafe. Motion is the average of
the position delta since last tick and the entity's own velocity — two independent
estimates that are noisy in different ways, so averaging cancels tick jitter.
Timing: a fixed 60Hz step with a clamped accumulator. Identical at 30 and 240 fps,
and a stall cannot spiral into a catch-up burst that flings the cosmetic.
Stability: every term is clamped before use.
Inertia: a damped spring per term, whose overshoot on a hard stop is the part the
sine wave could never fake.
Distribution — Prism's quadratic hinge weighting, where the tip swings and the anchor barely moves — is exposed as CosmeticMotion.weight() but unused: wings.geo.json has a single bone per side, so only whole-wing rotation is possible. It needs per-segment bones to have anything to weight.
Both branches of the version gate are rewired; no clock-driven animation remains. Verified on 26.2 only — the <1.21.11 branch is commented out there, so it is unverified.
cosmetic — Add a self-driven wing beat, slimmer wings and a chamfered pet mistake67
details
Three things, all aimed at cosmetics looking less like boxes on a timer.
Own animation: motion drive alone meant a cosmetic was purely reactive and dead while standing still. CosmeticMotion.flap(phaseOffset) adds a beat that always runs, sampled further behind at each joint so the stroke travels shoulder-to-tip rather than the wing snapping as one piece. It advances on the same fixed 60Hz step as the springs, so unlike the sin(currentTimeMillis()) this replaced it does not speed up with framerate, and the motion terms add on top of it.
cosmetic — Render wings as procedural meshes instead of boxes mistake67
details
Cosmetics looked like stacks of cubes because ModelPart can only emit axis-aligned boxes. Nothing about the renderer requires that: the ENTITY vertex format is Position, Color, UV0, UV1, UV2, Normal — everything a mesh needs, per-vertex normals included — and the consumer handed to submitCustomGeometry accepts whatever we push into it. So the wings now build their own geometry and keep vanilla lighting, overlay, batching and the deferred pass for free. A hand-rolled VBO/VAO pipeline would have thrown all of that away and had to reimplement it against 26.2's GpuBuffer API.
CosmeticMesh holds plain vertex arrays plus an index buffer and emits each triangle as a quad with its last vertex repeated — these render types take QUADS, since ModelPart feeds them four vertices per face, and the padded triangle has zero area. The structure is deliberately dumb so an OBJ/glTF loader can fill the same thing later; the drawing side does not care where vertices came from.
CosmeticMeshes.feather is a lofted surface: a spine curve falling along +Y and trailing backwards, a sin width profile giving a round shoulder and a point, and a camber bowing the blade so it is not a flat card edge-on. Normals come from crossing the real tangents, sampled by central differences — the analytic form is singular at the root, where the width profile's derivative blows up, and differences are free on a mesh built once and cached.
+Y is DOWN in model space, matching the boxes this replaces (Bedrock origin [0,-16,0] bakes to mcY 0..16). The first cut had it as -Y and rendered the wings upside down.
Wings have no ModelPart to hang on now, so emitWing walks the joint chain on the PoseStack directly. Same chain as before: each joint rotates on top of its parent and stays applied outward, which is what accumulates into the curl.
Textures are planar in blade space rather than box-UV, one image serving every feather length. No alpha cut here — the mesh already tapers the shape, so cutting again would clip the silhouette twice.
Pet and hats still use boxes, so mesh and box sit side by side for comparison. The <1.21.11 branch still uses the box path: the versions now diverge, which needs settling separately.
cosmetic — Build pet and hats from primitives instead of boxes mistake67
details
The halo was eight boxes arranged in a ring — an approximation of a torus, which is one line of maths. Same story elsewhere: the beanie was a box dome, the top hat a box cylinder, the crown a box band with box spikes, the pet a chamfered die. All of them are parametric surfaces, so they are now generated as such.
Rather than five separate builders, CosmeticMeshes is reorganised around one grid() that samples a Surface function. Normals — the awkward part, and the part a hand- rolled builder gets subtly wrong — are then solved once, from crossing the real tangents by central differences. sphere/dome/torus/cone/tube/disc are each a lambda.
Positions are taken from the boxes they replace rather than re-eyeballed: Blockbench origin/size bakes to mcY = -originY - sizeY, so the halo's origin y=14 size 1 held mcY -15..-14 and its torus sits at -14.5. The silhouette changes; the fit does not.
grid() takes doubleSided because it is a real distinction, not a toggle: open shells (feather, brim) need a back face since one sheet is lit from one side, while closed shapes must not have one or the duplicate surface z-fights with itself.
Textures change character with this. Meshes carry per-vertex normals, so the renderer lights them and the textures no longer paint fake shading — they supply colour and markings only. That was only ever there because boxes had no normals worth lighting. halo.png was literally one colour and is now 31; pet.png goes from 2 to 65.
An unknown hat still falls back to its Blockbench box, so adding an entry to ModelCosmetics draws something before it gets a mesh here. Cape is untouched: it is the one texture-based type, applied to vanilla's cape via the skin mixin, and never passes through this layer at all.
client — Bridge the input axis, and make ClientScreen own the boundary mistake67
details
Aurora already had the BridgeBase pattern — DrawCtx and Pose are aurora interfaces that every version's vanilla class implements via mixin, so the vanilla object IS the bridge object and feature code names one type instead of a gated one. What it did not have was the input axis.
1.21.11 packed vanilla's loose (x, y, button) / (key, scancode, modifiers) parameters into MouseButtonEvent / KeyEvent / CharacterEvent, and 26.2 then dropped CharacterEvent.modifiers() outright. No cast undoes a shape change, so this half of the bridge is aurora records built once at the boundary: MouseInput / KeyInput / CharInput, in the new dev.aurora.api.input, whose package-info documents the whole bridge — both mechanisms, where gates are allowed to live, and what is deliberately not bridged (entities, world, items, packets) with the reason.
ClientScreen already adapted vanilla input for its elements. The problem was that nothing stopped a screen from overriding the vanilla methods itself and re-opening the boundary in a file with no business being one — ten of them did. ClickGuiScreen paid the clearest price: it constructed a vanilla MouseButtonEvent just to hand transformed coordinates back to super.
So the vanilla overrides are now final and purely adaptive, and subclasses override version-free on* hooks instead. Making them final is what found the other nine screens: the compiler enumerated them.
Coordinates reach the hooks raw; the default hook impls descale. A screen with its own transform applies it and calls super, which is the order the old overrides produced.
393 -> 373 gates, 9 files now entirely version-free. Also drops two gates whose only job was importing a GuiGraphics that nothing in the file used.
Not covered, on purpose: - MinecraftElement implements vanilla GuiEventListener, so its signatures must be vanilla. It is an adapter — a boundary, like ClientScreen. Its gates stay. - CrosshairEditorScreen extends Screen directly and relies on vanilla widgets, which ClientScreen forbids by design. Converting its buttons to Elements is a different refactor; its 8 gates stay for now.
Version roadmap (1.8.9, 1.16.5, 1.19.4, 1.20.4, 26.1.2) is commented in settings.gradle.kts next to the live nodes, with what each would actually cost.
cosmetic — Give every version the mesh cosmetics, via a rig interface mistake67
details
1.21.11 replaced the immediate-mode render(PoseStack, MultiBufferSource, …) layer API with a deferred submit(PoseStack, SubmitNodeCollector, …) one and moved PlayerModel. CosmeticLayer answered that with two whole class bodies behind one gate, and the two drifted apart: >=1.21.11 grew procedural meshes (feather, sphere, torus, dome, cone, tube, disc) while 1.21.4/1.21.8 stayed on Blockbench boxes drawn through ModelPart. Same motion, different cosmetics — the client did not look like itself across versions.
The mesh engine was already version-free and nobody had noticed: CosmeticMesh .emit takes a PoseStack.Pose and a VertexConsumer, both of which 1.21.4 has, and CosmeticMeshes imports nothing but Mth. It simply had no caller down there.
So the split is now drawn where it actually is. CosmeticRig is what the geometry needs from its era — attach to a bone, take a mesh, take a ModelPart — and CosmeticGeometry holds the cosmetics themselves, naming no type Minecraft has renamed and carrying no gates. CosmeticLayer is two ~40-line rigs and nothing else: 328 -> 157 lines, 4 -> 3 gates, with the remaining three all on the class signature.
The immediate-mode rig turns out to be the simpler of the two: with no deferral there is no snapshot to honour, so pose.last() is still the transform the cosmetic was positioned by.
Both geometry sources stay, because they are for different things and only one of them can ever reach a store: - procedural meshes are Java, a `case` per cosmetic in CosmeticGeometry.hat — hand-tuned and smooth-shaded, but a new one costs a client release. - Blockbench .geo.json is data — authorable in a free tool, shippable without a release. It is the `default` arm today and the only path a shop or a community-made cosmetic can travel.
The data path still draws through vanilla ModelPart, which only emits axis-aligned boxes and is the same drifting type that forced this split in the first place. Baking .geo.json into a CosmeticMesh instead — one renderer, two sources — is the end state; it needs a bone tree of our own first, since ModelPart is what supplies bones today.
Compiles on all 6 nodes. NOT visually verified: the cosmetics only draw with one selected, and this changes what 1.21.4/1.21.8 players see.
cosmetic — Registry instead of switch for procedural hats mistake67
details
CosmeticGeometry.hat was a hardcoded switch on model name — a new procedural hat cost a client release. Replace with a HatDrawer functional interface + static registerHat(name, drawer), seeded with the same four built-ins. Blockbench fallback on a registry miss is unchanged.
Corrects the roadmap's original script-exposure plan: ScriptLibraries (compiler-jar provisioning) and ScriptEventBus (event fan-out) aren't a fit for a name->handler registry. Real path is a new client-api port over AuroraScript.services, split out as its own next step.
cosmetic — Script-facing port for registerHat (roadmap step 1b) mistake67
details
Moves CosmeticMesh/CosmeticMeshes into client-api (dev.aurora.api.cosmetic) — they already imported nothing but Mth/PoseStack/VertexConsumer, all vanilla types the api module already touches, so this is a pure relocation. Adds CosmeticPartSink + HatDrawer + CosmeticRegistryPort in client-api: a script can now reach CosmeticGeometry.registerHat via AuroraScript.cosmetics (services.get(CosmeticRegistryPort::class.java)) without ever naming CosmeticRig (impl) or the ModelPart/Blockbench path — the sink only exposes mesh drawing, matching the trusted tier's scope (procedural only, per cosmetics-roadmap.md's trust-tier split).
CosmeticRig now extends CosmeticPartSink directly (identical mesh() signature), so the same rig instance a registered HatDrawer receives at draw time is what CosmeticLayer already builds per era — no adapter needed. Wired into AuroraClient's service manager next to the other interface-keyed registrations for addons/scripts.
Verified compileKotlin+compileJava on client:client and client:api for 1.21.4-fabric and 26.2-fabric in one combined invocation.
Blockbench cosmetics no longer route through ModelPart/LayerDefinition at all. New api.cosmetic types: CosmeticBone (pivot offset + rotation + merged per-bone mesh + children) and CosmeticBoneModel (walks the tree on a PoseStack via CosmeticPartSink, mirroring how CosmeticGeometry.wing() already walks its own procedural joint chain by hand). CosmeticMeshes.box() bakes one cube straight into 6 quads using the standard Minecraft/Blockbench box-UV layout; CosmeticMesh gets a merge() to combine a bone's cubes into one mesh.
BlockbenchModel.load() now parses bones into a CosmeticBone tree instead of a PartDefinition/LayerDefinition (self-rotated cubes still become synthetic child bones, same as before). CosmeticModels caches CosmeticBoneModel instead of ModelPart. CosmeticRig drops part(ModelPart, ...) entirely -- mesh() (from CosmeticPartSink) is now the only drawing capability either drawer kind (procedural HatDrawer or baked CosmeticBoneModel) ever needs, so the data and code cosmetic tiers finally share one renderer.
Box-UV face/corner assignment is hand-derived from the well-known stable layout (unchanged across MC versions), not extracted from a live ModelPart -- correct on positions/silhouette, UV orientation is the one thing not visually confirmed yet. Verified compileKotlin+compileJava on client:client and client:api, 1.21.4-fabric and 26.2-fabric together.
cosmetic — Load .geo.json from disk + network, capped (roadmap step 3) mistake67
details
BlockbenchModel.loadFromDisk(Path) parses an untrusted .geo.json with caps (128 bones, 512 cubes, bone-tree depth 16, texture dims 0
CosmeticModels.loadCustom(Path) is a second cache keyed by absolute path, kept separate from the bundled name-keyed cache so a custom file can never shadow a built-in cosmetic name.
New CustomCosmetics mirrors ScriptManager's directory-scan shape: reload() scans aurora/cosmetics/*.geo.json (+ sibling .png) through the capped loaders above; download(url, name, onDone) fetches a .geo.json by URL, matching the pattern already established by CosmeticManager (cape/skin PNG downloads) but routing the result through the same caps before it's ever baked.
Not wired into any in-game picker -- nothing calls reload() at boot, and CustomCosmetics.all() doesn't feed ModelCosmetics' selection yet. That's a UI/selection design decision (how a custom entry sits next to the fixed catalogue), deliberately left for whoever designs the actual shop screen.
Verified compileJava on client:client 1.21.4-fabric only -- the concurrent bridge-work agent has the shared Stonecutter active-version pinned there; 26.2 cross-check pending until it's safe to switch back. Staged only these cosmetic files, not the ~163 other tracked files whose working-tree diff is pure Identifier<->ResourceLocation version-render noise from that pin, unrelated to this change.
Wires bridge:ksp into settings.gradle.kts and implements BridgeSymbolProcessor, which reads @Bridge-annotated interfaces and emits Bridge Java interfaces with default methods delegating to abstract aurora$$$ hooks. Fixed several issues in the plan's sample code along the way: primitive return types (float/float[]) routed through JavaPoet TypeName constants instead of Class.forName; JavaFile written via CodeGenerator.createNewFile since there's no writeTo(CodeGenerator, Dependencies) overload for Java sources; '$' in hook names passed through JavaPoet's $L literal placeholder instead of raw string interpolation (JavaPoet treats '$' as its format-specifier prefix); missing kspArgs import and missing @OptIn(ExperimentalCompilerApi) in the test; and the kotlin-compile-testing embedded 1.9.24 compiler choking on this repo's Kotlin 2.3.x metadata, worked around by disabling classpath inheritance and pointing kotlinStdLibJar at a resolved 1.9.24 stdlib jar.
mixin — Implement CameraAccessBridge on 1.21.4-fabric Camera mistake67
details
New CameraBridgeMixin in dev.aurora.mixin.fabric.client (loader-scoped by registration in runtime.fabric.mixins.json), with the CameraAccessBridge implementation additionally gated //? if 1.21.4 in-file — the combined loader+version idiom used elsewhere in the matrix (fabric/ registration + in-file version gate, see EntityRenderDispatcherMixin's version-axis half). Reuses vanilla Camera's getPosition()/getYRot() (1.21.4 Mojmap names). 1.21.8-fabric (same buildscript, also depends on :bridge:api) compiles the class but gets no bridge coverage yet; fabric-m nodes never see the bridge import at all since it's inside the same gate.
bridge — Expose Platform.camera() backed by CameraAccess mistake67
details
Adds Platform.camera(): CameraAccess (Task 6). FabricPlatform casts the live vanilla Camera to the generated CameraAccessBridge, gating the getMainCamera()/mainCamera() rename since this bootstrap file compiles on every fabric node, not just 1.21.4. NeoForgePlatform gets an explicit, documented UnsupportedOperationException stub (not yet bridged on that loader) rather than a silent no-op. Also wires :bridge:api into the neoforge buildscript so the CameraAccess type resolves there.
cosmetics — Sign the shop's script channel mistake67
details
Add ScriptSignatureVerifier (dev.aurora.util.signature) — a raw-bytes Ed25519 verifier over a SHA-256 digest, same pattern as ArtifactVerifier — since api/util/signature had no crypto, only jar watermarking. Wire a verify gate into ScriptCompiler.compile() before host.eval(): a detached