NeoOrigins: Resource Bar Art Spec
Spec for artists producing fills for NeoOrigins resource bars (mana, stamina, rage and custom origin resources). A bar style is a preset JSON plus its textures; the preset format and every field are in Resources, toggles & state → resource. This page covers the art.
1. Where it renders
The shipped styles (neoorigins:fire, water, wind, earth, soul, void, sculk and tinted) use the framed layout, drawn at 1 texel = 1 GUI pixel (the game then scales the whole HUD by the player’s GUI scale, nearest-neighbor):
| Piece | Size (GUI px) | Notes |
|---|---|---|
| Frame | 71 × 8 | neoorigins:textures/gui/bar_fx/empty_bar.png, shared by every shipped style. Set by the preset’s frame, frame_width and frame_height. |
| Fill | 69 × 6 | This is what you are drawing. It sits inside the frame, one pixel in from each edge. |
| Value ticks | 1 px wide | Drawn by the game over the top of the fill: a faint 1 px tick every 5 points and a brighter 2 px tick every 25. |
The fill is drawn over the frame and cut off at the current level: only the leftmost round(69 × fraction) pixels show. So the left edge is the empty end, and the cut edge must read well at any width.
A bar hides when full once it has been spent, so the fill is mostly seen partly drawn. Bars sit over arbitrary world backdrops, but inside the frame the fill covers its own area, so the frame and fill decide how the bar reads.
2. Format rules
- PNG, RGBA, sRGB. No GIF, APNG or WebP: Minecraft cannot load them.
- Draw the fill at its in-game height. A framed fill is drawn
frame_height − 2pixels tall (6 for the shipped frame). Settile_heightto the texture’s real height; a texture of another height is stretched to fit, which breaks the pixel grid. - Make the fill opaque. All the shipped fills are fully opaque. Blending is ordinary alpha blending, not additive: a transparent pixel shows the frame’s dark interior behind it, not a glow.
- There is no frame-by-frame animation. A fill either scrolls sideways or stands still (section 3).
3. Two kinds of fill
Scrolling strip ("mode": "scroll", the default)
A horizontal strip that drifts left at the preset’s scroll_speed, in GUI pixels per second (negative drifts right). The scroll follows game time, so it stops while the game is paused, and it steps one screen pixel at a time.
- Shipped size:
126 × 6. Width is free; the strip repeats everyloop_widthtexels. - Pick one seam convention and set
loop_widthto match:- The last column repeats the first: set
loop_widthtotile_width − 1, so that column is not shown twice. Six shipped strips do this (126 wide,loop_width125). - The strip wraps cleanly across its full width: set
loop_widthtotile_width.sculkdoes this (126 wide,loop_width126).
- The last column repeats the first: set
- Bake any motion you want beyond the sideways drift (rising flame, flowing water) into the strip itself. The game adds only the scroll.
Static fill ("mode": "static")
Drawn in place, with no scroll, and cut off at the current level. Pixel column c of the texture lands on column c of the fill, so make it as wide as the fill (69 for the shipped frame).
neoorigins:tinted is the shipped example: grayscale.png, 69 × 6.
4. Tintable art
A power can set tint in hud_render, and the game multiplies the fill by it, channel by channel. A preset with "tint_from_color": true also uses the bar’s color when no tint is given.
To make a fill that takes any color, draw it in greys: white comes out as the tint itself, and darker greys as deeper shades of it, so the shading survives. The tinted fill is mostly mid-grey, with white and darker greys for its shading.
A static fill can also shade across the bar with tint_end: column by column, from the tint at the left end to tint_end at the right. This applies only to a framed fill that does not scroll.
5. Shipped textures
All under assets/neoorigins/textures/gui/bar_fx/:
| Style | File | Size | loop_width | scroll_speed | Look |
|---|---|---|---|---|---|
fire | fire.png | 126 × 6 | 125 | 16 | Red and orange flames |
water | water.png | 126 × 6 | 125 | 10 | Deep blue water with bubbles |
wind | wind.png | 126 × 6 | 125 | 24 | White cloud wisps over grey |
earth | earth.png | 126 × 6 | 125 | 6 | Brown earth |
soul | soul.png | 126 × 6 | 125 | 8 | Cyan soul flames |
void | void.png | 126 × 6 | 125 | 10 | Purple veins |
sculk | sculk.png | 126 × 6 | 126 | 12 | Dark teal sculk with cyan sparks |
tinted | grayscale.png | 69 × 6 | static | static | Grey, colored by tint or color |
6. Style
Pixel art, authored at native resolution. The PNG ships 1:1 with no downsampling, so place pixels deliberately: what you draw is exactly what shows in game, apart from integer GUI-scale upscaling. Bias brightness a little hot, since the bar reads tiny on the HUD.
7. Deliverables checklist
- Layered source (PSD, Procreate or Krita) per fill.
- Final PNG per fill, RGBA, sRGB, opaque, at the in-game height (section 2).
- For a scrolling strip: which seam convention it uses, so
loop_widthcan be set. - File names: the lowercase style id (
fire.png,water.png, …). - QA: preview each fill inside the frame at several fill levels, and check the cut edge and the scroll seam.
8. Quick reference
Frame: 71 × 8 (empty_bar.png)
Fill: 69 × 6, one pixel in from each frame edge
Visible width: leftmost round(69 × fill%) pixels
Scroll strip: 126 × 6 shipped; loops every loop_width texels
Static fill: 69 × 6; column c of the texture = column c of the fill
Speed: scroll_speed GUI px/s, follows game time
Blend: normal alpha; ship opaque fills
Tint: multiply; author tintable fills in greys
Style: pixel art, native res, ships 1:1
The unframed box
A preset with no frame draws the layout from before 2.2.30: a 60 × 10 box with a 1 px border, the preset’s track_color under the empty part and level_color under the filled part, and the texture scaled to 10 px tall, keeping its aspect ratio, tiled across the filled part. The box scrolls the whole scaled texture, so loop_width, tint_from_color and tint_end do not apply to it; tint does. The backing colors are drawn first, so art for the box can leave gaps for them to show through.
9. Apoli-compat sprite_location sheets (static restyled bars)
Separate from the bar styles above: Apoli-style resource powers can declare hud_render.sprite_location to swap the whole static bar sheet for a custom one. NeoOrigins honors that override. This section is the spec for authoring such a sheet.
Where the texture lives
sprite_location is a full resource path used verbatim: e.g. "sprite_location": "mypack:textures/gui/my_bars.png" loads assets/mypack/textures/gui/my_bars.png from your resource pack / datapack assets. An empty or malformed id, or one naming a texture no loaded pack has, falls back to the vendored default sheet (neoorigins:textures/gui/resource_bar.png). Community Apoli restyle sheets use the same coordinates and drop in unchanged.
Required sheet dimensions
256 × 256 PNG. The renderer samples UVs against a 256 × 256 texture: any other canvas size misaligns every element. Only the top-left region is used; leave the rest transparent.
Sheet layout (what bar_index / icon_index select)
| Element | Position in sheet | Size | Selected by |
|---|---|---|---|
| Frame / backing | u 0, v 0 | 71 × 5 | fixed (shared by all bars) |
| Fill row | u 0, v 8 + bar_index × 10 | 71 × 8 | bar_index (row) |
| Icon | u 73 + icon_index × 9, v 8 + bar_index × 10 | 8 × 8 | icon_index (column) + bar_index (row) |
- Vertical stride between fill rows is 10 px (8 px fill + 2 px gap):
bar_index0 → v 8, 1 → v 18, 2 → v 28, … - Icons sit to the right of the fill area in the sheet (first column at u 73), on the same v row as their fill. Each bar row carries its own icon variants, 9 px horizontal stride (8 px icon + 1 px gap).
How it draws in game
The frame strip renders at the bar position; the fill renders clipped to the leftmost round(71 × fill%) pixels and overhangs the frame upward by 2 px (exactly as Apoli draws it); the icon renders 10 px left of the bar, top-aligned with the fill. Pixel art at native resolution, RGBA, transparent background.