Commit graph

110 commits

Author SHA1 Message Date
LoVisual AI
135628c2f1
feat(mod): Stage 3 (continued 2) — entity + block + Sodium contract mixins
Per mod/docs/optimize-layer-design.md Stage 3 (continued). This batch
implements the Stage 1 mixin-contract interfaces on their target MC classes
so CachedName, StateEntity, TickCached, CachedLight, CachedValidity and
CachedStack actually get used. Seven new mixin'ов; no new helpers (the
helpers were all written in Stage 1 already).

Entity-contract mixins (mixins/optimize/entity/):
- EntityNameMixin: implements CachedName on Entity — adds the per-tick
  cached name-tag fields (Component + tick). Vanilla Entity.getDisplayName()
  rebuilds the team prefix + name + suffix on every call.
- EntityRenderStateEntityMixin: implements StateEntity on EntityRenderState —
  adds the back-reference field to the source Entity. Render-states are
  rebuilt every frame so they can't keep their own pointer; this is captured
  by EntityRendererStateMixin.
- EntityRendererStateMixin: Inject at RETURN on EntityRenderer.createRenderState
  — captures the source Entity on the freshly-built state via the StateEntity
  contract. ZakoOpt used @ModifyReturnValue; we use plain @Inject because the
  MixinExtras ModifyReturnValue transformer is more fragile across MC versions.
- EntityRendererNameMixin: WrapOperation on EntityRenderer.getNameTag's
  Entity.getDisplayName call — caches by game tick so the per-frame cost is
  one identity check + read instead of a full Component rebuild.
- SodiumEntityRendererMixin: WrapOperation on Sodium EntityRenderer.renderCuboid's
  MemoryStack.stackPush — uses CachedStack (Stage 1) to skip the ThreadLocal
  lookup on the render thread. Registered as optional via LoVisualMixinPlugin
  (only applied when Sodium is loaded); remap = false because the target is
  a Sodium class, not a Mojang one.

BlockEntity-contract mixins (mixins/optimize/block/):
- BlockEntityMixin: implements TickCached + CachedLight + CachedValidity on
  BlockEntity — adds the per-tick cache slot, per-tick block-light lookups
  (single + pair for double-chests), per-tick should-render distance check,
  and per-state validity cache. All four are read by the (Stage 3, future)
  ChestRendererMixin / BlockEntityRenderStateMixin / BlockEntityRenderDispatcherMixin.
- BaseSpawnerMixin: implements TickCached on BaseSpawner — adds the per-tick
  cache slot that SpawnerCache (Stage 1) reads back.

Folder limit (≤4 .java per folder):
- mixins/optimize/entity/ hit 6 files after this batch — split into
  mixins/optimize/entity/renderer/ for EntityRendererStateMixin +
  EntityRendererNameMixin (the two that target EntityRenderer rather than
  Entity/EntityRenderState directly). The other 4 stay in entity/.

lovisual.mixins.json: seven new entries in the 'client' array, alphabetical:
  optimize.block.BaseSpawnerMixin
  optimize.block.BlockEntityMixin
  optimize.entity.EntityNameMixin
  optimize.entity.EntityRenderStateEntityMixin
  optimize.entity.SodiumEntityRendererMixin
  optimize.entity.renderer.EntityRendererNameMixin
  optimize.entity.renderer.EntityRendererStateMixin

LoVisualMixinPlugin: added SodiumEntityRendererMixin to OPTIONAL_SODIUM_MIXINS
so the mixin is only applied when Sodium is loaded (matches the existing
convention for sodium.* mixins).

