Changelog¶
What changed in every release of CoolCatLib: Core and CoolCatLib: Canvas, for each Minecraft version. The page is built from each version branch's CHANGELOG.md, so it's always up to date. Downloads are on CurseForge and Modrinth.
Latest releases¶
| Mod | Minecraft | Version | Status |
|---|---|---|---|
| CoolCatLib: Core | 26.1 – 26.1.2 | 26.1.2-1 |
Unreleased |
| CoolCatLib: Core | 1.21 – 1.21.1 | 1.21.1-1 |
Unreleased |
| CoolCatLib: Core | 1.20.1 | 1.20.1-1 |
Unreleased |
| CoolCatLib: Canvas | 26.1 – 26.1.2 | 26.1.2-1 |
Unreleased |
| CoolCatLib: Canvas | 1.21 – 1.21.1 | 1.21.1-1 |
Unreleased |
| CoolCatLib: Canvas | 1.20.1 | 1.20.1-1 |
Unreleased |
What's new¶
CoolCatLib: Core 26.1.2-1 — Unreleased
- CoolCatLib is split in two mods: CoolCatLib: Core (
coolcatcore, packagenet.ixdarklord.coolcatcore), this one, and CoolCatLib: Canvas (coolcatcanvas), which now holds screen effects, skyboxes, GUI widgets,RenderUtilsandEasing. The mod id, package, asset namespace, Fabric entrypoints (coolcatcore:common, ...) and commands (/coolcatcore,/coolcatcore_client) all changed fromcoolcatlib. - A cross-loader platform layer, so mods built on CoolCatLib: Core no longer need Architectury API:
- Events (
api.event.v2):EventInvokerkeeps listeners in common code, ordered byEventPhase, and is found by its listener type (EventInvoker.lookup(ServerTickEvents.End.class)) or its constant (ServerTickEvents.END).EventInvoker.create(Type.class)makes a mod's own event, combining listeners by return type (void,EventResult,EventResultHolder,boolean). - Built-in events: server lifecycle and ticks, datapack contents sync (
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS: per player on login and after/reload), player join/leave/tick, entity load, block break/place, commands; client ticks, player join/leave, HUD rendering, item tooltips, client commands. api.registry:DeferredRegister/RegistryEntry,CreativeTabs,ReloadListeners.api.menu.ExtendedMenus: menu types that open with extra data.api.network.Network: serverbound/clientbound payloads and sending.Network.canPlayerReceive(player, type)tells whether a player's connection accepts a payload (false for clients without the mod and for GameTest mock players; NeoForge throws when sending to them).- Record payloads without a
StreamCodec:Network.registerServerbound(MyPayload.class, receiver)(or with an explicitType) derives the codec from the record's components throughPayloadCodecs, which knows primitives, strings, common Minecraft types, enums, nested records, arrays,Optional,List,Set,Map,EitherandResourceKey. Other types are added withPayloadCodecs.register/registerFactory; registering a payload with a component type that has no codec throws right away, naming the component.
- Record payloads without a
api.client.registry: key mappings, menu screens, tooltip components.api.platform.Platform: loader, environment, mod checks, folders, the running server, fake players.- Mod constructors (
api.core):ModConstructor(both sides),ClientModConstructor,ServerModConstructor(dedicated server) andDataGenerationConstructorare written once in common code, each with a construct stage and a setup stage (DataGenerationContext.addProviderfor data providers).- Fabric needs no Java entry class: list them under the
coolcatcore:common,coolcatcore:client,coolcatcore:serverandcoolcatcore:datagenentrypoints, plusapi.core.fabric.FabricDataGenerationEntrypointunderfabric-datagen. - NeoForge: extend
api.core.neoforge.NeoForgeModEntrypointin the@Modclass and callcommon(...),client(() -> ...),server(() -> ...),dataGeneration(...); the mod id comes from the container.
- Fabric needs no Java entry class: list them under the
EventResult.pass()/interrupt()/allow()/deny(), andEventResultHolder.result()/getValue().- A config system (
api.config): - Declare configs with
Config.builder(modId, scope)(typed values, nested groups, presets) or from an annotated class withConfigObject.register. - Scopes:
CLIENT,COMMON,SERVER(synced to players) andWORLD(stored per world, seeded fromdefaultconfigs, synced). - Types: booleans, ranged numbers (optionally sliders), strings (length/pattern), enums, colors, ids, lists, and any
Codec; customConfigTypes with their own editors. - TOML (default) and JSON5 files with generated comments; a config whose format changes converts its old file once (kept as
.bak); broken files are backed up;version/migrationandaliaseshandle renamed or moved settings. - Hot reloading of edited files, change listeners and
ConfigEvents:LOADED(first read),RELOADED(hot reload, the reload command orConfig.reload()),UNLOADING(a world config before its server's values are dropped),VALUE_CHANGED(each value, with its old and new value),CHANGED(once per batch),SAVEDandSYNCED. serverOnly()values that never leave the server; operators edit synced configs in-game with permission checks.- Generated config screen: search, undo/redo, reset, presets, validation, dependencies (
enabledWhen), restart notices and list editing. Linked from the NeoForge mod list and Mod Menu. /coolcatcore config(server) and/coolcatcore_client config(client) commands: list, get, set, reset, reload, preset, open.STARTUPconfigs, read before content is registered (for item properties, which items exist...). Their values stay fixed until a restart; edits are saved for the next start. Joining a server compares them before entering the world: values must match by default (the client is offered to adopt the server's),useServerValue()values are taken from the server while connected, andlocalOnly()values stay per side.- Category popups: one category of a config in a small window with Save and Cancel, floating over the current screen or the game, e.g.
ConfigScreens.openCategory("mymod", "client/rendering"),ConfigScreens.categoryPopup(parent, config, path), or/coolcatcore_client config open <mod> <category>(with path suggestions). A single setting's path shows just that setting. - A color picker for color values (a popup with saturation/brightness, hue and alpha, hex input and dye colors), also available as
ConfigScreens.colorPicker. - The main config screen (shown for every mod, even one with a single config): a header with the mod's icon (a "?" when it has none; the list of every mod's configs has its own icon), and each config as a portrait navigation card with its own artwork (faint, brightening on hover; CoolCatLib: Core's per scope, or the mod's own at
assets/<modid>/textures/gui/config/cards/<config name>.png), its scope icon and a short label like "Server" (config.<modid>.<name>.label). Cards are centered, grow when hovered, and show a tooltip with the config's scope, contents, file and access. Mod Menu's CoolCatLib: Core button opens CoolCatLib: Core's own settings. - Page transitions: a config page's panels glide a little way into place (up from below when opened, down from above when going back, a shorter rise when opened from elsewhere) while growing from slightly smaller; the background stays still.
- Config screen effects: animations a theme names by id, drawn behind the panels, over the whole screen, and over each widget (buttons, toggles, sliders, text fields, cards, popup panels). Mods register their own on the client with
ConfigEffects.register(id, ConfigEffect)and use them withConfigTheme.Builder.effects(...),ConfigBuilder.effects(...)for one config, or"effects"inconfig_theme.json; an unknown id is skipped and an effect that throws is switched off, each logged once. The built-inConfigTheme.STARFALL, every theme's default, draws soft glows in the accent and small faint stars falling from the top, shifting with the mouse by depth (parallax). CoolCatLib: Core's client config turns effects and the page transitions on or off (Effects > Theme Effects / Page Transitions); both are always off on the Fast graphics preset. - Redesigned config screens: a top bar (title, scope badges, search), a category sidebar, settings with descriptions and nested sections, and a bottom bar with the unsaved-changes status and actions; toggle switches, sliders, selectors and flat buttons; presets, confirmations and the color picker as popups. Icons are 64x64 textures in
assets/coolcatcore/textures/gui/config/icons/(smoothly filtered), replaceable by resource packs. ConfigTheme: each mod's own look, set per mod (ConfigTheme.setForMod) or per config (ConfigBuilder.theme/background): a fullConfigColorScheme(presetsDARK,LIGHT, andtinted(accent)for the dark scheme shaded toward the mod's color), a background texture by its path (cover, stretch or tile), the texture's opacity (textureOpacity, letting the panorama or world show through) and the backdrop color's opacity over the background (backgroundOpacity). Players can scale both for every mod in CoolCatLib: Core's client config (Background > Backdrop Opacity / Texture Opacity). By default the screens are see-through to the title panorama or the world. Resource packs can restyle a mod withassets/<modid>/coolcatcore/config_theme.json.- Popup panel sprites:
ConfigTheme.Builder.popupSprite(orpopup_spriteinconfig_theme.json) draws a nine-slice GUI sprite as the panel of popups (category popups, confirmations, the color picker) instead of the flat panel, andConfigScreens.categoryPopup(parent, config, path, theme)opens a category popup with its own theme, e.g. to match the screen it's opened from. - The config list shows each mod's icon (a theme can set another); config pages and their cards show an icon of their kind (client, common, server, world, startup).
Platform.getModName.- Dark and light mode: a sun/moon switch in every config screen's top bar, remembered in CoolCatLib: Core's own client config (
themeMode). Each theme has a light scheme too (ConfigTheme.Builder.lightColors, by default derived from the mod's accent;light_base/light_colorsinconfig_theme.json). - The main config screen's search bar searches every config it lists (names, keys, comments, group names, values), with results grouped by config; opening a result shows that config filtered to it. A config's own search covers only that config.
- Attachments, containers and handlers for items, blocks and entities:
api.attachment: typed data any entity (players included), block entity or item stack can carry. Each mod creates its ownAttachmentRegistry.create(modId)(and callsregister()while it initialises); its values are stored under its own id, in the<modid>:attachmentsitem component and a<modid>:attachmentstag in entity and block entity data. Declared once (ATTACHMENTS.builder(name, codec, default)), then used asMADNESS.get(player),set,update,modify,reset, or throughAttachmentHolder.of(...).- Persistent attachments save with their holder;
transientBuilderones never do.copyOnDeath()keeps a player's value through death (always kept through dimension changes and the End exit);keepOnDrop()carries a block entity's value into its dropped item and back when placed. sync(SyncPolicy):SELF(the player it belongs to),TRACKING,ALL, or any predicate. Only changed values are sent, at most once per tick; everything when a player starts seeing the holder, receives its chunk, joins, respawns or changes dimension.- On item stacks, defaults aren't stored, so stacks still stack.
- Persistent attachments save with their holder;
AttachmentEvents:CHANGING(cancel a change or replace the value),ADDED,CHANGED(in-place changes included),REMOVED,START_TRACKING/STOP_TRACKING(a player starts or stops receiving a holder's data) andRECEIVED(synced values arrived on the client), plus typed per-attachment helpers (onChanged(MADNESS, ...)).api.container:ContainerLayout(slot filters, limits, rolesSTORAGE/INPUT/OUTPUT/INTERNAL, which slots each face reaches) makesSlotContainers, vanillaContainers with insert/extract, listeners and layout-aware menu slots.AttachmentRegistry.containerstores one on any entity or block entity (saved and synced with the rest);ItemContainerskeeps one in a stack (ContainerItemfor items that have one);ItemTransfermoves items between any containers through faces.api.block:ExtendedBlockEntity(attachment shortcuts, handlers,serverTick/clientTickwithExtendedBlockEntity.ticker) andExtendedContainerBlockEntity(an inventory hoppers and comparators use; contents spill or, withkeepContentsOnBreak, stay in the item).api.handler:HandlerTypefor anything holders hand out (inventories, energy...), from the holder itself (HandlerProvider,HandlerMap) or registered providers and fallbacks for blocks, block entities, entities and items.HandlerTypes.CONTAINERalso finds vanilla containers (double chests as one).BlockHandlerCachekeeps a lookup until the block changes, its block entity goes, orHandlerType.invalidateis called.- Other mods reach these containers through each loader's own system, following the layout's filters, roles and limits: NeoForge item handler capabilities (blocks, entities and
ContainerItemstacks) and Fabric's Transfer API (ItemStorage.SIDEDfor blocks,ItemStorage.ITEMforContainerItemstacks). api.registry.BlockEntityTypes.create: block entity types from common code.- Storage menus (
api.menu.StorageMenuDefinition): a menu for a block's or an item's inventory, declared once (StorageMenuDefinition.grid(columns, rows)or placed slot by slot), registered withcreateMenuTypeand opened withopen(player, blockEntity, title)oropen(player, hand, title). Slots follow the container's layout and shift-click; the menu closes when the block is removed, the player walks away, or the item leaves its slot (which stays locked meanwhile).sync(attachment)andsyncValue(...)send extra values to the screen while it's open, andbutton(id, action)runs screen buttons on the server.api.client.gui.screens.StorageScreendraws any of these menus with no texture, and can be extended.
CoolCatLib: Canvas 26.1.2-1 — Unreleased
- First release: the render and visuals half of what used to be CoolCatLib, split out and built on CoolCatLib: Core. Everything below was moved from CoolCatLib into the
net.ixdarklord.coolcatcanvaspackage andcoolcatcanvasnamespace. - Screen effects (
api.client.effect): full-screen post-processing shaders whose uniforms can change every frame (vanilla's post chains bake them in at load). ScreenEffects.register(id, definition)from a vanilla-formatpost_effectJSON (vanilla's own included) or aScreenEffectDefinitionbuilt in code; any number stack, ordered bypriority, drawn over the world (WORLD) or over everything including the HUD and menus (SCREEN).- Smooth fades (
fade,Easing), timed pulses (enableFor), animated strength, conditions (activeWhen), strength functions of the frame (strength) and per-frame callbacks (onFrame). - Uniforms by name: set, animated (
animateTo) or bound to a function of the frame;autoBlendfades shaders that ignore the effect's strength. - Shaders get
Strength,Time,AgeandSeedplus noise and luminance helpers from#moj_import <coolcatcanvas:screen_effect.glsl>; persistent targets allow feedback effects; reloaded with resource packs; a failing effect is logged and skipped. - No effects of its own: mods bring their own
post_effectJSON and shaders, or use vanilla's (minecraft:invert, ...). api.effect.ScreenEffectControldrives a player's effects from the server.- Layers (
ScreenEffects.layers()): the draw order of every effect, from priorities until rearranged (move up/down, to a layer, to the top or bottom, reset). - An effects screen (
ScreenEffects.openScreen(), a key unbound by default, and/coolcatcanvas_client effectsin development environments only): every selectable effect with a switch, the active ones as drag-and-drop layers grouped by stage with a strength slider each, a live unblurred preview and a Preview mode hiding the panels. Players' choices (on/off, strengths, order) are saved toconfig/coolcatcanvas-screen-effects.json. Effects have adisplayName,descriptionandselectableflag for it. - Events (
ScreenEffectEvents):BEFORE_TOGGLE(cancellable) andTOGGLEDwith the cause (code, condition, timeout, player, server),STRENGTH_CHANGED,UNIFORM_CHANGED,LAYERS_CHANGEDandLOADED. - Custom skyboxes (
api.client.sky): layers drawn inside vanilla's sky pass, around the sun, moon and stars. Skyboxes.register(id, definition)from aSkyboxDefinitionbuilt in code orassets/<namespace>/skybox/<path>.json; resource packs add skyboxes with no code by listingdimensions(dimensions without a sky, like the Nether, get one while it shows).- Layer types:
cubemap(six faces in a 3x2 image),panorama(equirectangular),sprite(an image placed in the sky, e.g. a planet),gradient, andshader(your own fragment shader, with#moj_import <coolcatcanvas:sky.glsl>); any type can swap in its own fragment shader. - Per layer: blend mode (alpha, additive, multiply, screen), tint, orientation, rotation over real time, game time, the day or vanilla's sun/moon/star angle, flipbook animation with optional interpolation, day-time fade windows, rain fade, horizon/underwater fog, and 4 shader params.
- Hides vanilla's sky color, sunrise, sun, moon, stars, void, End sky and End flashes, fading them out as the skybox fades in.
- Runtime control: fades,
enableFor, conditions (activeWhen), per-frame callbacks, and per layer (Skybox.layer(name)) visibility, animated opacity and tint, and params set, animated or bound to a function of the frame.api.sky.SkyboxControldrives them from the server: enable, disable,toggle,setEnabled, timed pulses and layer changes, for one player or several (to(players),inLevel(level),everyone(server)). - Cheap: nothing runs while no skybox shows; a visible layer is one draw from a shared static mesh, all layers of a stage share one render pass and one uniform upload.
api.utils.Easing: easing curves.- GUI components and widgets (
api.client.gui.components: panels, scroll and drag widgets, slide animations,ColorableImageButton), andapi.client.utilsRenderUtils,NineSliceInfoandScreenAnchor. - Animated color gradients (
api.utils.ColorGradient): color stops looping around (ColorGradient.of(colors...)) or the full rainbow (RAINBOW,rainbow(saturation, brightness)), scrolling over time (withSpeed) and along the text or outline (withSpread), with each letter colored (perLetter(n)) or the whole text in one cycling color (wholeText(),RAINBOW_WHOLE). Presets:RAINBOW,RAINBOW_WHOLE,PASTEL_RAINBOW,FIRE,OCEAN,AURORA. - Gradient components:
gradient.literal("..."),gradient.apply(component)or a style withgradient.textColor()make a component animate wherever it's drawn (chat, tooltips, item names, signs, widget labels). In JSON text and commands (/tellraw) the color is"coolcatcanvas:rainbow","coolcatcanvas:rainbow_whole","coolcatcanvas:rainbow/<speed>/<spread>/<saturation>/<brightness>"or"coolcatcanvas:gradient/<speed>/<spread>/#RRGGBB/#RRGGBB..."; players without Canvas can't read it. - Gradient and outlined text (
api.client.utils.TextEffects):gradient(text, gradient)andrainbow(text)recolor existing text and stay animated when kept; outlined text in a solid color or a gradient. - Outlines (
api.client.utils.Outline): solid or a gradient (Outline.gradient,Outline.rainbow()), with a thickness and padding, drawn around any rectangle;ElementOutlines.set(widget, outline[, when])attaches one to any widget (vanilla's too), optionally only while a condition holds (hovered, focused...).
CoolCatLib: Core¶
26.1.2-1 — Unreleased (Minecraft 26.1.2 port)
✨ New Features
- CoolCatLib is split in two mods: CoolCatLib: Core (coolcatcore, package net.ixdarklord.coolcatcore), this one, and CoolCatLib: Canvas (coolcatcanvas), which now holds screen effects, skyboxes, GUI widgets, RenderUtils and Easing. The mod id, package, asset namespace, Fabric entrypoints (coolcatcore:common, ...) and commands (/coolcatcore, /coolcatcore_client) all changed from coolcatlib.
- A cross-loader platform layer, so mods built on CoolCatLib: Core no longer need Architectury API:
- Events (api.event.v2): EventInvoker keeps listeners in common code, ordered by EventPhase, and is found by its listener type (EventInvoker.lookup(ServerTickEvents.End.class)) or its constant (ServerTickEvents.END). EventInvoker.create(Type.class) makes a mod's own event, combining listeners by return type (void, EventResult, EventResultHolder, boolean).
- Built-in events: server lifecycle and ticks, datapack contents sync (ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS: per player on login and after /reload), player join/leave/tick, entity load, block break/place, commands; client ticks, player join/leave, HUD rendering, item tooltips, client commands.
- api.registry: DeferredRegister / RegistryEntry, CreativeTabs, ReloadListeners.
- api.menu.ExtendedMenus: menu types that open with extra data.
- api.network.Network: serverbound/clientbound payloads and sending. Network.canPlayerReceive(player, type) tells whether a player's connection accepts a payload (false for clients without the mod and for GameTest mock players; NeoForge throws when sending to them).
- Record payloads without a StreamCodec: Network.registerServerbound(MyPayload.class, receiver) (or with an explicit Type) derives the codec from the record's components through PayloadCodecs, which knows primitives, strings, common Minecraft types, enums, nested records, arrays, Optional, List, Set, Map, Either and ResourceKey. Other types are added with PayloadCodecs.register / registerFactory; registering a payload with a component type that has no codec throws right away, naming the component.
- api.client.registry: key mappings, menu screens, tooltip components.
- api.platform.Platform: loader, environment, mod checks, folders, the running server, fake players.
- Mod constructors (api.core): ModConstructor (both sides), ClientModConstructor, ServerModConstructor (dedicated server) and DataGenerationConstructor are written once in common code, each with a construct stage and a setup stage (DataGenerationContext.addProvider for data providers).
- Fabric needs no Java entry class: list them under the coolcatcore:common, coolcatcore:client, coolcatcore:server and coolcatcore:datagen entrypoints, plus api.core.fabric.FabricDataGenerationEntrypoint under fabric-datagen.
- NeoForge: extend api.core.neoforge.NeoForgeModEntrypoint in the @Mod class and call common(...), client(() -> ...), server(() -> ...), dataGeneration(...); the mod id comes from the container.
- EventResult.pass()/interrupt()/allow()/deny(), and EventResultHolder.result()/getValue().
- A config system (api.config):
- Declare configs with Config.builder(modId, scope) (typed values, nested groups, presets) or from an annotated class with ConfigObject.register.
- Scopes: CLIENT, COMMON, SERVER (synced to players) and WORLD (stored per world, seeded from defaultconfigs, synced).
- Types: booleans, ranged numbers (optionally sliders), strings (length/pattern), enums, colors, ids, lists, and any Codec; custom ConfigTypes with their own editors.
- TOML (default) and JSON5 files with generated comments; a config whose format changes converts its old file once (kept as .bak); broken files are backed up; version/migration and aliases handle renamed or moved settings.
- Hot reloading of edited files, change listeners and ConfigEvents: LOADED (first read), RELOADED (hot reload, the reload command or Config.reload()), UNLOADING (a world config before its server's values are dropped), VALUE_CHANGED (each value, with its old and new value), CHANGED (once per batch), SAVED and SYNCED.
- serverOnly() values that never leave the server; operators edit synced configs in-game with permission checks.
- Generated config screen: search, undo/redo, reset, presets, validation, dependencies (enabledWhen), restart notices and list editing. Linked from the NeoForge mod list and Mod Menu.
- /coolcatcore config (server) and /coolcatcore_client config (client) commands: list, get, set, reset, reload, preset, open.
- STARTUP configs, read before content is registered (for item properties, which items exist...). Their values stay fixed until a restart; edits are saved for the next start. Joining a server compares them before entering the world: values must match by default (the client is offered to adopt the server's), useServerValue() values are taken from the server while connected, and localOnly() values stay per side.
- Category popups: one category of a config in a small window with Save and Cancel, floating over the current screen or the game, e.g. ConfigScreens.openCategory("mymod", "client/rendering"), ConfigScreens.categoryPopup(parent, config, path), or /coolcatcore_client config open <mod> <category> (with path suggestions). A single setting's path shows just that setting.
- A color picker for color values (a popup with saturation/brightness, hue and alpha, hex input and dye colors), also available as ConfigScreens.colorPicker.
- The main config screen (shown for every mod, even one with a single config): a header with the mod's icon (a "?" when it has none; the list of every mod's configs has its own icon), and each config as a portrait navigation card with its own artwork (faint, brightening on hover; CoolCatLib: Core's per scope, or the mod's own at assets/<modid>/textures/gui/config/cards/<config name>.png), its scope icon and a short label like "Server" (config.<modid>.<name>.label). Cards are centered, grow when hovered, and show a tooltip with the config's scope, contents, file and access. Mod Menu's CoolCatLib: Core button opens CoolCatLib: Core's own settings.
- Page transitions: a config page's panels glide a little way into place (up from below when opened, down from above when going back, a shorter rise when opened from elsewhere) while growing from slightly smaller; the background stays still.
- Config screen effects: animations a theme names by id, drawn behind the panels, over the whole screen, and over each widget (buttons, toggles, sliders, text fields, cards, popup panels). Mods register their own on the client with ConfigEffects.register(id, ConfigEffect) and use them with ConfigTheme.Builder.effects(...), ConfigBuilder.effects(...) for one config, or "effects" in config_theme.json; an unknown id is skipped and an effect that throws is switched off, each logged once. The built-in ConfigTheme.STARFALL, every theme's default, draws soft glows in the accent and small faint stars falling from the top, shifting with the mouse by depth (parallax). CoolCatLib: Core's client config turns effects and the page transitions on or off (Effects > Theme Effects / Page Transitions); both are always off on the Fast graphics preset.
- Redesigned config screens: a top bar (title, scope badges, search), a category sidebar, settings with descriptions and nested sections, and a bottom bar with the unsaved-changes status and actions; toggle switches, sliders, selectors and flat buttons; presets, confirmations and the color picker as popups. Icons are 64x64 textures in assets/coolcatcore/textures/gui/config/icons/ (smoothly filtered), replaceable by resource packs.
- ConfigTheme: each mod's own look, set per mod (ConfigTheme.setForMod) or per config (ConfigBuilder.theme / background): a full ConfigColorScheme (presets DARK, LIGHT, and tinted(accent) for the dark scheme shaded toward the mod's color), a background texture by its path (cover, stretch or tile), the texture's opacity (textureOpacity, letting the panorama or world show through) and the backdrop color's opacity over the background (backgroundOpacity). Players can scale both for every mod in CoolCatLib: Core's client config (Background > Backdrop Opacity / Texture Opacity). By default the screens are see-through to the title panorama or the world. Resource packs can restyle a mod with assets/<modid>/coolcatcore/config_theme.json.
- Popup panel sprites: ConfigTheme.Builder.popupSprite (or popup_sprite in config_theme.json) draws a nine-slice GUI sprite as the panel of popups (category popups, confirmations, the color picker) instead of the flat panel, and ConfigScreens.categoryPopup(parent, config, path, theme) opens a category popup with its own theme, e.g. to match the screen it's opened from.
- The config list shows each mod's icon (a theme can set another); config pages and their cards show an icon of their kind (client, common, server, world, startup).
- Platform.getModName.
- Dark and light mode: a sun/moon switch in every config screen's top bar, remembered in CoolCatLib: Core's own client config (themeMode). Each theme has a light scheme too (ConfigTheme.Builder.lightColors, by default derived from the mod's accent; light_base/light_colors in config_theme.json).
- The main config screen's search bar searches every config it lists (names, keys, comments, group names, values), with results grouped by config; opening a result shows that config filtered to it. A config's own search covers only that config.
- Attachments, containers and handlers for items, blocks and entities:
- api.attachment: typed data any entity (players included), block entity or item stack can carry. Each mod creates its own AttachmentRegistry.create(modId) (and calls register() while it initialises); its values are stored under its own id, in the <modid>:attachments item component and a <modid>:attachments tag in entity and block entity data. Declared once (ATTACHMENTS.builder(name, codec, default)), then used as MADNESS.get(player), set, update, modify, reset, or through AttachmentHolder.of(...).
- Persistent attachments save with their holder; transientBuilder ones never do. copyOnDeath() keeps a player's value through death (always kept through dimension changes and the End exit); keepOnDrop() carries a block entity's value into its dropped item and back when placed.
- sync(SyncPolicy): SELF (the player it belongs to), TRACKING, ALL, or any predicate. Only changed values are sent, at most once per tick; everything when a player starts seeing the holder, receives its chunk, joins, respawns or changes dimension.
- On item stacks, defaults aren't stored, so stacks still stack.
- AttachmentEvents: CHANGING (cancel a change or replace the value), ADDED, CHANGED (in-place changes included), REMOVED, START_TRACKING/STOP_TRACKING (a player starts or stops receiving a holder's data) and RECEIVED (synced values arrived on the client), plus typed per-attachment helpers (onChanged(MADNESS, ...)).
- api.container: ContainerLayout (slot filters, limits, roles STORAGE/INPUT/OUTPUT/INTERNAL, which slots each face reaches) makes SlotContainers, vanilla Containers with insert/extract, listeners and layout-aware menu slots. AttachmentRegistry.container stores one on any entity or block entity (saved and synced with the rest); ItemContainers keeps one in a stack (ContainerItem for items that have one); ItemTransfer moves items between any containers through faces.
- api.block: ExtendedBlockEntity (attachment shortcuts, handlers, serverTick/clientTick with ExtendedBlockEntity.ticker) and ExtendedContainerBlockEntity (an inventory hoppers and comparators use; contents spill or, with keepContentsOnBreak, stay in the item).
- api.handler: HandlerType for anything holders hand out (inventories, energy...), from the holder itself (HandlerProvider, HandlerMap) or registered providers and fallbacks for blocks, block entities, entities and items. HandlerTypes.CONTAINER also finds vanilla containers (double chests as one). BlockHandlerCache keeps a lookup until the block changes, its block entity goes, or HandlerType.invalidate is called.
- Other mods reach these containers through each loader's own system, following the layout's filters, roles and limits: NeoForge item handler capabilities (blocks, entities and ContainerItem stacks) and Fabric's Transfer API (ItemStorage.SIDED for blocks, ItemStorage.ITEM for ContainerItem stacks).
- api.registry.BlockEntityTypes.create: block entity types from common code.
- Storage menus (api.menu.StorageMenuDefinition): a menu for a block's or an item's inventory, declared once (StorageMenuDefinition.grid(columns, rows) or placed slot by slot), registered with createMenuType and opened with open(player, blockEntity, title) or open(player, hand, title). Slots follow the container's layout and shift-click; the menu closes when the block is removed, the player walks away, or the item leaves its slot (which stays locked meanwhile). sync(attachment) and syncValue(...) send extra values to the screen while it's open, and button(id, action) runs screen buttons on the server. api.client.gui.screens.StorageScreen draws any of these menus with no texture, and can be extended.
⚙️ Refactoring
- Rewrote the v2 event system (the lookup-based skeleton had no events); EventInvokerRegistry was removed.
2001.1.0.0 — Oct 30, 2025
⚙️ Refactoring - Renamed and reorganized several classes. - Updated version formatting from X.X.X to MCVR.X.X.X to clearly distinguish between Minecraft release versions.
1.1.2 — April 11, 2025
- Added new methods to MouseHelper and fixed an issue in RenderUtils
1.1.1 — (Fabric Hotfix) | March 20, 2025
- Correct implementation of Potion Brewing and Potion Brewing Builder extension interfaces
1.1.0 — March 19, 2025
- Revamped the Brewing Recipe API
- Added two versions of Events (second version is still unstable)
- Introduced new abstract classes for widgets
1.0.1 — December 30, 2024
- Changing and Organizing the packages
1.0.0 — September 21, 2024
- Port to 1.21
1.21.1-1 — Unreleased (Minecraft 1.21 - 1.21.1)
Backport of the 26.1.2 release: the same features, on Forge, NeoForge and Fabric.
✨ New Features
- CoolCatLib is split in two mods: CoolCatLib: Core (coolcatcore, package net.ixdarklord.coolcatcore), this one, and CoolCatLib: Canvas (coolcatcanvas), which now holds screen effects, skyboxes, GUI widgets, RenderUtils and Easing. The mod id, package, asset namespace, Fabric entrypoints (coolcatcore:common, ...) and commands (/coolcatcore, /coolcatcore_client) all changed from coolcatlib.
- A cross-loader platform layer, so mods built on CoolCatLib: Core no longer need Architectury API:
- Events (api.event.v2): EventInvoker keeps listeners in common code, ordered by EventPhase, and is found by its listener type (EventInvoker.lookup(ServerTickEvents.End.class)) or its constant (ServerTickEvents.END). EventInvoker.create(Type.class) makes a mod's own event, combining listeners by return type (void, EventResult, EventResultHolder, boolean).
- Built-in events: server lifecycle and ticks, datapack contents sync (ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS: per player on login and after /reload), player join/leave/tick, entity load, block break/place, commands; client ticks, player join/leave, HUD rendering, item tooltips, client commands.
- api.registry: DeferredRegister / RegistryEntry, CreativeTabs, ReloadListeners.
- api.menu.ExtendedMenus: menu types that open with extra data.
- api.network.Network: serverbound/clientbound payloads and sending. Network.canPlayerReceive(player, type) tells whether a player's connection accepts a payload (false for clients without the mod and for GameTest mock players; NeoForge throws when sending to them).
- Record payloads without a StreamCodec: Network.registerServerbound(MyPayload.class, receiver) (or with an explicit Type) derives the codec from the record's components through PayloadCodecs, which knows primitives, strings, common Minecraft types, enums, nested records, arrays, Optional, List, Set, Map, Either and ResourceKey. Other types are added with PayloadCodecs.register / registerFactory; registering a payload with a component type that has no codec throws right away, naming the component.
- api.client.registry: key mappings, menu screens, tooltip components.
- api.platform.Platform: loader, environment, mod checks, folders, the running server, fake players.
- Mod constructors (api.core): ModConstructor (both sides), ClientModConstructor, ServerModConstructor (dedicated server) and DataGenerationConstructor are written once in common code, each with a construct stage and a setup stage (DataGenerationContext.addProvider for data providers).
- Fabric needs no Java entry class: list them under the coolcatcore:common, coolcatcore:client, coolcatcore:server and coolcatcore:datagen entrypoints, plus api.core.fabric.FabricDataGenerationEntrypoint under fabric-datagen.
- NeoForge: extend api.core.neoforge.NeoForgeModEntrypoint in the @Mod class and call common(...), client(() -> ...), server(() -> ...), dataGeneration(...); the mod id comes from the container.
- Forge: the same with api.core.forge.ForgeModEntrypoint, constructed with the @Mod constructor's FMLJavaModLoadingContext.
- EventResult.pass()/interrupt()/allow()/deny(), and EventResultHolder.result()/getValue().
- A config system (api.config):
- Declare configs with Config.builder(modId, scope) (typed values, nested groups, presets) or from an annotated class with ConfigObject.register.
- Scopes: CLIENT, COMMON, SERVER (synced to players) and WORLD (stored per world, seeded from defaultconfigs, synced).
- Types: booleans, ranged numbers (optionally sliders), strings (length/pattern), enums, colors, ids, lists, and any Codec; custom ConfigTypes with their own editors.
- TOML (default) and JSON5 files with generated comments; a config whose format changes converts its old file once (kept as .bak); broken files are backed up; version/migration and aliases handle renamed or moved settings.
- Hot reloading of edited files, change listeners and ConfigEvents: LOADED (first read), RELOADED (hot reload, the reload command or Config.reload()), UNLOADING (a world config before its server's values are dropped), VALUE_CHANGED (each value, with its old and new value), CHANGED (once per batch), SAVED and SYNCED.
- serverOnly() values that never leave the server; operators edit synced configs in-game with permission checks.
- Generated config screen: search, undo/redo, reset, presets, validation, dependencies (enabledWhen), restart notices and list editing. Linked from the Forge and NeoForge mod lists and Mod Menu.
- /coolcatcore config (server) and /coolcatcore_client config (client) commands: list, get, set, reset, reload, preset, open.
- STARTUP configs, read before content is registered (for item properties, which items exist...). Their values stay fixed until a restart; edits are saved for the next start. Joining a server compares them before entering the world: values must match by default (the client is offered to adopt the server's), useServerValue() values are taken from the server while connected, and localOnly() values stay per side.
- Category popups: one category of a config in a small window with Save and Cancel, floating over the current screen or the game, e.g. ConfigScreens.openCategory("mymod", "client/rendering"), ConfigScreens.categoryPopup(parent, config, path), or /coolcatcore_client config open <mod> <category> (with path suggestions). A single setting's path shows just that setting.
- A color picker for color values (a popup with saturation/brightness, hue and alpha, hex input and dye colors), also available as ConfigScreens.colorPicker.
- The main config screen (shown for every mod, even one with a single config): a header with the mod's icon (a "?" when it has none; the list of every mod's configs has its own icon), and each config as a portrait navigation card with its own artwork (faint, brightening on hover; CoolCatLib: Core's per scope, or the mod's own at assets/<modid>/textures/gui/config/cards/<config name>.png), its scope icon and a short label like "Server" (config.<modid>.<name>.label). Cards are centered, grow when hovered, and show a tooltip with the config's scope, contents, file and access. Mod Menu's CoolCatLib: Core button opens CoolCatLib: Core's own settings.
- Page transitions: a config page's panels glide a little way into place (up from below when opened, down from above when going back, a shorter rise when opened from elsewhere) while growing from slightly smaller; the background stays still.
- Config screen effects: animations a theme names by id, drawn behind the panels, over the whole screen, and over each widget (buttons, toggles, sliders, text fields, cards, popup panels). Mods register their own on the client with ConfigEffects.register(id, ConfigEffect) and use them with ConfigTheme.Builder.effects(...), ConfigBuilder.effects(...) for one config, or "effects" in config_theme.json; an unknown id is skipped and an effect that throws is switched off, each logged once. The built-in ConfigTheme.STARFALL, every theme's default, draws soft glows in the accent and small faint stars falling from the top, shifting with the mouse by depth (parallax). CoolCatLib: Core's client config turns effects and the page transitions on or off (Effects > Theme Effects / Page Transitions); both are always off on the Fast graphics preset.
- Redesigned config screens: a top bar (title, scope badges, search), a category sidebar, settings with descriptions and nested sections, and a bottom bar with the unsaved-changes status and actions; toggle switches, sliders, selectors and flat buttons; presets, confirmations and the color picker as popups. Icons are 64x64 textures in assets/coolcatcore/textures/gui/config/icons/ (smoothly filtered), replaceable by resource packs.
- ConfigTheme: each mod's own look, set per mod (ConfigTheme.setForMod) or per config (ConfigBuilder.theme / background): a full ConfigColorScheme (presets DARK, LIGHT, and tinted(accent) for the dark scheme shaded toward the mod's color), a background texture by its path (cover, stretch or tile), the texture's opacity (textureOpacity, letting the panorama or world show through) and the backdrop color's opacity over the background (backgroundOpacity). Players can scale both for every mod in CoolCatLib: Core's client config (Background > Backdrop Opacity / Texture Opacity). By default the screens are see-through to the title panorama or the world. Resource packs can restyle a mod with assets/<modid>/coolcatcore/config_theme.json.
- Popup panel sprites: ConfigTheme.Builder.popupSprite (or popup_sprite in config_theme.json) draws a nine-slice GUI sprite as the panel of popups (category popups, confirmations, the color picker) instead of the flat panel, and ConfigScreens.categoryPopup(parent, config, path, theme) opens a category popup with its own theme, e.g. to match the screen it's opened from.
- The config list shows each mod's icon (a theme can set another); config pages and their cards show an icon of their kind (client, common, server, world, startup).
- Platform.getModName.
- Dark and light mode: a sun/moon switch in every config screen's top bar, remembered in CoolCatLib: Core's own client config (themeMode). Each theme has a light scheme too (ConfigTheme.Builder.lightColors, by default derived from the mod's accent; light_base/light_colors in config_theme.json).
- The main config screen's search bar searches every config it lists (names, keys, comments, group names, values), with results grouped by config; opening a result shows that config filtered to it. A config's own search covers only that config.
- Attachments, containers and handlers for items, blocks and entities:
- api.attachment: typed data any entity (players included), block entity or item stack can carry. Each mod creates its own AttachmentRegistry.create(modId) (and calls register() while it initialises); its values are stored under its own id, in the <modid>:attachments item component and a <modid>:attachments tag in entity and block entity data. Declared once (ATTACHMENTS.builder(name, codec, default)), then used as MADNESS.get(player), set, update, modify, reset, or through AttachmentHolder.of(...).
- Persistent attachments save with their holder; transientBuilder ones never do. copyOnDeath() keeps a player's value through death (always kept through dimension changes and the End exit); keepOnDrop() carries a block entity's value into its dropped item and back when placed.
- sync(SyncPolicy): SELF (the player it belongs to), TRACKING, ALL, or any predicate. Only changed values are sent, at most once per tick; everything when a player starts seeing the holder, receives its chunk, joins, respawns or changes dimension.
- On item stacks, defaults aren't stored, so stacks still stack.
- AttachmentEvents: CHANGING (cancel a change or replace the value), ADDED, CHANGED (in-place changes included), REMOVED, START_TRACKING/STOP_TRACKING (a player starts or stops receiving a holder's data) and RECEIVED (synced values arrived on the client), plus typed per-attachment helpers (onChanged(MADNESS, ...)).
- api.container: ContainerLayout (slot filters, limits, roles STORAGE/INPUT/OUTPUT/INTERNAL, which slots each face reaches) makes SlotContainers, vanilla Containers with insert/extract, listeners and layout-aware menu slots. AttachmentRegistry.container stores one on any entity or block entity (saved and synced with the rest); ItemContainers keeps one in a stack (ContainerItem for items that have one); ItemTransfer moves items between any containers through faces.
- api.block: ExtendedBlockEntity (attachment shortcuts, handlers, serverTick/clientTick with ExtendedBlockEntity.ticker) and ExtendedContainerBlockEntity (an inventory hoppers and comparators use; contents spill or, with keepContentsOnBreak, stay in the item).
- api.handler: HandlerType for anything holders hand out (inventories, energy...), from the holder itself (HandlerProvider, HandlerMap) or registered providers and fallbacks for blocks, block entities, entities and items. HandlerTypes.CONTAINER also finds vanilla containers (double chests as one). BlockHandlerCache keeps a lookup until the block changes, its block entity goes, or HandlerType.invalidate is called.
- Other mods reach these containers through each loader's own system, following the layout's filters, roles and limits: Forge and NeoForge item handler capabilities (blocks, entities and ContainerItem stacks) and Fabric's Transfer API (ItemStorage.SIDED for blocks, ItemStorage.ITEM for ContainerItem stacks).
- api.registry.BlockEntityTypes.create: block entity types from common code.
- Storage menus (api.menu.StorageMenuDefinition): a menu for a block's or an item's inventory, declared once (StorageMenuDefinition.grid(columns, rows) or placed slot by slot), registered with createMenuType and opened with open(player, blockEntity, title) or open(player, hand, title). Slots follow the container's layout and shift-click; the menu closes when the block is removed, the player walks away, or the item leaves its slot (which stays locked meanwhile). sync(attachment) and syncValue(...) send extra values to the screen while it's open, and button(id, action) runs screen buttons on the server. api.client.gui.screens.StorageScreen draws any of these menus with no texture, and can be extended.
⚙️ Refactoring
- Rewrote the v2 event system (the lookup-based skeleton had no events); EventInvokerRegistry was removed.
🔧 Differences from the 26.1.2 release
- Config edit permissions are permission levels (ConfigBuilder.editPermission(int), default 2), as 1.21.1 has no permission sets. The slider doesn't change the cursor shape (1.21.1 has no cursor shapes).
- Signatures use 1.21.1's types where 26.1's don't exist: GuiGraphics instead of GuiGraphicsExtractor (StorageScreen.renderBg, ClientGuiEvents.RenderHud), ClickType in StorageMenu.clicked, List<Component> tooltips in ComponentItem, and CompoundTag saving for attachments.
- ConfigEffect's hooks are renderBackground / renderForeground / renderWidget (26.1.2: extract*), drawing with GuiGraphics. The Fast graphics mode turns effects and transitions off.
- Platform.isForge() and Platform.Loader.FORGE.
2001.1.0.0 — Oct 30, 2025
⚙️ Refactoring - Renamed and reorganized several classes. - Updated version formatting from X.X.X to MCVR.X.X.X to clearly distinguish between Minecraft release versions.
1.1.2 — April 11, 2025
- Added new methods to MouseHelper and fixed an issue in RenderUtils
1.1.1 — (Fabric Hotfix) | March 20, 2025
- Correct implementation of Potion Brewing and Potion Brewing Builder extension interfaces
1.1.0 — March 19, 2025
- Revamped the Brewing Recipe API
- Added two versions of Events (second version is still unstable)
- Introduced new abstract classes for widgets
1.0.1 — December 30, 2024
- Changing and Organizing the packages
1.0.0 — September 21, 2024
- Port to 1.21
1.20.1-1 — Unreleased (Minecraft 1.20.1 backport)
✨ New Features
- CoolCatLib is split in two mods: CoolCatLib: Core (coolcatcore, package net.ixdarklord.coolcatcore), this one, and CoolCatLib: Canvas (coolcatcanvas), which now holds screen effects, skyboxes, GUI widgets, RenderUtils and Easing. The mod id, package, asset namespace, Fabric entrypoints (coolcatcore:common, ...) and commands (/coolcatcore, /coolcatcore_client) all changed from coolcatlib.
- A cross-loader platform layer, so mods built on CoolCatLib: Core no longer need Architectury API:
- Events (api.event.v2): EventInvoker keeps listeners in common code, ordered by EventPhase, and is found by its listener type (EventInvoker.lookup(ServerTickEvents.End.class)) or its constant (ServerTickEvents.END). EventInvoker.create(Type.class) makes a mod's own event, combining listeners by return type (void, EventResult, EventResultHolder, boolean).
- Built-in events: server lifecycle and ticks, datapack contents sync (ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS: per player on login and after /reload), player join/leave/tick, entity load, block break/place, commands; client ticks, player join/leave, HUD rendering, item tooltips, client commands.
- api.registry: DeferredRegister / RegistryEntry, CreativeTabs, ReloadListeners.
- api.menu.ExtendedMenus: menu types that open with extra data.
- api.network.Network: serverbound/clientbound payloads and sending. Network.canPlayerReceive(player, type) tells whether a player's connection accepts a payload (false for clients without the mod and for GameTest mock players).
- Record payloads without a StreamCodec: Network.registerServerbound(MyPayload.class, receiver) (or with an explicit Type) derives the codec from the record's components through PayloadCodecs, which knows primitives, strings, common Minecraft types, enums, nested records, arrays, Optional, List, Set, Map, Either and ResourceKey. Other types are added with PayloadCodecs.register / registerFactory; registering a payload with a component type that has no codec throws right away, naming the component.
- api.client.registry: key mappings, menu screens, tooltip components.
- api.platform.Platform: loader, environment, mod checks, folders, the running server, fake players.
- Mod constructors (api.core): ModConstructor (both sides), ClientModConstructor, ServerModConstructor (dedicated server) and DataGenerationConstructor are written once in common code, each with a construct stage and a setup stage (DataGenerationContext.addProvider for data providers).
- Fabric needs no Java entry class: list them under the coolcatcore:common, coolcatcore:client, coolcatcore:server and coolcatcore:datagen entrypoints, plus api.core.fabric.FabricDataGenerationEntrypoint under fabric-datagen.
- Forge: extend api.core.forge.ForgeModEntrypoint in the @Mod class (its constructor takes the FMLJavaModLoadingContext Forge passes to @Mod constructors) and call common(...), client(() -> ...), server(() -> ...), dataGeneration(...); the mod id comes from the context.
- EventResult.pass()/interrupt()/allow()/deny(), and EventResultHolder.result()/getValue().
- A config system (api.config):
- Declare configs with Config.builder(modId, scope) (typed values, nested groups, presets) or from an annotated class with ConfigObject.register.
- Scopes: CLIENT, COMMON, SERVER (synced to players) and WORLD (stored per world, seeded from defaultconfigs, synced).
- Types: booleans, ranged numbers (optionally sliders), strings (length/pattern), enums, colors, ids, lists, and any Codec; custom ConfigTypes with their own editors.
- TOML (default) and JSON5 files with generated comments; a config whose format changes converts its old file once (kept as .bak); broken files are backed up; version/migration and aliases handle renamed or moved settings.
- Hot reloading of edited files, change listeners and ConfigEvents: LOADED (first read), RELOADED (hot reload, the reload command or Config.reload()), UNLOADING (a world config before its server's values are dropped), VALUE_CHANGED (each value, with its old and new value), CHANGED (once per batch), SAVED and SYNCED.
- serverOnly() values that never leave the server; operators edit synced configs in-game with permission checks.
- Generated config screen: search, undo/redo, reset, presets, validation, dependencies (enabledWhen), restart notices and list editing. Linked from the Forge mod list and Mod Menu.
- /coolcatcore config (server) and /coolcatcore_client config (client) commands: list, get, set, reset, reload, preset, open.
- STARTUP configs, read before content is registered (for item properties, which items exist...). Their values stay fixed until a restart; edits are saved for the next start. Joining a server compares them before entering the world: values must match by default (the client is offered to adopt the server's), useServerValue() values are taken from the server while connected, and localOnly() values stay per side.
- Category popups: one category of a config in a small window with Save and Cancel, floating over the current screen or the game, e.g. ConfigScreens.openCategory("mymod", "client/rendering"), ConfigScreens.categoryPopup(parent, config, path), or /coolcatcore_client config open <mod> <category> (with path suggestions). A single setting's path shows just that setting.
- A color picker for color values (a popup with saturation/brightness, hue and alpha, hex input and dye colors), also available as ConfigScreens.colorPicker.
- The main config screen (shown for every mod, even one with a single config): a header with the mod's icon (a "?" when it has none; the list of every mod's configs has its own icon), and each config as a portrait navigation card with its own artwork (faint, brightening on hover; CoolCatLib: Core's per scope, or the mod's own at assets/<modid>/textures/gui/config/cards/<config name>.png), its scope icon and a short label like "Server" (config.<modid>.<name>.label). Cards are centered, grow when hovered, and show a tooltip with the config's scope, contents, file and access. Mod Menu's CoolCatLib: Core button opens CoolCatLib: Core's own settings.
- Page transitions: a config page's panels glide a little way into place (up from below when opened, down from above when going back, a shorter rise when opened from elsewhere) while growing from slightly smaller; the background stays still.
- Config screen effects: animations a theme names by id, drawn behind the panels, over the whole screen, and over each widget (buttons, toggles, sliders, text fields, cards, popup panels). Mods register their own on the client with ConfigEffects.register(id, ConfigEffect) and use them with ConfigTheme.Builder.effects(...), ConfigBuilder.effects(...) for one config, or "effects" in config_theme.json; an unknown id is skipped and an effect that throws is switched off, each logged once. The built-in ConfigTheme.STARFALL, every theme's default, draws soft glows in the accent and small faint stars falling from the top, shifting with the mouse by depth (parallax). CoolCatLib: Core's client config turns effects and the page transitions on or off (Effects > Theme Effects / Page Transitions); both are always off on the Fast graphics preset.
- Redesigned config screens: a top bar (title, scope badges, search), a category sidebar, settings with descriptions and nested sections, and a bottom bar with the unsaved-changes status and actions; toggle switches, sliders, selectors and flat buttons; presets, confirmations and the color picker as popups. Icons are 64x64 textures in assets/coolcatcore/textures/gui/config/icons/ (smoothly filtered), replaceable by resource packs.
- ConfigTheme: each mod's own look, set per mod (ConfigTheme.setForMod) or per config (ConfigBuilder.theme / background): a full ConfigColorScheme (presets DARK, LIGHT, and tinted(accent) for the dark scheme shaded toward the mod's color), a background texture by its path (cover, stretch or tile), the texture's opacity (textureOpacity, letting the panorama or world show through) and the backdrop color's opacity over the background (backgroundOpacity). Players can scale both for every mod in CoolCatLib: Core's client config (Background > Backdrop Opacity / Texture Opacity). By default the screens are see-through to the title panorama or the world. Resource packs can restyle a mod with assets/<modid>/coolcatcore/config_theme.json.
- Popup panel sprites: ConfigTheme.Builder.popupSprite (or popup_sprite in config_theme.json) draws a nine-slice GUI sprite as the panel of popups (category popups, confirmations, the color picker) instead of the flat panel, and ConfigScreens.categoryPopup(parent, config, path, theme) opens a category popup with its own theme, e.g. to match the screen it's opened from.
- The config list shows each mod's icon (a theme can set another); config pages and their cards show an icon of their kind (client, common, server, world, startup).
- Platform.getModName.
- Dark and light mode: a sun/moon switch in every config screen's top bar, remembered in CoolCatLib: Core's own client config (themeMode). Each theme has a light scheme too (ConfigTheme.Builder.lightColors, by default derived from the mod's accent; light_base/light_colors in config_theme.json).
- The main config screen's search bar searches every config it lists (names, keys, comments, group names, values), with results grouped by config; opening a result shows that config filtered to it. A config's own search covers only that config.
- Attachments, containers and handlers for items, blocks and entities:
- api.attachment: typed data any entity (players included), block entity or item stack can carry. Each mod creates its own AttachmentRegistry.create(modId) (and calls register() while it initialises); its values are stored under its own id, in the <modid>:attachments item component and a <modid>:attachments tag in entity and block entity data. Declared once (ATTACHMENTS.builder(name, codec, default)), then used as MADNESS.get(player), set, update, modify, reset, or through AttachmentHolder.of(...).
- Persistent attachments save with their holder; transientBuilder ones never do. copyOnDeath() keeps a player's value through death (always kept through dimension changes and the End exit); keepOnDrop() carries a block entity's value into its dropped item and back when placed.
- sync(SyncPolicy): SELF (the player it belongs to), TRACKING, ALL, or any predicate. Only changed values are sent, at most once per tick; everything when a player starts seeing the holder, receives its chunk, joins, respawns or changes dimension.
- On item stacks, defaults aren't stored, so stacks still stack.
- AttachmentEvents: CHANGING (cancel a change or replace the value), ADDED, CHANGED (in-place changes included), REMOVED, START_TRACKING/STOP_TRACKING (a player starts or stops receiving a holder's data) and RECEIVED (synced values arrived on the client), plus typed per-attachment helpers (onChanged(MADNESS, ...)).
- api.container: ContainerLayout (slot filters, limits, roles STORAGE/INPUT/OUTPUT/INTERNAL, which slots each face reaches) makes SlotContainers, vanilla Containers with insert/extract, listeners and layout-aware menu slots. AttachmentRegistry.container stores one on any entity or block entity (saved and synced with the rest); ItemContainers keeps one in a stack (ContainerItem for items that have one); ItemTransfer moves items between any containers through faces.
- api.block: ExtendedBlockEntity (attachment shortcuts, handlers, serverTick/clientTick with ExtendedBlockEntity.ticker) and ExtendedContainerBlockEntity (an inventory hoppers and comparators use; contents spill or, with keepContentsOnBreak, stay in the item).
- api.handler: HandlerType for anything holders hand out (inventories, energy...), from the holder itself (HandlerProvider, HandlerMap) or registered providers and fallbacks for blocks, block entities, entities and items. HandlerTypes.CONTAINER also finds vanilla containers (double chests as one). BlockHandlerCache keeps a lookup until the block changes, its block entity goes, or HandlerType.invalidate is called.
- Other mods reach these containers through each loader's own system, following the layout's filters, roles and limits: Forge item handler capabilities (ForgeCapabilities.ITEM_HANDLER on block entities, entities and ContainerItem stacks) and Fabric's Transfer API (ItemStorage.SIDED for blocks).
- api.registry.BlockEntityTypes.create: block entity types from common code.
- Storage menus (api.menu.StorageMenuDefinition): a menu for a block's or an item's inventory, declared once (StorageMenuDefinition.grid(columns, rows) or placed slot by slot), registered with createMenuType and opened with open(player, blockEntity, title) or open(player, hand, title). Slots follow the container's layout and shift-click; the menu closes when the block is removed, the player walks away, or the item leaves its slot (which stays locked meanwhile). sync(attachment) and syncValue(...) send extra values to the screen while it's open, and button(id, action) runs screen buttons on the server. api.client.gui.screens.StorageScreen draws any of these menus with no texture, and can be extended.
⚙️ Refactoring
- Rewrote the v2 event system (the lookup-based skeleton had no events); EventInvokerRegistry was removed.
🔁 Differences from the 26.1.2 version (Minecraft 1.20.1)
- Built for Forge 47 and Fabric (Fabric API 0.92.6) on Java 17, with the same features as CoolCatLib: Core for 26.1.2, except where 1.20.1 has no equivalent:
- Networking: 1.20.1 has no payload types, so Core brings its own api.network.CustomPacketPayload and the api.network.codec package (StreamCodec, ByteBufCodecs, ...; ByteBufCodecs also holds the codecs newer Minecraft keeps on vanilla classes, such as RESOURCE_LOCATION, BLOCK_POS, ITEM_STACK, COMPONENT). On Forge every payload travels on one coolcatcore:network channel; on Fabric each payload type is its own channel.
- There is no configuration phase: configuration payloads (config sync and the STARTUP config check) are sent in the login phase instead.
- api.utils.ARGB: the packed colour helpers newer Minecraft has as net.minecraft.util.ARGB.
- GUI: everything draws with GuiGraphics; methods named extract... on 26.1.2 are render... again (StyledScreen.renderBackground/renderPanels/renderTitle, StyledPopup.renderPopup, FlatButton.renderContents, StorageScreen.renderPanel, ConfigEffect.renderBackground/renderForeground/renderWidget), and input uses 1.20.1's mouseClicked(double, double, int), keyPressed(int, int, int), ... signatures. GUI sprites (config theme popup sprites included) are textures under textures/gui/sprites/, with their stretch, tile or nine-slice scaling read from the .mcmeta; a theme's popupSprite may also be a .png texture path. The menu blur is always on, at the default strength. Config screen effects and page transitions are off on the "Fast" graphics setting (1.20.1's equivalent of the Fast graphics preset).
- Events: ClientGuiEvents HUD listeners take (GuiGraphics, float partialTick); ItemTooltipEvents has no tooltip context.
- Attachments: item stack values live in the stack's NBT ("<modid>:attachments"), not in a data component (AttachmentRegistry.componentType()/bundleComponent() don't exist). keepOnDrop values reach the dropped block item through the loot table: AttachmentRegistry.copyKeptOnDrop() gives the copy_nbt function.
- Containers: SlotContainer.toContents/fromContents use a CompoundTag (a vanilla Items list); ItemContainers keeps contents in BlockEntityTag.Items for block items and Items for other items. Blocks of an ExtendedContainerBlockEntity call ExtendedContainerBlockEntity.onBlockRemoved(state, level, pos, newState) from onRemove so the contents spill, and a keepContentsOnBreak layout needs a copy_nbt of Items into BlockEntityTag.Items in the loot table. There's no Fabric item storage lookup for ContainerItem stacks.
- Config: ConfigBuilder.editPermission(int level) / Config.editPermission() use a permission level (default 2) instead of a Permission.
- ItemDataComponent(ResourceLocation, Codec) and DataComponent are backed by the stack's NBT.
- Brewing: BrewingBuilder takes Potions; RegisterBrewingRecipesEvent.invokeEvent() takes no builder and fires once per game. On Fabric, custom recipes are read through api.brewing.fabric.FabricBrewingRecipes (the PotionBrewingExt/PotionBrewingBuilderExt interfaces don't exist on 1.20.1).
- FabricLanguageWrapper takes a FabricDataOutput.
- Platform.isForge() and Platform.Loader.FORGE instead of isNeoForge()/NEOFORGE.
- Carries the brewing fix of v2001.1.0.1: RegisterBrewingRecipesEvent fires during Forge's common setup.
2001.1.0.1 — Jul 9, 2026
🐛 Bug Fixes & Improvements - Resolved an issue where the RegisterBrewingRecipesEvent was not being triggered correctly.
2001.1.0.0 — Oct 30, 2025
⚙️ Refactoring - Renamed and reorganized several classes. - Updated version formatting from X.X.X to MCVR.X.X.X to clearly distinguish between Minecraft release versions.
✨ New Feature - Added Language Data Generator to support shared environments.
1.0.3 — Feb 19, 2024
Fixed - [CCL-1] [Fabric] Incompatibility with KubeJS
1.0.2 — Dec 27, 2023
Adding - [Fabric] Conditional Recipes - Improving the TomlConfigReader class
1.0.1 — Nov 8, 2023
Adding - Adding Arabic Translation - More methods in ScreenUtils class - Moving and rename some of the packages and classes
1.0.0 — Oct 9, 2023
- Port to 1.20.1
CoolCatLib: Canvas¶
26.1.2-1 — Unreleased (Minecraft 26.1.2)
✨ New Features
- First release: the render and visuals half of what used to be CoolCatLib, split out and built on CoolCatLib: Core. Everything below was moved from CoolCatLib into the net.ixdarklord.coolcatcanvas package and coolcatcanvas namespace.
- Screen effects (api.client.effect): full-screen post-processing shaders whose uniforms can change every frame (vanilla's post chains bake them in at load).
- ScreenEffects.register(id, definition) from a vanilla-format post_effect JSON (vanilla's own included) or a ScreenEffectDefinition built in code; any number stack, ordered by priority, drawn over the world (WORLD) or over everything including the HUD and menus (SCREEN).
- Smooth fades (fade, Easing), timed pulses (enableFor), animated strength, conditions (activeWhen), strength functions of the frame (strength) and per-frame callbacks (onFrame).
- Uniforms by name: set, animated (animateTo) or bound to a function of the frame; autoBlend fades shaders that ignore the effect's strength.
- Shaders get Strength, Time, Age and Seed plus noise and luminance helpers from #moj_import <coolcatcanvas:screen_effect.glsl>; persistent targets allow feedback effects; reloaded with resource packs; a failing effect is logged and skipped.
- No effects of its own: mods bring their own post_effect JSON and shaders, or use vanilla's (minecraft:invert, ...).
- api.effect.ScreenEffectControl drives a player's effects from the server.
- Layers (ScreenEffects.layers()): the draw order of every effect, from priorities until rearranged (move up/down, to a layer, to the top or bottom, reset).
- An effects screen (ScreenEffects.openScreen(), a key unbound by default, and /coolcatcanvas_client effects in development environments only): every selectable effect with a switch, the active ones as drag-and-drop layers grouped by stage with a strength slider each, a live unblurred preview and a Preview mode hiding the panels. Players' choices (on/off, strengths, order) are saved to config/coolcatcanvas-screen-effects.json. Effects have a displayName, description and selectable flag for it.
- Events (ScreenEffectEvents): BEFORE_TOGGLE (cancellable) and TOGGLED with the cause (code, condition, timeout, player, server), STRENGTH_CHANGED, UNIFORM_CHANGED, LAYERS_CHANGED and LOADED.
- Custom skyboxes (api.client.sky): layers drawn inside vanilla's sky pass, around the sun, moon and stars.
- Skyboxes.register(id, definition) from a SkyboxDefinition built in code or assets/<namespace>/skybox/<path>.json; resource packs add skyboxes with no code by listing dimensions (dimensions without a sky, like the Nether, get one while it shows).
- Layer types: cubemap (six faces in a 3x2 image), panorama (equirectangular), sprite (an image placed in the sky, e.g. a planet), gradient, and shader (your own fragment shader, with #moj_import <coolcatcanvas:sky.glsl>); any type can swap in its own fragment shader.
- Per layer: blend mode (alpha, additive, multiply, screen), tint, orientation, rotation over real time, game time, the day or vanilla's sun/moon/star angle, flipbook animation with optional interpolation, day-time fade windows, rain fade, horizon/underwater fog, and 4 shader params.
- Hides vanilla's sky color, sunrise, sun, moon, stars, void, End sky and End flashes, fading them out as the skybox fades in.
- Runtime control: fades, enableFor, conditions (activeWhen), per-frame callbacks, and per layer (Skybox.layer(name)) visibility, animated opacity and tint, and params set, animated or bound to a function of the frame. api.sky.SkyboxControl drives them from the server: enable, disable, toggle, setEnabled, timed pulses and layer changes, for one player or several (to(players), inLevel(level), everyone(server)).
- Cheap: nothing runs while no skybox shows; a visible layer is one draw from a shared static mesh, all layers of a stage share one render pass and one uniform upload.
- api.utils.Easing: easing curves.
- GUI components and widgets (api.client.gui.components: panels, scroll and drag widgets, slide animations, ColorableImageButton), and api.client.utils RenderUtils, NineSliceInfo and ScreenAnchor.
- Animated color gradients (api.utils.ColorGradient): color stops looping around (ColorGradient.of(colors...)) or the full rainbow (RAINBOW, rainbow(saturation, brightness)), scrolling over time (withSpeed) and along the text or outline (withSpread), with each letter colored (perLetter(n)) or the whole text in one cycling color (wholeText(), RAINBOW_WHOLE). Presets: RAINBOW, RAINBOW_WHOLE, PASTEL_RAINBOW, FIRE, OCEAN, AURORA.
- Gradient components: gradient.literal("..."), gradient.apply(component) or a style with gradient.textColor() make a component animate wherever it's drawn (chat, tooltips, item names, signs, widget labels). In JSON text and commands (/tellraw) the color is "coolcatcanvas:rainbow", "coolcatcanvas:rainbow_whole", "coolcatcanvas:rainbow/<speed>/<spread>/<saturation>/<brightness>" or "coolcatcanvas:gradient/<speed>/<spread>/#RRGGBB/#RRGGBB..."; players without Canvas can't read it.
- Gradient and outlined text (api.client.utils.TextEffects): gradient(text, gradient) and rainbow(text) recolor existing text and stay animated when kept; outlined text in a solid color or a gradient.
- Outlines (api.client.utils.Outline): solid or a gradient (Outline.gradient, Outline.rainbow()), with a thickness and padding, drawn around any rectangle; ElementOutlines.set(widget, outline[, when]) attaches one to any widget (vanilla's too), optionally only while a condition holds (hovered, focused...).
1.21.1-1 — Unreleased (Minecraft 1.21 - 1.21.1)
Backport of the 26.1.2 release: the same features, on Forge, NeoForge and Fabric, with the rendering rebuilt on 1.21.1's.
✨ New Features
- First release: the render and visuals half of what used to be CoolCatLib, split out and built on CoolCatLib: Core. Everything below was moved from CoolCatLib into the net.ixdarklord.coolcatcanvas package and coolcatcanvas namespace.
- Screen effects (api.client.effect): full-screen post-processing shaders whose uniforms can change every frame (vanilla's post chains bake them in at load).
- ScreenEffects.register(id, definition) from a vanilla-format post_effect JSON (vanilla's own included) or a ScreenEffectDefinition built in code; any number stack, ordered by priority, drawn over the world (WORLD) or over everything including the HUD and menus (SCREEN).
- Smooth fades (fade, Easing), timed pulses (enableFor), animated strength, conditions (activeWhen), strength functions of the frame (strength) and per-frame callbacks (onFrame).
- Uniforms by name: set, animated (animateTo) or bound to a function of the frame; autoBlend fades shaders that ignore the effect's strength.
- Shaders get Strength, Time, Age and Seed plus noise and luminance helpers from #moj_import <coolcatcanvas:screen_effect.glsl>; persistent targets allow feedback effects; reloaded with resource packs; a failing effect is logged and skipped.
- No effects of its own: mods bring their own post effect JSON and shaders, or use vanilla's (minecraft:invert, ...).
- api.effect.ScreenEffectControl drives a player's effects from the server.
- Layers (ScreenEffects.layers()): the draw order of every effect, from priorities until rearranged (move up/down, to a layer, to the top or bottom, reset).
- An effects screen (ScreenEffects.openScreen(), a key unbound by default, and /coolcatcanvas_client effects in development environments only): every selectable effect with a switch, the active ones as drag-and-drop layers grouped by stage with a strength slider each, a live unblurred preview and a Preview mode hiding the panels. Players' choices (on/off, strengths, order) are saved to config/coolcatcanvas-screen-effects.json. Effects have a displayName, description and selectable flag for it.
- Events (ScreenEffectEvents): BEFORE_TOGGLE (cancellable) and TOGGLED with the cause (code, condition, timeout, player, server), STRENGTH_CHANGED, UNIFORM_CHANGED, LAYERS_CHANGED and LOADED.
- Custom skyboxes (api.client.sky): layers drawn inside vanilla's sky pass, around the sun, moon and stars.
- Skyboxes.register(id, definition) from a SkyboxDefinition built in code or assets/<namespace>/skybox/<path>.json; resource packs add skyboxes with no code by listing dimensions (dimensions without a sky, like the Nether, get one while it shows).
- Layer types: cubemap (six faces in a 3x2 image), panorama (equirectangular), sprite (an image placed in the sky, e.g. a planet), gradient, and shader (your own fragment shader, with #moj_import <coolcatcanvas:sky.glsl>); any type can swap in its own fragment shader.
- Per layer: blend mode (alpha, additive, multiply, screen), tint, orientation, rotation over real time, game time, the day or vanilla's sun/moon/star angle, flipbook animation with optional interpolation, day-time fade windows, rain fade, horizon/underwater fog, and 4 shader params.
- Hides vanilla's sky color, sunrise, sun, moon, stars, void, End sky and End flashes, fading them out as the skybox fades in.
- Runtime control: fades, enableFor, conditions (activeWhen), per-frame callbacks, and per layer (Skybox.layer(name)) visibility, animated opacity and tint, and params set, animated or bound to a function of the frame. api.sky.SkyboxControl drives them from the server: enable, disable, toggle, setEnabled, timed pulses and layer changes, for one player or several (to(players), inLevel(level), everyone(server)).
- Cheap: nothing runs while no skybox shows; a visible layer is one draw from a shared static mesh, all layers of a stage share one render pass and one uniform upload.
- api.utils.Easing: easing curves.
- GUI components and widgets (api.client.gui.components: panels, scroll and drag widgets, slide animations, ColorableImageButton), and api.client.utils RenderUtils, NineSliceInfo and ScreenAnchor.
- Animated color gradients (api.utils.ColorGradient): color stops looping around (ColorGradient.of(colors...)) or the full rainbow (RAINBOW, rainbow(saturation, brightness)), scrolling over time (withSpeed) and along the text or outline (withSpread), with each letter colored (perLetter(n)) or the whole text in one cycling color (wholeText(), RAINBOW_WHOLE). Presets: RAINBOW, RAINBOW_WHOLE, PASTEL_RAINBOW, FIRE, OCEAN, AURORA.
- Gradient components: gradient.literal("..."), gradient.apply(component) or a style with gradient.textColor() make a component animate wherever it's drawn (chat, tooltips, item names, signs, widget labels). In JSON text and commands (/tellraw) the color is "coolcatcanvas:rainbow", "coolcatcanvas:rainbow_whole", "coolcatcanvas:rainbow/<speed>/<spread>/<saturation>/<brightness>" or "coolcatcanvas:gradient/<speed>/<spread>/#RRGGBB/#RRGGBB..."; players without Canvas can't read it.
- Gradient and outlined text (api.client.utils.TextEffects): gradient(text, gradient) and rainbow(text) recolor existing text and stay animated when kept; outlined text in a solid color or a gradient.
- Outlines (api.client.utils.Outline): solid or a gradient (Outline.gradient, Outline.rainbow()), with a thickness and padding, drawn around any rectangle; ElementOutlines.set(widget, outline[, when]) attaches one to any widget (vanilla's too), optionally only while a condition holds (hovered, focused...).
🔧 Differences from the 26.1.2 release
- Screen effect and sky shaders are GLSL 150 with plain uniforms instead of uniform blocks; post_effect definitions and their JSON stay the same, and a vanilla shaders/post chain (e.g. minecraft:creeper) can be registered as an effect too.
- End flashes don't exist on 1.21.1, so VanillaSky.END_FLASH does nothing.
- GUI panel input methods take 1.21.1's (mouse x, y, button...) parameters, and their extract* hooks are render*.
1.20.1-1 — Unreleased (Minecraft 1.20.1)
✨ New Features
- First release: the render and visuals half of what used to be CoolCatLib, split out and built on CoolCatLib: Core. Everything below was moved from CoolCatLib into the net.ixdarklord.coolcatcanvas package and coolcatcanvas namespace.
- Screen effects (api.client.effect): full-screen post-processing shaders whose uniforms can change every frame (vanilla's post chains bake them in at load).
- ScreenEffects.register(id, definition) from a vanilla-format post_effect JSON (vanilla's own included) or a ScreenEffectDefinition built in code; any number stack, ordered by priority, drawn over the world (WORLD) or over everything including the HUD and menus (SCREEN).
- Smooth fades (fade, Easing), timed pulses (enableFor), animated strength, conditions (activeWhen), strength functions of the frame (strength) and per-frame callbacks (onFrame).
- Uniforms by name: set, animated (animateTo) or bound to a function of the frame; autoBlend fades shaders that ignore the effect's strength.
- Shaders get Strength, Time, Age and Seed plus noise and luminance helpers from #moj_import <coolcatcanvas:screen_effect.glsl>; persistent targets allow feedback effects; reloaded with resource packs; a failing effect is logged and skipped.
- No effects of its own: mods bring their own post effect JSON and shaders, or use vanilla's (minecraft:invert, ...).
- api.effect.ScreenEffectControl drives a player's effects from the server.
- Layers (ScreenEffects.layers()): the draw order of every effect, from priorities until rearranged (move up/down, to a layer, to the top or bottom, reset).
- An effects screen (ScreenEffects.openScreen(), a key unbound by default, /coolcatcanvas_client effects): every selectable effect with a switch, the active ones as drag-and-drop layers grouped by stage with a strength slider each, a live unblurred preview and a Preview mode hiding the panels. Players' choices (on/off, strengths, order) are saved to config/coolcatcanvas-screen-effects.json. Effects have a displayName, description and selectable flag for it.
- Events (ScreenEffectEvents): BEFORE_TOGGLE (cancellable) and TOGGLED with the cause (code, condition, timeout, player, server), STRENGTH_CHANGED, UNIFORM_CHANGED, LAYERS_CHANGED and LOADED.
- Custom skyboxes (api.client.sky): layers drawn inside vanilla's sky pass, around the sun, moon and stars.
- Skyboxes.register(id, definition) from a SkyboxDefinition built in code or assets/<namespace>/skybox/<path>.json; resource packs add skyboxes with no code by listing dimensions (dimensions without a sky, like the Nether, get one while it shows).
- Layer types: cubemap (six faces in a 3x2 image), panorama (equirectangular), sprite (an image placed in the sky, e.g. a planet), gradient, and shader (your own fragment shader, with #moj_import <coolcatcanvas:sky.glsl>); any type can swap in its own fragment shader.
- Per layer: blend mode (alpha, additive, multiply, screen), tint, orientation, rotation over real time, game time, the day or vanilla's sun/moon/star angle, flipbook animation with optional interpolation, day-time fade windows, rain fade, horizon/underwater fog, and 4 shader params.
- Hides vanilla's sky color, sunrise, sun, moon, stars, void, End sky and End flashes, fading them out as the skybox fades in.
- Runtime control: fades, enableFor, conditions (activeWhen), per-frame callbacks, and per layer (Skybox.layer(name)) visibility, animated opacity and tint, and params set, animated or bound to a function of the frame. api.sky.SkyboxControl drives them from the server: enable, disable, toggle, setEnabled, timed pulses and layer changes, for one player or several (to(players), inLevel(level), everyone(server)).
- Cheap: nothing runs while no skybox shows; a visible layer is one draw from a shared static mesh, all layers of a stage share one render pass and one uniform upload.
- api.utils.Easing: easing curves.
- GUI components and widgets (api.client.gui.components: panels, scroll and drag widgets, slide animations, ColorableImageButton), and api.client.utils RenderUtils, NineSliceInfo and ScreenAnchor.
- Animated color gradients (api.utils.ColorGradient): color stops looping around (ColorGradient.of(colors...)) or the full rainbow (RAINBOW, rainbow(saturation, brightness)), scrolling over time (withSpeed) and along the text or outline (withSpread), with each letter colored (perLetter(n)) or the whole text in one cycling color (wholeText(), RAINBOW_WHOLE). Presets: RAINBOW, RAINBOW_WHOLE, PASTEL_RAINBOW, FIRE, OCEAN, AURORA.
- Gradient components: gradient.literal("..."), gradient.apply(component) or a style with gradient.textColor() make a component animate wherever it's drawn (chat, tooltips, item names, signs, widget labels). In JSON text and commands (/tellraw) the color is "coolcatcanvas:rainbow", "coolcatcanvas:rainbow_whole", "coolcatcanvas:rainbow/<speed>/<spread>/<saturation>/<brightness>" or "coolcatcanvas:gradient/<speed>/<spread>/#RRGGBB/#RRGGBB..."; players without Canvas can't read it.
- Gradient and outlined text (api.client.utils.TextEffects): gradient(text, gradient) and rainbow(text) recolor existing text and stay animated when kept; outlined text in a solid color or a gradient.
- Outlines (api.client.utils.Outline): solid or a gradient (Outline.gradient, Outline.rainbow()), with a thickness and padding, drawn around any rectangle; ElementOutlines.set(widget, outline[, when]) attaches one to any widget (vanilla's too), optionally only while a condition holds (hovered, focused...).
🔁 Differences from the 26.1.2 version (Minecraft 1.20.1)
- Built for Forge 47 and Fabric on Java 17. Screen effects and skyboxes run on 1.20.1's OpenGL rendering with Canvas's own shader programs (GLSL 150, no uniform blocks, #moj_import supported), hooked into GameRenderer.render and LevelRenderer.renderSky on both loaders.
- Screen effects use 1.20.1's post chain format: definitions are assets/<ns>/shaders/post/<path>.json (vanilla's own included, e.g. minecraft:invert) with programs in shaders/program/. ScreenEffectDefinition is (targets, passes); a Pass has program, input, output, auxTargets, uniforms and bilinear (JSON name, intarget, outtarget, auxtargets, uniforms, bilinear); uniform types come from the program JSON (UniformSpec(name, values)); the main input sampler is DiffuseSampler. simple(program, uniforms...), PassBuilder.input(sampler, target) takes the full sampler name, and PassBuilder.bilinear/uniform are new; every target persists between frames. BLIT_PROGRAM and BUILTIN_UNIFORMS replace the 26.1.2 shader-stage constants.
- Skyboxes: SkyBlend exposes sourceColor()/destColor()/sourceAlpha()/destAlpha()/apply(). 1.20.1 has no End flashes (VanillaSky.END_FLASH does nothing) and its moon and stars follow the sun, so the moon and star clocks do too. In dimensions with a sky renderer of their own (Forge DimensionSpecialEffects.renderSky, Fabric API DimensionRenderingRegistry), the layers are drawn over that sky, in the sky's fog; what a skybox hides only applies to vanilla's sky, so nothing of that sky is hidden. With an Iris/Oculus shader pack active, skyboxes step aside.
- GUI widgets: render methods named extract... on 26.1.2 are render... (Panel.renderContents, ScrollPanel.renderScrolled/renderFrame, ViewportPanel.renderWorld/renderViewBackground/renderViewForeground); input uses 1.20.1's signatures (ViewportPanel.worldClicked(x, y, int button)); widgets take Canvas's own WidgetSprites (texture paths, stretched or nine-sliced); AbstractScrollableWidget scrolls sideways with Shift + wheel. RenderUtils adds containsPoint, nextStratum, withTint and blitSprite.