Skip to content

High Level Peripherals

This is a fork of the mod Tom's Peripherals with minor additions and fixes

NeoForge
Loaders
NeoForge
Downloads on Modrinth
304
Followers on Modrinth
1
versions
3
Updated
July 2, 2026Jul 2
Published
in 2026

At a glance

Runs on NeoForge
For Minecraft 1.21.1
Needed in the game and on the server
Latest version — 1.4.3 from July 2, 2026
License MIT — free
Where it's needed
In gamerequiredOn serverrequired

Needed both in the game and on the server

Game versions1.21.1

High Level Peripherals

A CC:Tweaked monitor peripheral that actually keeps up with what you want to build.

A fork of Tom's Peripherals, rebuilt to be far more usable, stable, and complete — bigger screens, real GPU-rendered shaders, full mouse/touch input, and a cleaner API that doesn't fight you.

✨ Features

🖥️ Big, sharp monitors

Build arrays up to 32x32 blocks (admin-adjustable up to 64x64), with per-block resolution up to 4096x4096. Draw with a full 2D API — filled shapes, gradients, text with custom fonts, image loading, double buffering — all running server-side, synced to every client automatically.

⚡ Real GPU shaders, not Lua math

Write a small GLSL-like shader once and it renders live on every viewer's own graphics card, at their own framerate, completely decoupled from the server tick. No more choking the game with per-pixel Lua raymarching — the shader engine handles that with zero Lua involved per pixel. Includes first-class raytracing primitives (sphere/plane/box intersection) so you're not hand-rolling ray math from scratch.

gpu.compileShader([[
  color = vec3(uv.x, uv.y, sin(time));
]])

That's it — it's already rendering.

🖱️ Full mouse input

Click, right-click, drag, and scroll directly on a monitor's screen face, with pixel-accurate coordinates delivered straight to your script. Respects whatever controls the player has configured — no hardcoded key assumptions. Perfect for building actual interactive UIs, not just static displays.

🎮 3D immediate-mode rendering

An OpenGL-1-style API (glBegin/glVertex/glTranslate/glRotate/lighting) for building real 3D scenes on a monitor without writing a shader — great for models, diagrams, or simple games.

🔆 Brightness control

Scale a monitor's output brightness in nits, from dim ambient displays to eye-searingly bright — applies to both drawn pixels and live shaders.

🧠 Room to build big

Generous default VRAM budget (~2 GiB per screen) shared across framebuffers, images, and shader textures, with server-configurable limits for bigger builds.

Why this fork?

Tom's Peripherals gave monitors and a GPU peripheral, but hit real ceilings fast — low resolution limits, no shader rendering, no mouse input, and a handful of long-standing multiblock/sync bugs. High Level Peripherals keeps the same familiar peripheral.find("tm_monitor") API you already know, and pushes every one of those ceilings out — so your builds stop being limited by the peripheral and start being limited by your imagination.

Getting started

local gpu = peripheral.find("tm_monitor")
gpu.fill(0x000000)
gpu.drawText(10, 10, "Hello, HLPS!", 0xFFFFFF)

Full API reference below.

Docs

tm_monitor Lua API Reference

Complete reference for the monitor peripheral: 2D drawing, text, images, the 3D immediate-mode API, mouse/scroll input, and the shader engine.

1. Limits

LimitValue
Grid sizeUp to 32x32 blocks by default (maxScreenSize, 1-64). Over limit → every call throws.
gpu.setSize(n)64–4096 px/axis, default 1024.
gpu.setGpuResolution(w, h)64–4096 px/axis, or (0,0) for auto.
VRAM budget~2 GiB default (maxVRAMSize), shared across framebuffer/images/buffers/textures.

2. Color format

Packed 0xRRGGBB ints, or (r,g,b[,a]) 0-255 each.

  • Alpha 0 or 255 → opaque.
  • Alpha 1..254 → source-over blend: out = (src*a + dst*(255-a)) / 255.
  • getPixel/getpx return 0xRRGGBB (alpha stripped).

3. Sizing

CallEffect
gpu.setSize(n)Per-block resolution, one axis. Total canvas is (blocksWide*n) x (blocksTall*n).
gpu.getSize()→ width, height, cols, rows, blockSize.
gpu.getResolution()→ width, height.
gpu.refreshSize()Forces a re-scan of the array's grid layout.
gpu.debugTiling()→ string dump of live server-side tiling state, for diagnosing a wrong-looking array.

Keep setSize low (64-256) if drawing per-pixel in Lua — use the shader engine (section 8) instead for anything procedural.

