Apoli (1.22.0)
Curse Maven Snippet
What's new
[1.22.0] — 2026-08-04
Added
apoli:custom_model_rendergeometry mode honoursshow_first_person. The field existed but only ever did anything in texture mode, so a Blockbench model bound to the arms was invisible on your own hands. It now draws the model'sright_arm/left_armbones — and everything nested under them — onto the vanilla first-person arm, posed from the same bones the third-person model uses.body_partsstill applies, so a power that only shows aheadbone draws nothing in first person, and the vanilla arm is still underneath: hide it withapoli:modify_model_partsif the model is meant to replace it.apoli:show_both_armsgains ghost arms —ghost_arms(0–16),ghost_spacingandghost_alpha. Each ghost is a translucent copy of the same arm frozen at an earlier point of the swing, so one punch trails a fan behind it and a fast stream of swings reads as a flurry. They are drawn only while an arm is swinging, and only on arms that are drawn at all. They go through the samerenderPlayerArmpath as the real arm, socustom_model_render,model_color,modify_player_model,modify_model_partsand disguise skins all apply to them for free.apoli:attach_ropegainsstart_length— the length the rope is created at, clamped tomin_length–max_length.
Fixed
apoli:creative_flightignored itscondition. The power granted flight on add and then re-granted it every tick without ever testing the condition, so a conditional flight power was permanent flight. It now re-evaluates every tick: while the condition fails (or the power is suppressed) flight is taken away and the holder drops, and it comes back when the condition passes. Creative and spectator mode are never touched.apoli:custom_model_render— a rig's second layer detached from its limb. Only the first bone naming a body part bound to it, so a model with bothright_armandright_sleeve(orheadandhat_layer, orbodyandjacket) animated one and froze the other at its rest pose. Standing still it looked right; sneaking, blocking with a shield or winding up a trident moved the bound bone and left the other behind, which read as the model coming apart. Every bone that names a body part now binds to it.apoli:custom_model_render— a body-part bone under a rotated group animated twice. Body-part bones are posed in the player's frame, so they are now always lifted out of their parent group, not just when no ancestor carried a rotation. A bone that loses a parent rotation this way is named in the load log.apoli:custom_model_render— slim skins were half a pixel out. The rest pose the animation is measured against was baked from the slim player layer, whose arms sit aty = 2.5; vanilla normalises them to the widey = 2.0every frame, so every arm-bound bone on a slim player was offset by 0.5. The rest pose is now always the wide bake, which is the basis vanilla animates from for both models.apoli:attach_rope—max_lengthdid nothing on a rope that can't be reeled. Every rope was created at whatever distance its two ends happened to be apart, and only the reel keys could change that. Acontrollablegrapple wants to start taut, so that is still its default — but a tether is not controllable and has no way to pay itself out, so"max_length": 20on one meant "stuck at however far apart you were", not "may roam 20 blocks". Ropes that are notcontrollablenow start atmax_length, andstart_lengthoverrides either default.
[1.21.2] — 2026-08-03
Fixed
apoli:custom_model_renderis drawn in the inventory preview while the camera is in first person. Both modes suppressed themselves whenever the holder was the local player and the camera was first person. That guard was aimed at the first-person hand view, but the hand is rendered byPlayerRenderer.renderHand, which draws the arm parts directly and never runs render layers — so it never had anything to suppress there. What it did suppress was every other whole-body render of the local player, all of which happen with the camera still in first person: the inventory preview and any screen using it, and your own body while sleeping. The model showed in third person and vanished in first person for the same screen. The guard is gone; vanilla already declines to render the camera entity's body during the first-person world pass, so there is nothing left to guard against.apoli:disguise_ashas the same fix. The disguise renderer hooksEntityRenderDispatcher.render, which is exactly what the inventory preview calls, and carried the same first-person guard — so a disguised player saw their own undisguised body in the preview while everyone else saw the disguise. The preview now shows the disguise.
[1.21.1] — 2026-08-03
Follow-up to 1.21.0. Bedrock models now match Blockbench's preview exactly — verified per cube corner and per UV rect against Blockbench's own import and export code, not by eye.
Fixed
apoli:custom_model_render— box UV is laid out on floored cube sizes. Blockbench rounds each cube dimension down before packing the six box-UV faces; only its Java-entity format keeps the fractional size. Apoli was using the raw float size, so every cube with a fractional dimension sampled the wrong part of the texture — up to 2.65 UV pixels out on a 32×32 sheet. Faces that overran their island's edge into empty texture also read as gaps between cubes, so this fixes two separate-looking symptoms. Cubes with whole-number sizes are unaffected. The cube's geometry still uses the exact fractional size.apoli:custom_model_render— every bone is bindable, not just root bones. A rig built inside a Blockbench wrapper group (the normal case) never picked up the player's animation, because only top-level bones were indexed by name.apoli:custom_model_render— a body-part bone nested under another body-part bone no longer animates twice. Java's player parts are siblings in root space —bodynever carriesright_arm's swing — so aheadbone parented to abodybone was picking up the body's animation and its own. Such bones are now re-parented to the model root with a root-relative bind offset, which is exactly bind-pose-preserving. Skipped when an ancestor carries its own rotation, where nesting is what the author meant.
Added
apoli:custom_model_render— body-part names are matched loosely. Case, spaces,_and-are ignored, and alias spellings bind to the seven vanilla parts:headwear/hat_layer/head_layer→hat;torso/waist/jacket/body_layer→body;arm_right/right_sleeve/right_arm_layer→right_arm, and the left and leg equivalents includingright_pants/left_pants.
Changed
body_partsin geometry mode now names bones in your own model, not just the seven vanilla parts. Behaviour change: a non-emptybody_partsnow hides every bone it does not name (hiding a bone hides everything nested under it). Leavebody_partsout to draw the whole model, as before.
[1.21.0] — 2026-08-03
apoli:custom_model_render geometry mode was correct in Blockbench and "exploded" in game. Two independent causes, both fixed.
Fixed
- Per-cube
rotationandpivotare now applied. Bedrock rotates individual cubes; Java'sModelPart.Cubecannot. Each rotated cube now becomes a synthetic child bone<bone>_r<n>carrying that cube's pivot and rotation — the same transformation Blockbench's own Java exporter performs. Previously every rotated cube was drawn unrotated, which flattened angled parts and pulled the model apart at the joints. - Body-part binding no longer teleports bones. Binding copied the vanilla
part's position along with its rotation, so a bone named
headsnapped to the vanilla head pivot,bodyto the model origin, and the arms to±5. Binding is now the vanilla part's delta from its rest pose, applied on top of the pose you authored — a bone rotates about its own pivot and stays where Blockbench put it. Models built on the vanilla skeleton behave exactly as before.
Added
- Per-face UV.
"uv": { "north": { "uv": […], "uv_size": […] }, … }is now read per face, including cubes that mix per-face and box UV within one model. Previously the north face's UV was applied to all six sides. Bedrock face names map onto Java's aseast↔west,up↔down,north/southunchanged.
Known limitations
uv_rotation(Bedrock format 1.21.0+) is not supported; a model using it logs a warning and draws that face unrotated.- Only
minecraft:geometry[0]is read from a.geo.json. - A cube with a zero-size axis is a flat plane, and both of its faces land on
the same plane — the game z-fights it, as Blockbench does. Give the cube a
small
inflateor a non-zero thickness. - Geometry mode renders in third person only.