Tests: no new tests in this batch (the new mixins are pure side-effect
field-bags — they don't have unit-testable logic). Existing suite still green.
Total: 866 tests, 0 failures. checkFolderLimit: OK (0 папок >4).
2026-10-11 10:23:03 +02:00
LoVisual AI
15f070af6d
feat(mod): Stage 3 (continued) — LivingEntityLod + BubbleColumnUp + LevelRendererOutline
Some checks failed
CI / backend (cargo test + clippy) (push) Failing after 6m48s
CI / frontend (lint + test + build) (push) Failing after 24s
CI / mod (gradle test + checkFolderLimit) (push) Successful in 1m57s
Per mod/docs/optimize-layer-design.md Stage 3 (continued). Three more simple
mixin'ы are added on top of the existing RenderBackendOps + lazy-clear/TBO/
RenderTypes trio:

mixins/optimize/entity/LivingEntityLodMixin.java:
- ModifyExpressionValue on LivingEntityRenderer.submit's shouldRenderLayers
  call — return false when the entity's distanceToCameraSq is beyond the
  Stage 1 entity_lod threshold. Skips the layer pass (armour, held items,
  eyes, cape, elytra, stuck arrows) for far entities. Ported from
  zako.opt.mixin.entity.LivingEntityLodMixin.

mixins/optimize/particle/BubbleColumnUpParticleMixin.java:
- WrapOperation on BubbleColumnUpParticle.tick's ClientLevel.getFluidState
  call — consult BubbleColumnCache first, store on miss. Cache is cleared
  per-tick (BlockPos.asLong key + game-tick tracking). Ported from
  zako.opt.mixin.particle.BubbleColumnUpParticleMixin.

mixins/optimize/world/LevelRendererOutlineMixin.java:
- Inject on LevelRenderer.doEntityOutline HEAD-cancellable — skip the
  outline render when no glowing entity was seen this frame (OutlineTracker).
- WrapOperation on LevelRenderer.addMainPass's clearColorTexture — call
  OutlineTracker.markGlowing() to record that the renderer is about to
  draw an outline this frame. (Conservative: marks every clear, not just
  the entity-outline one — ZakoOpt uses @Local for precision, we keep it
  simple to avoid MixinExtras @Local fragility across MC versions.)
- Ported from zako.opt.mixin.entity.LevelRendererOutlineMixin.

Helpers (features/.../optimize/):
- particle/TickCache<V>: generic per-tick keyed cache (Long2ObjectOpenHashMap).
  BubbleColumnCache wraps it for FluidState. Other per-tick caches
  (ParticleLightCache etc.) can reuse it in later Stage 3 commits.
- particle/BubbleColumnCache: thin wrapper over TickCache<FluidState>.
- world/OutlineTracker: per-frame state for the outline-skip optimization
  (glowingThisFrame + dirty flag, beginFrame/markGlowing/markCleared API).

lovisual.mixins.json: three new entries in the 'client' array:
  optimize.entity.LivingEntityLodMixin
  optimize.particle.BubbleColumnUpParticleMixin
  optimize.world.LevelRendererOutlineMixin

Tests (JUnit 5):
- TickCacheTest: 9 tests covering get/put/clear-on-tick-change/multi-key/
  overwrite/null-values/long-keys.
- OutlineTrackerTest: 8 tests covering enabled flag, skip-when-no-glowing,
  begin-frame-clears, dirty-tracking, needsClear logic.
- (BubbleColumnCache itself is a 4-line wrapper around TickCache so its
  test would just re-test TickCache — skipped.)
Total suite: 866 tests, 0 failures. checkFolderLimit: OK (0 папок >4).
2026-10-10 18:53:38 +02:00
LoVisual AI
5e1864fed1
refactor(mod): restructure mixins/optimize/ into gl/hud/entity/particle/world subfolders
Per mod/docs/optimize-layer-design.md Stage 3 (continued). The mixins/optimize/
folder hit the project's ≤4 .java-files-per-folder rule when we tried to add
the next batch of mixin'ов (LivingEntityLodMixin, BubbleColumnUpParticleMixin,
LevelRendererOutlineMixin). Move the existing 4 mixin'ов into semantic subfolders:

- mixins/optimize/gl/GlCommandEncoderClearMixin.java (was mixins/optimize/)
- mixins/optimize/gl/GlCommandEncoderTexBufferMixin.java
- mixins/optimize/gl/RenderTypesMixin.java
- mixins/optimize/hud/OptimizeDebugHudMixin.java

lovisual.mixins.json: the 'client' array entries are updated to use the
new dotted paths (optimize.gl.*, optimize.hud.*). The package field in
each mixin file is updated to match.