4. Basic 2D drawing

All coordinates are 1-based.

CallNotes
gpu.fill([color])Fills the canvas. Default black.
gpu.clear([color])Alias of fill.
gpu.setPixel(x, y, color)Out-of-bounds writes ignored.
gpu.getPixel(x, y)→ int, 0 if out of bounds.
gpu.filledRectangle(x, y, w, h, [color])Throws if out of bounds.
gpu.rectangle(x, y, w, h, [color])Outline only.
gpu.line(x1, y1, x2, y2, [color])Bresenham.
gpu.lineS(x1, y1, x2, y2, [color])Alternate algorithm.
gpu.circle(cx, cy, r, [color])Outline.
gpu.fillCircle(cx, cy, r, [color])Filled.
gpu.triangle(x1,y1, x2,y2, x3,y3, [color])Outline.
gpu.fillTriangle(x1,y1, x2,y2, x3,y3, [color])Filled.
gpu.gradientRectangle(x, y, w, h, c1, c2, [vertical])Linear interpolation between two colors.
gpu.copy(srcX, srcY, w, h, dstX, dstY)Overlap-safe. Capped at 64M px.
gpu.scroll(dx, dy, [fillColor])Shifts canvas; exposed area filled. Same cap.
gpu.drawBuffer(x, y, w, scale, ...pixels)Row-major pixels as vararg numbers, not a table.

5. Double buffering

gpu.setDoubleBuffered(true)
-- ... draw calls ...
gpu.flush()   -- presents + syncs

gpu.sync() pushes the framebuffer directly (throttled internally) — not usually needed outside double-buffering/shader flows.

6. Text

CallNotes
gpu.drawText(x, y, text, [fg=-1], [bg=-1], [size=1], [pad=1])-1 skips that layer.
gpu.drawTextSmart(x, y, text, [fg], [bg], [forceUnicode=false], [size=1], [pad=1])Auto ASCII/unicode fonts (ASCII draws at 2x size).
gpu.getTextLength(text, [size=1], [pad=1])→ pixel width.
gpu.getFont()→ name, editable.
gpu.setFont(name)No-op if font doesn't exist.
gpu.drawChar(x, y, charIndex, [fg], [bg], [size=1])Draws one glyph, 1-based index.
gpu.addNewChar(char, width, ...16 numbers)→ int. Font must be editable.
gpu.delChar(char) / gpu.freeChars() / gpu.clearChars()Glyph management.
gpu.setFontDefaultCharID(id) / gpu.getFontDefaultCharID()Fallback glyph.

7. Images and buffers

CallReturns
gpu.newImage(w, h)Blank LuaImage.
gpu.imageFromBuffer(w, ...pixels)LuaImage from raw pixel data.
gpu.decodeImage(bufferRef) / gpu.decodeImage(...bytes)Decodes PNG/etc.
gpu.newBuffer([initialCapacity=32])Growable LuaByteBuffer.
gpu.drawImage(x, y, image)Draws, clipped to canvas.

All charge VRAM (w*h*4 bytes) up front and throw if over budget.

8. The shader engine

Write a small GLSL-like program once; it runs per-pixel on the real GPU, no Lua involved.

gpu.compileShader([[
  float sdSphere(vec3 p, float r) { return length(p) - r; }
  uniform float speed;
  color = vec3(uv.x, uv.y, sin(time * speed));
]])
gpu.setUniform("speed", 2.0)

There's no main — code after the function defs runs top-to-bottom; color is the pixel output. gpu.clearShader() returns to normal 2D drawing.

  • gpu.isGpuMode() → true while a shader is live.
  • gpu.setUniform(name, value) / gpu.setUniform3(name, x, y, z) — live-update, no recompile.
  • gpu.setGpuResolution(w, h) — resolution the shader renders at (independent of setSize). Match your array's cols:rows shape or don't call it.

A live shader has no ongoing tie to the computer that started it — it stops only if the last attached computer disconnects, or you call gpu.clearShader().

texture() isn't GPU-accelerated yet — a texture-sampling shader compiles fine but won't auto-render. Drive it yourself:

gpu.compileShader(src)
gpu.uploadTexture(0, w, h, pixels)
while true do
  gpu.runShader(os.clock())
  gpu.sync()
  sleep(0)
