DirkScripts
Model Only

Everything in this GIF can be done with the models alone. This page shows how.
dirk_keypadModel is the keypad's models without the script. Use it when you want to drive the keypad from your own code. Want it working out of the box? The script has these same models inside it.
⚠️ Run dirk_keypadModel or dirk_keypad, never both: the script already streams these models.
#What's in it
| Model | What it is |
|---|---|
dirk_keypad | The keypad for walls. One cheap piece (460 tris) with its own collision. Place this one. |
dirk_keypad_hd | The detailed housing: screen, LEDs, screws, bezel. Spawn it over dirk_keypad only while someone is using it. |
dirk_keypad_key_1 … _9, _0, _star, _hash | The 12 keys, each its own model so each can move on its own. |
dirk_keypad_lockscreen | A red padlock screen (2 tris). Attach it to dirk_keypad at 0, 0, 0 to show a keypad is locked. |
All the textures are in one dictionary, dirk_keypad_txd. The whole pack streams about 140 KB.
Start it like any resource: ensure dirk_keypadModel.
#Placing it
Every model's origin is the centre of its back face, and its front faces the model's -Y. So stand it flat on a wall with its forward direction (+Y) pointing into the wall: the heading the player has when facing the keypad.
lualocal keypad = CreateObjectNoOffset(`dirk_keypad`, coords.x, coords.y, coords.z, false, false, false) SetEntityHeading(keypad, heading) FreezeEntityPosition(keypad, true)
#Swapping in the detailed keypad
Keep dirk_keypad on the wall for everyone. When a player uses it, hide it for them and spawn dirk_keypad_hd in exactly the same place. The hidden piece keeps its collision.
lualocal pos, rot = GetEntityCoords(keypad), GetEntityRotation(keypad, 2) local hd = CreateObjectNoOffset(`dirk_keypad_hd`, pos.x, pos.y, pos.z, false, false, false) SetEntityRotation(hd, rot.x, rot.y, rot.z, 2, false) SetEntityCollision(hd, false, false) FreezeEntityPosition(hd, true) SetEntityVisible(keypad, false, false)
#Pressing the keys
Each key attaches to dirk_keypad_hd at its offset. To press a key, attach it a little further along +Y: 2.5 mm is a full press.
| Key | Offset (x, y, z) |
|---|---|
| 1 | -0.0260, -0.0289, 0.0190 |
| 2 | 0.0000, -0.0289, 0.0190 |
| 3 | 0.0260, -0.0289, 0.0190 |
| 4 | -0.0260, -0.0289, -0.0050 |
| 5 | 0.0000, -0.0289, -0.0050 |
| 6 | 0.0260, -0.0289, -0.0050 |
| 7 | -0.0260, -0.0289, -0.0290 |
| 8 | 0.0000, -0.0289, -0.0290 |
| 9 | 0.0260, -0.0289, -0.0290 |
| star | -0.0260, -0.0289, -0.0530 |
| 0 | 0.0000, -0.0289, -0.0530 |
| hash | 0.0260, -0.0289, -0.0530 |
luaAttachEntityToEntity(key, hd, 0, off.x, off.y + depth, off.z, 0.0, 0.0, 0.0, false, false, false, false, 2, true)
The press in the GIF uses this curve. Re-attach the key every frame while it moves:
- In: 0 to 2.5 mm in 45 ms, easing out (
2.5mm * (1 - (1 - t/0.045)^3)). - Hold: 50 ms at the bottom (or as long as the mouse is held).
- Out: a spring back that overshoots a little:
2.5mm * e^(-t/0.04) * (cos(w t) + sin(w t) / (w * 0.04))withw = 39.27, settled after 0.25 s. - Tilt (optional): up to 2.5° toward the side that was pressed, following the same curve.
#Showing a lockout on the wall
dirk_keypad (the wall piece) has a blue resting screen baked in. To show it's locked, attach dirk_keypad_lockscreen over it: it sits just in front of the screen with a red padlock, and needs no DUI.
lualocal lock = CreateObjectNoOffset(`dirk_keypad_lockscreen`, pos.x, pos.y, pos.z, false, false, false) SetEntityCollision(lock, false, false) AttachEntityToEntity(lock, keypad, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false, false, false, false, 2, true) -- delete it when the lockout ends
#The screen, backlight and LEDs
Everything on dirk_keypad_hd and the keys that lights up draws from one 512 x 512 texture, dirk_keypad_panel in dirk_keypad_txd. Put your own DUI over it and you control the screen, every key's glow and both LEDs at once:
| Area (pixels) | What it lights |
|---|---|
| x 0–512, y 0–256 | The screen |
| y 256–448: 6 x 2 cells of 85 x 96 | Each key's glyph, in the order 1 2 3 4 5 6 / 7 8 9 * 0 # |
| circle at (48, 480) | The red LED |
| circle at (128, 480) | The green LED |
lualocal dui = CreateDui('https://your.site/keypad.html', 512, 512) local txd = CreateRuntimeTxd('my_keypad_rt') CreateRuntimeTextureFromDuiHandle(txd, 'panel', GetDuiHandle(dui)) AddReplaceTexture('dirk_keypad_txd', 'dirk_keypad_panel', 'my_keypad_rt', 'panel') -- when you are done: RemoveReplaceTexture('dirk_keypad_txd', 'dirk_keypad_panel')
Draw your page in that layout: brighter pixels glow brighter. The wall piece, dirk_keypad, uses its own texture (dirk_keypad_panel_lo), so your DUI never changes the keypads nobody is using.
For real light on the wall at night, add a small light in front of the keys each frame while the keypad is in use:
lualocal at = GetOffsetFromEntityInWorldCoords(hd, 0.0, -0.06, -0.018) DrawLightWithRange(at.x, at.y, at.z, 205, 225, 240, 0.28, 0.9)
#What the script adds
The dirk_keypad script does all of the above for you, and adds server-checked codes, attempt limits and lockouts, native sounds heard by nearby players, 13 languages, and a one-line export.
Last updated on 30 September 2026
