Tags
Creators
Details
Licensed MIT
Published 4 months ago
Updated 6 days ago
All versions
1.7.0
Release
Guide NeoForge 1.7.0 (Customization, Themes, Cursors, Icons)6 days ago 48
Compatibility
Minecraft: Java Edition
1.21.1
Platform
NeoForge
Supported environments
Client-side
Server-side
Changes
[CHANGELOG] Version 1.7.0 (NeoForge)
In-Game Customization Editor: Icon, Cursor, Theme & Background Tabs, Custom Theme Creation, Per-Book Theme Overrides, Themed Effects, URL Media, Full Localization
🛠️ Changes:
- CurseForge Compliance (Maven Central) — Native media libraries (FFmpeg, JavaCV) are no longer fetched from personal GitHub repositories. They are now downloaded directly from the official Maven Central repository (
repo1.maven.org), fully complying with mod hosting security guidelines. - Opt-in Native Downloads — To further ensure user safety and consent, a new client config option
allow_native_downloads(default:false) has been added toguide-client.toml. Video playback requires the user to explicitly enable this option and restart the game, which then downloads the required FFmpeg binaries in the background. - In-Game Customization Screen — A new
CustomizationScreen(560×340) brings the whole theme editor in-game. It ships with a sidebar of 12 tabs (4 implemented this release), a book selector on the left, and scissor clipping against each tab boundary so nothing spills outside the active panel. Every widget pulls its colors from the active theme, including focused/unfocused border states. Layout is recomputed fromwinW/winH, so all buttons fit correctly at GUI scale 2, 3 and 4. The oldThemeSelectScreenhas been removed — its functionality now lives inside the Customization Screen, and the palette button on the book selector opens it directly. - Icon Tab — Pick from 5 item presets (
minecraft:book,writable_book,enchanted_book,knowledge_book,written_book) or from an image gallery inconfig/guide/user/icons/. PNG, JPG, JPEG, GIF and BMP are accepted. Icons are rendered with UV-based scaling to 32×32 directly on the GPU: the original texture is uploaded as-is and filtered at draw time, so custom icons stay sharp instead of getting muddied by a CPU-side resize. - Icon Rendering — Fit-To-Slot — Any image size is accepted. Large images are downscaled to fit the 16×16 slot with aspect preserved; small images (8×8, 16×16) are drawn at native size and centered instead of being stretched to fill the cell. Non-square images (250×141, 128×64, etc.) keep their proportions inside the square slot.
- Cursor Tab — Full cursor editor in
config/guide/user/cursors/. PNG, JPG, JPEG and BMP are accepted. Per-book cursor override with an automatic fallback chain:book.json > user UI choice for this book > global (_global) > default. The tab shows exactly which source is currently in effect, so you always know where the cursor comes from. - Cursor Scale (1×–4×) — A single button cycles cursor size through 1× / 2× / 3× / 4×. Scaling is done in nearest-neighbor, so pixel-art cursors stay crisp instead of getting blurred.
- Cursor Hotspot — Choose between Center (click point = image center — good for crosshairs and dots) or manual X/Y in original image pixels (good for arrows and pointers). The X/Y fields are disabled and dimmed while Center is on, and both fields save on the fly, not only on checkbox clicks.
- Global Cursor Fallback — Cursor choice is stored per book, but a
_globalfallback can be set incustomization.jsonand is used for any book without its own override. The Cursor tab shows which of the four sources is currently in effect (book.json/user/global/default) directly under the preview grid. - URL Downloads For Icons & Cursors — Both tabs ship with a URL field and a Download button. Files are fetched through
MediaDownloadManager, validated by magic bytes (not just file extension), and saved into the same user folders as manual drops. Image formats: PNG, JPG, JPEG, GIF, BMP. Status is shown directly in the button label —§aOK/§cNot an image/§cBad URL/§cError. - Cursor Overrides In
book.json— Five new optional fields let a book force its own cursor set:cursor(main book screen),cursor_selector(book selector),cursor_diary(diary),cursor_scale(1–4, 0 = fall back to UI),cursor_hotspot("center"or"x,y", empty = fall back to UI). Same rules as the existingthemefield: an id forces the value, an empty string falls back to the normal behavior. - Theme Tab — Full list of 70 theme fields with an HSV picker, an alpha slider and a hex input, plus a live preview and 6 effect toggles. Built-in themes (
standard,blood,forest,cyber_tech,matrix,sakura,honey) are read-only: Apply/Reset are blocked and a 🔒 tooltip explains why. A colored square next to the theme name shows its source —local,serverorbuiltin— with a tooltip whose colors come fromguide.theme.source.*lang keys. - Background Tab — Three modes: Color (HSV picker + alpha + hex + live preview), File (gallery from
config/guide/user/backgrounds/with a preview of the selected image), and URL (link input with a grey placeholder and white typed text, auto-preview download throughMediaDownloadManager, cached after Apply). Background overrides are stored per-book and resolved with theuser:prefix for local files. - Themed Effect Toggles (Radio Mode) — Six theme effects (shake, flashes, falling glyphs, petals, and more) can be toggled from the Theme Tab. Only one effect can be active at a time: enabling a second replaces the first, and clicking an active toggle turns it off. Effects are now stored per book and per theme, so each book+theme combination keeps its own effect set. They run in every Guide screen —
GuideScreen,BookSelectorScreen,DiaryScreenandCustomizationScreen— and the editor shows the active effect live (startShake,updateMouseEffects,renderMouseEffects,onMouseClick). - CustomizationStore — A single JSON file at
config/guide/user/customization.jsonholds everything:icon,cursor,cursorScale,cursorHotspot,theme,effects,background. Loaded once on startup, written on Apply. Theme color overrides are stored per-book and per-theme — each base theme keeps its own set of overrides, so switching base themes no longer drags old paint across. Effect overrides follow the same per-book per-theme layout. - CustomizationResolver — Resolves the effective theme for UI through
ThemeManager.getStable()(no transition interpolation while a screen is open) and for gameplay rendering throughThemeManager.getCurrent(). - ThemeManager Additions —
getStable()returns the theme without transition interpolation, for editor UI.withOverrides()andwithEffects()layer per-book color overrides and per-book per-theme effects over a base theme.ThemeAccentreserves 8 accent fields for a future single-accent-color feature.ThemeManager.getThemesDir()andisValidThemeId()expose the local themes folder and the id validator as reusable helpers. - Create Custom Theme — The Theme Tab ships with a Create Theme button that opens a small modal: type a lowercase id (
a-z,0-9,_, up to 32 chars), press Enter or Save, and the current editor state is written toconfig/guide/themes/<id>.json. The theme reloads immediately and becomes the active one. Reserved ids (built-in themes), existing files and already-taken ids are rejected with a short inline hint. - Delete Custom Theme — Local themes can be deleted straight from the Theme Tab. A red ✕ button sits inside the base-theme selector bar. Click it while a local theme is active to open a confirmation modal; built-in and server themes show the ✕ greyed out and cannot be removed.
- Live Color Preview — Dragging the HSV picker, the hue strip or the alpha slider recolors the whole editor immediately — window border, sidebar, tab buttons, buttons and theme swatches. The preview is non-destructive: it disappears when you switch to another field, press Apply, Reset, or change the base theme. The same preview is pushed to
CustomizationScreenso the entire window follows the picker in real time. - Per-Book Theme Overrides With Migration — Theme color overrides are now stored as
theme.<book>.<themeId>.<field>instead of the old flattheme.<book>.<field>. Old files are migrated on first load: existing overrides are moved under thestandardtheme id, so nothing is lost and the change is silent for players. Empty themes and empty books are pruned automatically, so the JSON never accumulates dead entries. - Per-Book Per-Theme Effect Overrides — Theme effects are now stored as
effects.<book>.<themeId>.<effect>and follow the same migration path as color overrides. The old"global"key is dropped on first launch. Only LOCAL themes can have their effect toggles edited; BUILTIN and SERVER themes show their active effect as a non-clickable green marker. - Read-Only Themes By Source — Whether a theme is editable is now decided by its source, not by a hardcoded id list. BUILTIN and SERVER themes are read-only — Apply, Reset and the effect toggles are locked, and the ✕ button is disabled. LOCAL themes (created through Create Theme or dropped into
config/guide/themes/) are fully editable and deletable. - Reserved Theme IDs — The seven built-in ids (
standard,blood,forest,cyber_tech,matrix,sakura,honey) are now reserved. They cannot be created by the player, cannot be loaded from server themes, and cannot be removed. Theme ids already taken by server or local themes also block Create Theme with a dedicated ID already taken message. - Theme Inheritance For Selector & Diary — The book selector and the diary now follow the same theme context as the last opened book. Open
guide, paint its border, close it — the selector and diary use the same overrides.ThemeManagerkeeps alastActiveBookNamespacealongside the transient one, so once a book is opened, both screens pick up its customization automatically. - Per-Book Theme Forcing In
book.json— Two new optional fields,theme_selectorandtheme_diary, let a book override the theme of the book selector and diary screens respectively while it is the last active book. Same rules as the existingthemefield: an id forces the theme, an empty string falls back to the normal behavior. Useful for showcase books that want to leave their visual signature on the menu. - Status In Buttons — Apply, Reset and Refresh now show their result directly in the button label —
§aПрименено/§aОбновлено/§cСброшено/§cОшибка— reverting to the default label after roughly two seconds. No separate status line, no layout shift. Short error strings (§cПусто,§cНе HTTP(S),§cНет файла) are kept short enough to fit inside a 90 px button. The same behavior is wired up in the Icon, Cursor, Theme and Background tabs. - Icon Prefixes —
book.jsonicons accept explicit prefixes now:item:minecraft:bookforces an item,texture:my_icon.pngforces a PNG,user:file.pngloads fromconfig/guide/user/icons/. Unprefixed strings still work through the legacy heuristic. If an icon cannot be resolved, a warning is logged and the button falls back tominecraft:bookinstead of rendering blank. - URL Mode in Background Tab — The URL box uses the reworked
GuideEditBox, so the caret, selection and input handling all work correctly. The placeholder draws in grey while the field is empty, the typed value in white, and the preview is downloaded automatically after Apply. Switching to a different URL now correctly re-downloads the preview instead of reusing the previous one. - GuideEditBox — Editable Mode — The shared edit box now supports an
editableflag. When disabled, the field dims, refuses keyboard/mouse input, and drops focus automatically. Used by the Cursor tab to lock the X/Y hotspot fields while Center is on. - Custom Tooltips — Custom tooltips on the Cursor tab are rendered through
font.split()with a fixed wrap width and automatic edge detection. Long strings no longer run off the right edge of the screen, and tooltips flip to the left / top side of the mouse when there is not enough room. - HTTP User-Agent Headers —
MediaDownloadManagernow sends a properUser-AgentandAcceptheader with every request. Wikimedia Commons, Imgur and GitHub no longer respond with HTTP 403 to image downloads. - Localization — Roughly 150 new keys across
en_us.jsonandru_ru.json:guide.customization.*for headers, buttons, statuses and errors, plusguide.customization.icon.*,cursor.*,theme.*,background.*, and 70guide.customization.theme.field.*keys for the theme field labels. Both files are kept in sync. - Hooks in Existing Classes —
GuideScreen.renderChapterBackgroundOrVanilla()now reads the background override fromCustomizationStore.getBackgroundOverride().GuideScreen.resolveChapterBgTexture()understands theuser:prefix.BookSelectorScreen.BookButtonreads the icon override (user:/item:/texture:) and renders it with fit-to-slot UV scaling.ThemeManager.getCurrent()applies color overrides and effects together.ModCommandsno longer routes to the removedThemeSelectScreen. Cursor overrides are resolved inGuideScreen,BookSelectorScreenandDiaryScreenthrough the same fallback chain.
🐛 Fixes:
- Missing FFmpeg Chat Warning — If a player tries to play a video while the FFmpeg libraries are missing or disabled in the config, the mod now displays a clear, localized message in the chat explaining how to enable video support (
allow_native_downloads = true). - Theme Manager NPE On Startup —
RESERVED_IDSwas declared belowINSTANCE, so the constructor'sloadThemes()call hit aNullPointerExceptionbefore the set was initialized. Static fields were reordered, startup is now clean. - Picker Jitter on Theme Switch — The HSV picker used to jump while the theme transition was interpolating. It now reads through
ThemeManager.getStable()and never samples a mid-transition value, so the cursor stays where the author put it. - Effect Buttons Not Resetting — Toggling an effect back off read the override after inverting it, so the button and the stored state could desync. The override is now read first and inverted afterwards.
- Effects Were Selector-Only — Effects used to run only in the book selector. They are now applied in every Guide screen and stored per book and per theme, so each book+theme combination keeps its own effect set.
- Builtin Themes Were Editable — Editability is now decided by theme source instead of a hardcoded set. BUILTIN and SERVER themes are read-only — Apply, Reset and the effect toggles are locked, and a 🔒 tooltip explains why. LOCAL themes stay fully editable.
- Layout Broke at GUI Scale 3/4 — Button positions are now computed from
winW/winHwith per-tab scissor clipping, so no control overflows the panel at higher GUI scales. - Icons Looked Blurry — Icon rendering no longer calls
resizeSubRectTo. The original texture is uploaded as-is and scaled with UV coordinates, so the GPU filters it cleanly instead of the CPU muddying it first. - Icon/Cursor Refresh Didn't Rebuild The Grid — After clicking Refresh, newly added files did not appear and deleted files left an empty frame in place. The grid is now rebuilt after every scan, so changes show up instantly without leaving the Customization screen.
- Texture Leak On Refresh —
scanFiles()cleared the preview map but never released the oldDynamicTextureinstances. Old GPU textures are now released before every rescan, preventing a slow VRAM leak when refreshing the Icon and Cursor tabs often. - Cursor Hotspot X/Y Not Saved While Typing — Hotspot X/Y only persisted when the Center checkbox was toggled. Values entered into the fields were lost on screen close. They are now saved as soon as the number changes.
- Cursor Not Applied Live In Customization — Changing the cursor in the editor did not update the actual mouse cursor until the screen was reopened.
CustomizationScreennow applies the cursor on init and re-applies it after every change in the Cursor tab — picking an image, cycling scale, toggling Center, editing X/Y, downloading from URL and pressing Reset all take effect immediately. - Cursor Tooltips Cut Off / Wrong Style — Long hotspot tooltips ran off the right edge of the screen and the X/Y tooltips used a hand-rolled dark background that did not match vanilla. They are now split with
font.split(), flipped to the opposite side of the mouse when needed, and rendered through the standard tooltip renderer. - Cursor Tooltip Y Disappeared — A 2 px gap between the X and Y fields meant hovering exactly between them produced no tooltip at all. The custom tooltip hitbox now covers the full control row.
- Bad PNG Signature When Loading URL Images — Downloading a non-image URL (HTML page, redirect, wrong format) crashed the preview with
IOException: Bad PNG Signature. Files are now checked by magic bytes before decoding, a short error is shown in the UI, and the raw response is logged with its first bytes for diagnostics. - JEI Integration Silently Swallowed Errors — Recipe and use lookups in
JeiIntegrationcaughtThrowablewithout logging, so failures in JEI / EMI / REI left no trace. Both paths now log throughGuide-JEIwith the failing item stack. - HTML Color Codes in Button Status — Status values in the lang files now use
§a,§cand§7prefixes instead of HTML, so colors render as intended in-game. - Local Backgrounds Not Applying — Local files needed the
user:prefix and are now read fromconfig/guide/user/backgrounds/, matching the icon and cursor folders. switchBookReset State With One Book —switchBookused to wipe the editor state even when there was only one book in the selector. It now returns early ifsize() <= 1, so a single-book setup keeps its edits.- Background Cache Outlived Its File — Deleting a local background file or replacing it with new content left the old texture hanging.
GuideScreen.clearBackgroundCache()now releases every loaded background texture, clears the URL caches and is called from Refresh and Reset in the Background tab. - URL Preview Stuck On First Link — Once a URL preview was loaded, changing the link and pressing Apply never downloaded the new one. The preview now tracks the source URL and re-downloads when the input changes.
- File Preview Read On Every Frame — The File-mode preview used to run
NativeImage.read()and register a newDynamicTextureevery frame, leaking memory on large PNGs. The texture is now cached per selected file and released when the selection changes. - Background Tab Ignored Theme Changes — Switching the base theme left the background preview showing the old theme.
BackgroundTab.onThemeChanged()now releases both preview caches and re-syncs the override when the base theme changes from the Theme tab. - Book Theme Applied Multiple Times —
GuideScreen.init()used to push the book theme on everyrebuildWidgets(), resetting the transition mid-fade.pushBookThemenow checks againstgetCurrentThemeId()(which returns the target id during a transition) so the transition completes cleanly. - Customization Screen Shake Moved The Background — The dark backdrop in
CustomizationScreenused to shake along with the window because it was drawn inside the same pose transform. It is now drawn before the shake pose, so only the window itself moves. - Duplicate Modals Under The Create Dialog — The hex readout and picker used to render on top of the Create / Delete confirmation modals. They are now skipped entirely while a modal is open, so only the modal is visible.
🧹 Removed / Cleaned:
ThemeSelectScreen.javaRemoved — Its functionality moved intoCustomizationScreen. Theguide.theme.select.titlekey was dropped along with it.- Hardcoded Russian Strings Removed —
IconTab,CursorTab,ThemeTabandBackgroundTabnow useComponent.translatableeverywhere instead of hardcoded strings.Theme.getFieldLabel()resolves throughguide.customization.theme.field.*instead of a 70-branch switch. - Hardcoded
READONLY_THEMESRemoved — The hardcoded read-only id set is gone; editability now comes fromThemeSource(BUILTIN/SERVER/LOCAL).
Optional dependencies
Unavailable version
Unavailable version
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:ubKIGRC6:JLxyUMZ5"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:ubKIGRC6:JLxyUMZ5"
}