No functional changes — this is purely a code-organization commit to make
room for the new Stage 3 mixin'ов in the next commit.
2026-10-10 18:53:38 +02:00
LoVisual AI
7a2ed9fc34
docs(mod): mark Stage 1+2 done and Stage 3 partial in optimize-layer-design.md
Per mod/docs/optimize-layer-design.md.

Status header: was 'черновик на согласование (2026-10-09)', now
'Этап 1 готов, Этап 2 + начало Этапа 3 готовы (2026-10-10)'.

New 'История изменений' section: three dated entries (Stage 1, Stage 2,
Stage 3 partial) listing files / tests / patch references.

Stages section: each line now carries a status icon (✅/🔄/❌), a completion
date, and a one-line summary of what shipped. Stage 3 partial lists what's
done (RenderBackendOps + GlRenderBackendOps + 3 GL mixins) and what's still
left (FrameFence, SharedDepthFbos, SkinAtlas, AnimFreeze, ItemLod,
LivingEntityLodMixin, ParticleMixin, SpawnerRendererMixin, etc.).

New 'Оценки для Этапов 3-4' section: rough effort estimates for the
remaining Stage 3 work (~25 mixins + ~8 helpers, 3-4 work sessions) and
Stage 4 (6 Vulkan items, profiling-driven, 1+ session for vkCmdCopyImage
which is needed for SkinAtlas to work on Vulkan).
2026-10-10 18:53:38 +02:00
LoVisual AI
e88718a32d
feat(mod): Stage 3 (partial) — RenderBackendOps interface + 3 GL mixins
Per mod/docs/optimize-layer-design.md Stage 3 (partial). This commit ships
the simplest GL mixins and the strategy interface that splits GL/Vulkan
backends. SkinAtlas/AnimFreeze/HudCache/FrameFence deferred to a later pass
because they're more complex (vertex-format / glCopyImageSubData /
RenderPipeline+RenderPass).

RenderBackendOps interface (features/.../optimize/gl/RenderBackendOps.java):
- Backend-agnostic surface for lazy clear, TBO cache, RenderTypes cache.
- current() resolves the active backend — returns GlRenderBackendOps on GL,
  null on Vulkan (so all WrapOperations fall through to the vanilla call).
- Stage 4 will add a VulkanRenderBackendOps no-op implementation.

GlRenderBackendOps (features/.../optimize/gl/GlRenderBackendOps.java):
- Concrete GL implementation. Three caches ported from ZakoOpt:
  * Lazy clear (from zako.opt.mixin.gl.GlCommandEncoderClearMixin).
  * TBO cache (from zako.opt.gl.TexBufferCache + the TexBufferMixin).
  * RenderTypes cache (from zako.opt.mixin.gl.RenderTypesMixin).
- All three gated on OptimizeToggles.microOpts() (the Stage 1 'micro_opts'
  toggle wired in Optimize.java).
- Includes test helpers (resetForTesting, boundTboTextureForTesting,
  cachedRenderTypeCountForTesting).

Three new mixins (mixins/optimize/):
- RenderTypesMixin: WrapOperation on RenderTypes.entityTranslucent's
  BiFunction.apply — cache by Identifier when flag=true (the common case).
  Drops the per-call Objects.hash(Pair) hit.
- GlCommandEncoderClearMixin: WrapOperation on GlCommandEncoder's
  clearColorAndDepthTextures → GlStateManager._glBindFramebuffer — skip the
  bind-framebuffer-0 because the next render pass binds its own target
  anyway and GlStateManager's cache already skips redundant binds.
- GlCommandEncoderTexBufferMixin: WrapOperation on GlCommandEncoder's
  trySetup → glBindTexture (track bound) and glTexBuffer (skip re-attach
  when the same (format, buffer) pair is already attached). Re-attaching
  makes the driver revalidate the texture (clouds: ~2% of a frame).

lovisual.mixins.json:
- Register all three mixins + OptimizeDebugHudMixin in the 'client' array,
  alphabetically under optimize.* (before accessors.*).

OptimizeDebugHudMixin (mixins/optimize/OptimizeDebugHudMixin.java):
- F3 overlay for the Optimize layer — Stage 2 of the design doc.
- Adds three blocks of lines to F3 (after the existing LoVisual Engine block):
  * 'LoVisual Optimize' — toggles summary + budget mode + scale + frame time.
  * 'frame:' — EMA-averaged per-section timings (entities/particles/HUD/effects/text).
  * 'props:' — when any -Dlovisual.opt.* is set, list which ones.
