HomeJavaModsHigh Level Peripherals
High Level Peripherals
ModsJava

High Level Peripherals

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

⬇ Download on Modrinth

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

Limit Value
Grid size Up 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.

3. Sizing

Call Effect
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.

Call Notes
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

Call Notes
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

Call Returns
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.

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

9. Memory

Call Returns
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.

Event Args Trigger
tm_monitor_touch side, x, y, soft Whichever button is bound to "use" (right-click by default). soft is always false.
tm_monitor_mouse side, x, y, button, action Mouse button press/release.
tm_monitor_scroll side, x, y, dir dir is 1 (up) or -1 (down).
tm_monitor_drag side, x, y, button Cursor 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()
Call Notes
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 / glTexImage Texture 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).

Verified by MCModsHub

These come from our own check of the pack file, not from the source page.

Explore more