Allows you to create custom portals, designed for packdev
Add custom portal blocks to your pack: each block teleports to a dimension you choose (e.g. custom dimensions, Nether, End) at the same x, y, z.
For pack creators: define portals in JSON (id, destination, optional base/capsule blocks, sound, usable dimensions, default return). Files go in a configurable directory — default: kubejs/external_scripts/simp_cm_portal_portals/ under the game directory. The path can be changed in the mod config. When the game loads, the mod also writes a PORTALS.md in that folder with the same documentation below. No KubeJS required; the path name is just the default.
Features: optional safe-zone building at destination, one-way portals via usableIn, /simp_cm_portal_reload for live reload without restart.
The rest of this page is the full documentation (same as the auto-generated PORTALS.md, which is created in the same folder where you put the portal JSON scripts).
Portal definitions are loaded from JSON files in: <game dir>/<externalScriptsPath>/simp_cm_portal_portals/.
externalScriptsPath is set in mod config (default: kubejs/external_scripts). Only .json files are read.
Each JSON file can contain one or more portal definitions. Root structure:
"simp_cm_portal:portals" or "iska_utils:portals"."custom_dimensions-portal_void"). Used for the block registry; only portals loaded at game startup get a block. After a reload, only the logic of existing ids is updated."minecraft:overworld", "custom_dimensions:void")."minecraft:stone"). If empty, floor is not replaced."minecraft:glass"). If empty, walls/ceiling are not built."width height depth" as fractions from 0 to 1, space or comma separated. Example: "1 1 1" or omit = full block; "0.5 1 0.5" = half width and depth, full height; "0.5" = cube 0.5×0.5×0.5. Invalid or empty = full block.["minecraft:overworld"] so the return portal in the destination does not work).glass. See "Supported sounds" below. Example: "rock".Valid values for sound (default if omitted or unknown: glass). Examples: rock, glass, wood — full list in the PORTALS.md generated in the same folder as the scripts.
JSON can contain // and /* */ comments; they are stripped before parsing.
Minimal (two-way, no safe-zone styling):
{
"type": "simp_cm_portal:portals",
"portals": [
{
"id": "my_portal_void",
"destination": "custom_dimensions:void"
}
]
}
Two-way with safe-zone, default return and custom sound (e.g. overworld ↔ void):
{
"type": "simp_cm_portal:portals",
"portals": [
{
"id": "portal_void",
"destination": "custom_dimensions:void",
"baseBlock": "minecraft:stone",
"capsuleBlock": "minecraft:glass",
"sound": "rock",
"usableIn": [],
"defaultReturn": "minecraft:overworld"
}
]
}
One-way (only from overworld to void; return portal does not work):
{
"type": "simp_cm_portal:portals",
"portals": [
{
"id": "one_way_void",
"destination": "custom_dimensions:void",
"baseBlock": "minecraft:stone",
"capsuleBlock": "minecraft:glass",
"usableIn": ["minecraft:overworld"],
"defaultReturn": ""
}
]
}
Custom hitbox (thin pillar, half width/depth, full height):
{
"type": "simp_cm_portal:portals",
"portals": [
{
"id": "slim_portal",
"destination": "minecraft:the_nether",
"box": "0.5 1 0.5"
}
]
}
Other box examples: "1 1 1" full block; "0.5" small centered cube.
Multiple portals in one file:
{
"type": "simp_cm_portal:portals",
"portals": [
{
"id": "portal_overworld",
"destination": "minecraft:overworld",
"baseBlock": "minecraft:grass_block",
"capsuleBlock": "minecraft:oak_planks",
"defaultReturn": "custom_dimensions:void"
},
{
"id": "portal_void",
"destination": "custom_dimensions:void",
"baseBlock": "minecraft:stone",
"capsuleBlock": "minecraft:glass",
"usableIn": ["minecraft:overworld"],
"defaultReturn": "minecraft:overworld"
}
]
}
Before building the capsule, the mod checks that no block in the zone has:
minecraft:features_cannot_replaceIf any of these fail, the player gets an action-bar message (e.g. "Invalid position for portal") and no build/teleport happens.
If a portal block still exists in the world but its id was removed from every JSON (e.g. after a reload), the block does nothing and does not crash: click returns PASS. After a game restart, that block type may no longer exist depending on registration.