- Mirrors the existing hud.DebugHudMixin pattern (ModifyArg on extractLines).

Tests (JUnit 5): 11 new tests in GlRenderBackendOpsTest — pure-logic pieces
of RenderBackendOps + Identifier equality/hash. Total suite: 849 tests,
0 failures. checkFolderLimit: OK (0 folders >4).
2026-10-10 18:53:38 +02:00
LoVisual AI
64f27ee9e3
feat(mod): Stage 2 — frame budget + profiler + -Dlovisual.opt.* overrides
Per mod/docs/optimize-layer-design.md Stage 2.

Engine-side state holders (render/engine/optimize/profile/):
- FrameBudget: Mode enum (OFF/SOFT/AGGRESSIVE) + target FPS + per-subsystem
  caps (entity LOD distance², particle near/mid², spawner distance, trail max
  points + step). Scale 1.0 / 0.9 / 0.6 per mode. NOT auto-degradation —
  the user picks the mode explicitly; Phase 9 rule stands.
- FrameProfiler: per-section EMA timings (entities/particles/HUD/effects/text),
  try-with-resources Section API, 2 s idle decay, frame-time tracking.
- OptimizePropertyBridge: -Dlovisual.opt.* system-property overrides.
  10 properties (entity_lod, particle_lod, spawner_cull, spawner_tick_cache,
  block_entity_cache, prepared_text_cache, micro_opts, entity_lod_distance,
  spawner_distance, budget_mode, target_fps) + all=false to disable everything.
  Mirrors ZakoOpt's ZakoOptConfig.refresh() shape.

Module wiring:
- Optimize.java: extended with budget_mode (enum), target_fps (15..360),
  show_profiler toggles. pushState() now resolves the property bridge and
  pushes FrameBudget + OptimizeToggles snapshots together.

Tests (JUnit 5): 22 new tests — FrameBudgetTest (8), FrameProfilerTest (7),
OptimizePropertyBridgeTest (12). Total suite: 849 tests, 0 failures.

