 
A guidebook mod for Minecraft NeoForge, designed to provide in-game guides for other mods. Ageratum offers rich Markdown rendering, i18n localization, and an extensible custom syntax/component system.
✅ Block Elements
# ~ ######) and Setext headings (underline style)✅ Inline Elements
<hover> and <click> tags)✅ Advanced Features
ageratum/<language_code>/ (e.g., en_us, zh_cn)en_us if localized version missingTwo block-level extension syntaxes for custom components:
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a danger warning.
:::
<namespace:component key="value" param=123>
Block content supports Markdown syntax.
</namespace:component>
<namespace:component/>
Self-closing form without content.
Namespace can be omitted (defaults to ageratum:).
ageratum:info - Blue info boxageratum:tip - Green tip boxageratum:warning - Orange warning boxageratum:danger - Red danger boxSupport interactive text that allows players to hover for tooltips or click to perform actions.
<hover>)Display tooltip text when hovering over text:
<hover type="SHOW_TEXT" data="This is the tooltip">Hover over me</hover>
Supported Types:
SHOW_TEXT - Display plain text tooltip (data is the tooltip content)<click>)Execute an action when clicking on text:
<click type="OPEN_URL" data="https://example.com">Click to open link</click>
<click type="COPY_TO_CLIPBOARD" data="Text to copy">Click to copy</click>
<click type="SUGGEST_COMMAND" data="/say hello">Click to suggest command</click>
Supported Types:
OPEN_URL - Open a URL (data is the complete URL)COPY_TO_CLIPBOARD - Copy text to clipboard (data is the text to copy)SUGGEST_COMMAND - Suggest a command in chat (data is the command text)You can combine multiple styles in the same text:
<hover type="SHOW_TEXT" data="This is a tooltip"><click type="OPEN_URL" data="https://example.com">Click and hover on me!</click></hover>
<recipe/>)Use the recipe extension to render recipes directly inside Markdown documents:
<recipe id="minecraft:acacia_boat"/>
id: required, target recipe ResourceLocationRecipeType.CRAFTING (crafting table recipes)IngredientYou can register additional recipe component factories through AgeratumRegistries.RECIPE_COMPONENT_FACTORIES:
public static final DeferredHolder<MDRecipeComponent.RecipeComponentFactory<?>, MDRecipeComponent.RecipeComponentFactory<?>> SMELTING =
AgeratumRegistries.RECIPE_COMPONENT_FACTORIES.register(
"smelting",
() -> MDRecipeComponent.RecipeComponentFactory.create(RecipeType.SMELTING, MDSmeltingRecipeComponent::new)
);
<structure/>)Use the structure extension to render a summary, top-down block preview, and bounded NBT tree for .nbt structure files directly inside documents:
<structure id="minecraft:village/plains/houses/plains_small_house_1"/>
<structure id="./test.nbt"/>
id / path: required, target structure file ResourceLocationmaxDepth: optional, maximum expansion depth, default 2maxEntries: optional, maximum number of keys/list entries shown per level, default 12.nbt files placed next to the Markdown document inside the resource pack; in preview mode the matching file is loaded from run/ageratum_review/MDComponent lists on resource load// Client: open directly
Ageratum.openGuide(ResourceLocation location);
// Server: notify client via network packet
Ageratum.
openGuide(ResourceLocation location);
src/main/java/dev/anvilcraft/resource/ageratum/
├── Ageratum.java // Main mod class + command registration
├── GuideDocumentLoader.java // Document loading utils
├── GuideDocumentCache.java // Preload cache & reload listener
│
├── client/
│ ├── AgeratumClient.java // Client hooks (reserved)
│ ├── gui/
│ │ └── GuideScreen.java // Guide reading GUI
│ └── feat/markdown/
│ ├── MarkdownParser.java // Markdown block-level parser
│ ├── BuiltinExtensionComponents.java // Built-in extension registration
│ ├── BlockExtensionState.java // Block extension state machine
│ ├── SelfClosingBlockExtensionState.java
│ ├── ExtensionParamParser.java // Parameter parsing utility
│ ├── MDExtensionContext.java // Extension execution context
│ ├── MDExtensionComponentFactory.java // Extension factory interface
│ └── component/
│ ├── MDComponent.java // Base class + inline parsing
│ ├── MDTextComponent.java // Plain text paragraphs
│ ├── MDHeaderComponent.java // Headings
│ ├── MDCodeBlockComponent.java // Code blocks
│ ├── MDListComponent.java // Lists (inc. task lists)
│ ├── MDQuoteComponent.java // Blockquotes
│ ├── MDTableComponent.java // Tables
│ ├── MDImageComponent.java // Images
│ ├── MDHorizontalRuleComponent.java
│ └── MDNoticeBoxComponent.java // Notice box container
│
└── network/
├── AgeratumNetwork.java // Network registration & dispatch
└── OpenGuidePayload.java // Guide open network packet
registerExtensionComponent()Open guides with client command:
/ageratum <namespace> [file]
Examples:
/ageratum ageratum # Opens ageratum:en_us/index.md
/ageratum mymod guide # Opens mymod:en_us/guide.md
/ageratum mymod zh_cn/tutorial # Opens mymod:zh_cn/tutorial.md
Tab completion supported for namespaces and file names.
Use registration methods described in NeoForge docs:
DeferredRegister (recommended)RegisterEvent (advanced usage)public static final DeferredRegister<MDExtensionComponentFactory> EXT_COMPONENT_FACTORIES =
AgeratumRegistries.createExtensionComponentFactoryRegister("your_modid");
public static final DeferredHolder<MDExtensionComponentFactory, MDExtensionComponentFactory> CUSTOM =
EXT_COMPONENT_FACTORIES.register(
"custom", () ->
context -> new MyComponent(context.renderedContent(), context.params())
);
// In your mod constructor
EXT_COMPONENT_FACTORIES.
register(modEventBus);
Inline style parsers are registered through INLINE_STYLE_PARSER_REGISTRY_KEY. MDComponent queries this registry and resolves matches by position + parser priority.
package com.example.mymod.client.markdown;
import dev.anvilcraft.resource.ageratum.client.feat.markdown.component.MDInlineStyleParser;
import dev.anvilcraft.resource.ageratum.client.registries.AgeratumRegistries;
import net.minecraft.network.chat.Style;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import java.util.regex.Pattern;
public final class MyInlineStyleParsers {
// Use your own modid here, not ageratum
public static final DeferredRegister<MDInlineStyleParser> INLINE_STYLE_PARSERS = DeferredRegister.create(
AgeratumRegistries.INLINE_STYLE_PARSER_REGISTRY_KEY,
"mymod"
);
// Example tag: <rainbow>text</rainbow>
public static final DeferredHolder<MDInlineStyleParser, MDInlineStyleParser> RAINBOW =
INLINE_STYLE_PARSERS.register(
"rainbow",
() -> MDInlineStyleParser.create(
100, // smaller value = higher precedence at same position
Pattern.compile("<rainbow>"),
"</rainbow>",
(Style parentStyle, java.util.regex.Matcher matcher) -> parentStyle.withColor(0xFF55FF)
)
);
private MyInlineStyleParsers() {
}
}
Register it in your client init:
public class MyModClient {
public MyModClient(IEventBus modEventBus) {
MyInlineStyleParsers.INLINE_STYLE_PARSERS.register(modEventBus);
}
}
Markdown usage:
normal text <rainbow>colored text</rainbow> normal text
See full guide: docs/inline-style-parser-example.en.md.
Create in resource pack:
assets/<namespace>/ageratum/<language>/index.md
assets/<namespace>/ageratum/en_us/index.md
assets/<namespace>/ageratum/zh_cn/index.md