end
Shader language
  • Two types: float, vec3.
  • Predefined: color (write this), uv (.x/.y 0..1, .y=0 at top), res, time.
  • uniform <float|vec3> name;
  • Functions: <float|vec3> name(params) { ...; return expr; }. No recursion. Must appear before any other top-level statement, including uniform declarations.
  • Control flow: if/else, for (init; cond; update) {}, break;, return expr;.
  • Operators: + - * /, unary - !, comparisons, && ||, .x .y .z swizzle. vec3 * float works; float * vec3 does not.
  • Built-ins: vec3(f,f,f), sin cos tan sqrt abs floor fract exp pow mod min max step clamp mix smoothstep length dot cross normalize reflect, texture(slot, u, v).
  • Raytracing builtins (return nearest positive hit distance, or -1.0 for a miss): intersectSphere(ro, rd, center, radius), intersectPlane(ro, rd, planeY), intersectBox(ro, rd, center, halfSize).

9. Memory

CallReturns
gpu.getUsedMemory()Bytes currently used.
gpu.getMaxMemory()VRAM budget for this peripheral.

10. Mouse & scroll input

Fires only while looking at the screen face with no GUI open. Sneaking has no effect. Keyboard input isn't captured here — that's a separate keyboard peripheral.

EventArgsTrigger
tm_monitor_touchside, x, y, softWhichever button is bound to "use" (right-click by default). soft is always false.
tm_monitor_mouseside, x, y, button, actionMouse button press/release.
tm_monitor_scrollside, x, y, dirdir is 1 (up) or -1 (down).
tm_monitor_dragside, x, y, buttonCursor moved this tick while held. Once per client tick.

x, y are screen-absolute (1-based) across the whole array.

while true do
  local ev, side, x, y, button, action = os.pullEvent("tm_monitor_mouse")
  gpu.setPixel(x, y, 0xFF0000)
  gpu.sync()
end

11. 3D immediate-mode API

gpu3d = gpu.createWindow3D(...)
gpu3d.glFrustum(70, 0.1, 100)
gpu3d.glLoadIdentity()
gpu3d.glTranslate(0, 0, -5)
gpu3d.glDirLight(0, -1, 0)
gpu3d.glBegin(4)   -- triangles
gpu3d.glColor(0xFF0000)
gpu3d.glVertex(-1, -1, 0)
gpu3d.glVertex( 1, -1, 0)
gpu3d.glVertex( 0,  1, 0)
gpu3d.glEnd()
gpu3d.render()
gpu3d.sync()
CallNotes
glFrustum(fov, near, far)Perspective projection.
glDirLight(x, y, z)Directional light.
glLoadIdentity() / glPushMatrix() / glPopMatrix()Model matrix stack.
glTranslate / glScale / glRotate(angleDeg, x,y,z)
glBegin([mode=4]) / glEnd()Start/finish a primitive.
glVertex(x,y,z)Appends a vertex with current color/UV.
glTexCoord(u,v)UV for the next vertex.
glColor(color)Packed int or (r,g,b[,a]).
glEnable(3553) / glDisable(3553)Only GL_TEXTURE_2D supported.
glGenTextures() / glDeleteTextures / glBindTexture / glTexImageTexture management.
getConstants()GL constant name→value table.
render()Culls, lights, clips, projects, sorts, blits since last clear().
clear()Wipes canvas + triangles + resets matrix/depth buffer.

12. Performance

All drawing is server-side Java, always — singleplayer, LAN, or dedicated. Pushing pixels to the client is the one real client cost, done via a bulk memory copy.

Per-pixel Lua drawing (raymarching, plasma, etc.) will choke a client — use the shader engine instead, which runs on the GPU with zero Lua per pixel.

13. Brightness (nits)

gpu.setBrightness(200)   -- 2x normal
print(gpu.getBrightness())

nits / 100 scales final pixel output — 100 is default (1.0x). Applies to both CPU drawing and GPU shaders. Values that would exceed 255 clip instead of wrapping. Range is server-configurable (minBrightnessNits/maxBrightnessNits, default 10–400).

FAQ

How to install High Level Peripherals?

Install NeoForge for your Minecraft version, download High Level Peripherals for the same version and loader, put the file into the mods folder and launch the game with the loader profile.

Which Minecraft versions does High Level Peripherals support?

High Level Peripherals has builds for Minecraft 1.21.1.

Is High Level Peripherals needed on the server?

Needed in the game and on the server

License and source
MIT Licensefree to use and share with credit to the author
Original — Modrinth↗Files unchanged, verified with SHA-512Is this your mod? For rights holders

The site uses cookies: the necessary ones for sign-in and the theme, plus the Yandex Metrica and LiveInternet visit counters — they show us how the site is used. We have no advertising cookies. More