Note: OptimizeDebugHudMixin (the F3 overlay) is committed in a separate
patch alongside the Stage 3 mixins because it depends on the RenderBackendOps
GL/Vulkan strategy interface for the property-bridge status line.
2026-10-10 18:53:38 +02:00
494990ca4c
test(mod): JUnit 5 tests for Stage 1 optimization helpers
Some checks failed
CI / backend (cargo test + clippy) (push) Successful in 3m43s
CI / frontend (lint + test + build) (push) Failing after 23s
CI / mod (gradle test + checkFolderLimit) (push) Successful in 2m13s
53 tests covering the pure-logic pieces: OptimizeToggles, LruMap, EntityLod,
ParticleLod, Workers, HudWorth, SpawnerCache, StableText, CachedStack.
2026-10-10 14:50:50 +02:00
1a50a757b7
feat(mod): Stage 1 optimization helpers (backend-independent)
Per mod/docs/optimize-layer-design.md Stage 1: pure helpers and mixin-contract
interfaces for the Optimize module, plus the OptimizeToggles engine-side state
holder and nine new toggles in Optimize. GL/Vulkan hooks are Stages 3-4.
2026-10-10 14:50:50 +02:00
4a722259a5
deploy(nginx): serve the mod jar from nginx with a speed cap (750k per connection) and 2 connections per IP
Some checks failed
CI / backend (cargo test + clippy) (push) Successful in 7m0s
CI / frontend (lint + test + build) (push) Failing after 26s
CI / mod (gradle test + checkFolderLimit) (push) Successful in 1m34s
2026-10-09 22:26:27 +02:00
acb69472c2
docs: README download button points at the site's /download (Forgejo has no releases/latest/download)
Some checks failed
CI / backend (cargo test + clippy) (push) Has been cancelled
CI / frontend (lint + test + build) (push) Has been cancelled
CI / mod (gradle test + checkFolderLimit) (push) Has been cancelled
2026-10-09 22:25:03 +02:00
da4112afb3
release: bump mod to 0.1.3; skip the CI release build when the release already exists
Some checks failed
CI / backend (cargo test + clippy) (push) Has been cancelled
CI / mod (gradle test + checkFolderLimit) (push) Has been cancelled
CI / frontend (lint + test + build) (push) Has been cancelled
Release / check (push) Successful in 2s
Release / release (push) Has been skipped
2026-10-09 22:23:23 +02:00
2d96f28091
feat(site): redesigned /download, releases and links moved from GitHub to Forgejo
Some checks failed
CI / backend (cargo test + clippy) (push) Has been cancelled
CI / frontend (lint + test + build) (push) Has been cancelled
CI / mod (gradle test + checkFolderLimit) (push) Has been cancelled
- /download: the jar as an in-game item (pixel heart in an inventory slot, vanilla-style tooltip with version, size and SHA-256, copy button), spec list, three install steps, release timeline
- releases read through a cached nginx proxy (/api/releases): Forgejo's API has no CORS headers
- README, footer and landing links point to git.wihuk.pro/boba/LoVisual (the GitHub repo they used does not exist)
- release workflow publishes through the Forgejo API and ships lovisual.jar.sha256
- fix i18n interpolation placeholders ({{x}}) in the download strings
2026-10-09 22:15:55 +02:00
fa08d50704
ci: make the backend job work on the local Forgejo runner
minio/minio is gone from Docker Hub (use the bitnami image that starts without a command), install psql/protoc/socat in the bare job container (no sudo), forward the services to localhost, and fetch non-mirrored actions from github.com.
2026-10-09 22:15:55 +02:00
b0ee4ab317
build(backend): one shared Dockerfile with cargo cache mounts, sequential compose build, stripped release binaries
Some checks failed
CI / backend (cargo test + clippy) (push) Failing after 1s
CI / frontend (lint + test + build) (push) Failing after 26s
CI / mod (gradle test + checkFolderLimit) (push) Successful in 1m57s
All four services now share one builder stage (dependencies compile once per
deploy, not once per service). BuildKit cache mounts keep the cargo registry
and target/ between deploys: a one-line change rebuilds in ~16 s instead of
recompiling the whole dependency tree.
2026-10-09 22:01:09 +02:00
cc33b6e4fc
feat(mail): redesigned transactional emails (banner, bulletproof button, copyable link, preheader, ru/en) with tests
Some checks failed
CI / backend (cargo test + clippy) (push) Failing after 1s
CI / frontend (lint + test + build) (push) Failing after 1m25s
CI / mod (gradle test + checkFolderLimit) (push) Successful in 5m7s
2026-10-09 21:52:46 +02:00
c57f851a8b
feat(accounts): outgoing mail over SMTP (Resend), email verification, fail-closed password reset
- mail/ module (lettre, ru/en templates), links built only from PUBLIC_BASE_URL
- migration 0006: accounts.email_verified_at, shared email_tokens table (verify + reset), existing accounts marked verified
- reset mailer no longer logs tokens; RESET_MAIL_MODE=log is dev-only and refused with COOKIE_SECURE=true; Disabled by default answers 503
- forgot-password and resend-verification do their work in a background task (no timing oracle)
- device linking requires a verified email; email_verified exposed via /me and gRPC
- gateway rate limits, SMTP_* in compose and .env.example
- frontend: verify, forgot-password, reset-password pages, verify banner, ru/en strings
2026-10-09 21:08:33 +02:00
12ce6216b6
docs: accounts-service email plan (Resend SMTP, verification, password reset), TODO phase 11 closed 2026-10-09 19:25:55 +02:00
f4e15b45c9
fix: CI workflow, password reset flow, health/limits in services, session refactor, dead mixin stub cleanup 2026-10-09 19:21:17 +02:00
45dd592c40
docs(mod): design for Optimize layer (ZakoOpt port, GL/Vulkan backends, frame budget) 2026-10-09 18:31:38 +02:00
edd6a3dc0b
feat(mod): cosmetics settings category with custom card previews, in-chat widget quick settings, HUD and ClickGUI look pages, TotemSound
- Cosmetics: new Settings category with kind pills (Wings, Hats, Models, Masks, Weapons) and a card grid; Wings, ChinaHat, TazikHat,
  CustomModels, TrollfaceMask and Knife moved to ModuleCategory.ACCESSORIES and hidden from the Modules panels
- Card previews: pick a picture (native dialog or drag and drop) and crop it in an editor; PreviewCrop, PreviewStore, PreviewEditor
  stored under config/lovisual/cosmetics/previews
- HUD: right click a widget while the chat is open to get a popup with its toggles, sliders and modes (quick settings)
- Themes tab: HUD and ClickGUI pages; new ClickGuiLookConfig replaces hard-coded panel blur constants, HudGlobalConfig look defs
- TotemSound: own sound on totem pop (everyone/self/others, volume, pitch, mute vanilla through SoundEngineMixin)
- tests: CosmeticKind, PreviewCrop, QuickSliderMath, TotemSound; ./gradlew test green
2026-10-07 17:54:25 +02:00
8bc884c297
feat(mod): GodRays, Knife melee skins, Wings Bedrock models, EnchantGlint animated styles, shader theme backdrop
- GodRays: PostProcessPass PRE_HAND, godrays.frag (radial sky blur to the sun over the scene, depth from mainDepth),
  GodRaysUniforms, GodRaysSkyMixin takes sunAngle/sunset colour from SkyRenderState; off under shaderpacks (Iris)
- Knife (Melee Skins): 33 skins from Bedrock geo/anim in assets/lovisual/knife, animator (static_idle, draw/inspect/melee/run,
  0.2 s crossfade, Catmull-Rom) with background baking, first/third-person render, sounds, mixins ItemInHand/PlayerItemInHand/Minecraft
- Wings: wingSource Procedural/Model with 14 textured Bedrock models (WingModelDef/WingModels/WingModelRenderer, BedrockClip +
  procedural angel/demon/dragon); shared Bedrock parser util/bedrock (GeoParser, GeoFaces, Channel, Clip)
- EnchantGlint: Pulse/Fire/Galaxy/Hologram/Glitch/Sparkle/Aurora styles in glint/style, coverage setting, custom animated
  texture matrix via GlintTextureMixin.styleMotion; lang en/ru for all new settings
- Themes: shader backdrop for ClickGUI (Backdrop record, 6 modes, intensity/speed/scale, ui_theme_backdrop_batch.frag with
  700 ms REVEAL/ERASE wipe, ThemeBackdrop2D in BackgroundComponent), ThemeEntry.backdrop persisted in JSON and profile codec,
  6 presets with backdrops, backdrop settings in the theme editor
- tests: GodRaysSun, GlintStyles, Knife assets/animator, WingModel, Backdrop, bedrock Channel; ./gradlew build green
2026-10-05 19:55:49 +02:00
6c641c4a94
feat(mod): P1 modules (AutoSprint, TotemCounter, EnchantGlint, ArmorColor, PlaceAnimation), CustomModels, KineticLyrics fix
- AutoSprint, TotemCounter, EnchantGlint (styles, texture repaint, scroll speed/scale mixin), ArmorColor (durability colouring, targets, pulse),
  PlaceAnimation (block slides in from the hand; chunk-mesh hiding incl. Sodium, moving-block render), aligned with evo behaviour
- CustomModels: Chicken, Rabbit and Verity (Blockbench) models for chosen players, bundled assets, render-state carrier + submit redirect
- KineticLyrics: fix track key wiped by reset() (lyrics never applied, lrclib hammered every tick); new LyricsFinder with ranked lrclib search,
  unsynced timing estimate, NetEase fallback and retry on busy services; tests for the pure parts
- fix mode()/modeSetting() misuse for new modules; TODO updated
2026-10-02 19:54:27 +02:00
60b4fedb29
feat(mod): align ElytraTrails and Blizzard with evo (real wing-tip matrices, ribbon styles, ground-aware snow, whiteout fog, hide vanilla weather), spec tests 2026-10-02 15:58:33 +02:00
9661ff638d
feat(mod): ElytraTrails and Blizzard reviewed and fixed, shared trail ribbon, spec-style tests 2026-10-02 14:26:41 +02:00
622984f619
docs(mod): note chat-service prod deploy 2026-10-02 14:13:26 +02:00
a4638d386d
fix(mod): SpatialGui transparent inventory (no dim overlay in capture, premultiplied composite) 2026-10-02 13:55:27 +02:00
e82efb74e7
feat: GuiPresence (chat-service presence backend, gateway route, mod module); restore TODO history 2026-10-02 13:41:49 +02:00
8d9a2ad0d6
feat(mod): ProjectileTrails, KillEffect death modes (Shatter/Ascend/Explosion/Disintegrate), TNT fuse bar; compact TODO
Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-10-02 10:01:37 +02:00
483d6bfb93
docs(mod): detail evo port plan in TODO
Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-10-02 09:50:15 +02:00
e604a48c31
fix(mod): smaller module description plaque, tooltip auto-scale to GUI scale
Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-10-02 09:49:02 +02:00
0504be5b57
feat(mod): scripted HoldMyItems on LuaJ (hand/item/model scripts, addons, vanilla overrides, particles, camera)
Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-10-02 09:47:30 +02:00
44353e893c
feat: mod platform integration (showcase, cloud slots, cloud screen, server-side unlink)
Mod:
- %config slots/pull/publish/unpublish for the four cloud slots
- %showcase [new|popular] [page] | load | copy, with number references
- %cloud opens a CloudScreen (link/unlink, slots, showcase) on vanilla widgets
- %config load IDDQD works offline (everything off except ChinaHat)
- default backend URL is now the production gateway
- shared ConfigRemoteApplier and ClientThread replace per-class copies
- %link unlink revokes the link on the server, then clears the local token

Backend:
- POST /device/revoke (RFC 7009 style self-revoke, always 204), rate limited
  to 10/min per IP at the gateway

CloudScreen is compiled but has not been opened in a running client yet.
2026-10-02 09:23:44 +02:00
e00ea8eb11
feat: frontend perf and a11y pass, plus mod visuals, hero main menu, Simple Voice Chat and vanilla chat autocomplete
Frontend:
- replace the i18next stack with a small typed i18n module
- hero clouds removed, llms.txt, HUD widget ARIA fixes and tests

Mod:
- TargetESP constellation mode; tracker and colors extracted
- JumpCircles: 7 new shapes, shared animation and color pipeline
- KillEffect blood mode with Burst/Fountain/Ring/Spray styles
- main menu: menuLayout setting (orbs/hero) and hero screen
- Simple Voice Chat soft integration: VoiceChat module and HUD panel
- renderer/quick: static Draw facade with glass outline
- vanilla chat: Baritone-style autocomplete popup for the % command prefix
2026-10-01 21:29:54 +02:00
167405aed0
perf(frontend): replace react-markdown with a small safe renderer (DownloadPage 120 KB -> 6 KB) 2026-09-30 16:27:32 +02:00
d629ccf496
perf(frontend): drop the motion library for CSS keyframes and small FLIP/presence hooks 2026-09-30 16:26:36 +02:00
7172652ac3
perf(frontend): defer landing lower sections and voxel backdrop, skip guest refresh 401, fix hud a11y 2026-09-30 16:24:28 +02:00
b170227adf
perf(frontend): route-level code splitting, main chunk 538 -> 491 KB
Lighthouse (production, default mobile 4x-CPU profile) scored
Performance 33/100, dominated by one ~536-538 KB entry chunk that
bundled every route's code regardless of which page a visitor landed
on -- the "chunks are larger than 500 kB" Vite warning on every build
this session.

Converted every route except / and the 404 catch-all to React Router
8's native route.lazy (blocks navigation until the chunk is ready --
no separate Suspense fallback needed). AppShell/HomePage/NotFoundPage/
RequireAuth stay eager since they're needed on every load regardless.

Result: main chunk 490.84 KB, no >500kB warning, one small chunk per
route (LoginPage 1.4 KB, ThemesPage 15.5 KB, AccountPage 11 KB, etc.)
loaded only when actually visited.

Fixed a real race the lazy boundary exposed: /login and /register
share an "Почта" field label, and during the chunk swap between them
the old page can stay mounted a beat longer than before -- a test
grabbing the field by label could land on the about-to-unmount one.
Also bumped RTL's asyncUtilTimeout and vitest's testTimeout, since the
route-transition + findBy chain didn't always land inside the old
1000/5000ms defaults under full parallel test-suite load.

Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-09-30 16:06:45 +02:00
6b0633034d
feat(frontend): SEO — sitemap, canonical link, structured data
- robots.txt now also points at a real sitemap.xml (public pages
  only: /, /download, /themes, /showcase) and disallows the
  auth-gated routes (/account, /configs, /link) that have nothing
  useful to a crawler
- canonical <link> on the root page
- SoftwareApplication JSON-LD so Google can render a rich result
  (name, free price, icon) instead of a plain blue link

Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-09-30 15:48:44 +02:00
9744dc7f24
fix(frontend): add a real robots.txt, cache hashed assets forever
Lighthouse audit findings:
- No robots.txt existed, so nginx's SPA fallback (try_files -> index.html)
  served the React app's HTML at /robots.txt -- crawlers got 44 "syntax
  not understood" lines instead of directives.
- No Cache-Control on /assets/*, so every visit re-fetched a hashed,
  content-addressed bundle that can never actually change under that
  URL. Lighthouse estimated 936 KiB/visit wasted on this alone.

Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-09-30 15:40:04 +02:00
54b47db7c1
docs(plan): restore full plan and integrate phase 11 design 2026-09-30 12:29:35 +02:00
fdc239db88
feat(mod): %policy command and clickgui lock 2026-09-30 12:24:43 +02:00
33cff90c82
feat(mod): apply server policy from the proxy 2026-09-30 12:24:42 +02:00
711fcafc3a
feat(policy): velocity plugin sending a lovisual:policy payload 2026-09-30 12:08:02 +02:00
af2b417289
docs(plan): design phase 11 server policy plugin 2026-09-30 12:08:02 +02:00
676dc4f441
docs(plan): record 8.5.3 top-4 split wave 2026-09-30 11:33:17 +02:00
71f779c8ee
refactor(hud): split BetterButtons to 197 lines
Settings values and visibility predicates move to ButtonStyleSettings,
icon drawing to ButtonIconRenderer; facade keeps the public static API
and getters. Drops three dead one-liners (getLastContext,
renderCenteredText, renderLeftAlignedText) and the unused
renderButtonInternal wrapper.
2026-09-30 11:32:17 +02:00
76bd8e9510
refactor(hud): split ScriptedTriangulatorHudPanel to 189 lines
Rendering moves to ScriptedTriangulatorRenderer, prop maps and cache
signatures to scripted/panel/; records and row helpers stay nested so
caller references (Panel, Palette, row, rows, idString) keep working.
2026-09-30 11:22:54 +02:00
3e57542bad
refactor(aim): split RotationManager to 199 lines
State machine, mutable state and server-rotation packet tracking move to
rotation/internal/; the singleton, event wiring and public API stay put.
2026-09-30 11:17:03 +02:00
7e8b6b6467
refactor(clickgui): split ConfigDiffPanelComponent to 167 lines
Header buttons, body text and scrollbar move to package-private helpers
under config/diff/; the public API, rendering order and math stay as-is.
2026-09-30 11:07:33 +02:00
6fa36f8b32
perf(frontend): memoize ColorField/GradientField with stable callbacks
React.memo alone does nothing here: PaletteTabs built a fresh
`(hex) => setColor(slot, hex)` closure per field on every render, so
memo's prop comparison always saw a "changed" onChange and re-rendered
anyway. Stabilized it properly:

- setColor/setGradient read draft/onChange from a ref (updated in a
  useLayoutEffect, not during render -- oxlint's react(refs) rule
  correctly flags a ref write in the render body) so they keep a
  stable identity (useCallback, empty deps) across edits
- per-slot wrapper closures are built once in a useMemo keyed off
  those now-stable functions, not off `draft`

This doesn't change the preset-switch case measured earlier (every
field's value genuinely changes then, so memo correctly re-renders
all of them -- that cost is what startTransition already covers). It
does stop sibling fields re-rendering on interactions that don't
touch them: undo/redo, tab switching, hovering unrelated panel
elements.

Claude-Session: https://claude.ai/code/session_01F1M1Jic1wTSn4igUENynmZ
2026-09-30 10:58:34 +02:00