diff --git a/player-sensor/ligma.lua b/player-sensor/ligma.lua
new file mode 100644
index 0000000..efab9ec
--- /dev/null
+++ b/player-sensor/ligma.lua
@@ -0,0 +1,98 @@
+-- Configuration
+
+local WH_URL = "https://discord.com/api/webhooks/id/token"
+local IGNORE = { "player1", "player2" } -- case sensitive
+local DIMENSION = "minecraft:overworld" -- dimension the area is in
+local AREA = {                          -- The cubic area to monitor for players
+  [0] = { x = 100, y = 0, z = 200 },    -- Position 1
+  [1] = { x = 200, y = 200, z = 300 }   -- Position 2
+}
+local REDSTONE_SIDE = "right"  -- pulse a redstone signal to this side whenever a player is detected
+
+-- End of configuration
+
+local sensor = peripheral.find("playerDetector")
+local KNOWN_PLAYERS = {}
+local COOLDOWNS = {}
+local COOLDOWN = 0.1
+
+function sendWhMessage(msg)
+  local payload = { content = msg } 
+  http.post(WH_URL,
+            textutils.serializeJSON(payload),
+            { ["Content-Type"] = "application/json" })
+end
+
+function findPlayers()
+  local players = sensor.getPlayersInCoords(AREA[0], AREA[1])
+  return players
+end
+
+function getPlayerPos(player)
+  local pos = sensor.getPlayerPos(player)
+  return pos
+end
+
+function isInArr(arr, val)
+  for k,v in pairs(arr) do
+    if v == val then return k end
+  end
+  return false
+end
+
+function bell()
+  redstone.setOutput(REDSTONE_SIDE, true)
+  sleep(0.1)
+  redstone.setOutput(REDSTONE_SIDE, false)
+end
+
+function timestamp()
+  return (os.day() * 24) + os.time()
+end
+
+function isCooldown(player)
+  local item = COOLDOWNS[player]
+  local time = timestamp()
+  return not (not item or item < time)
+end
+
+function setCooldown(player)
+  COOLDOWNS[player] = timestamp() + COOLDOWN
+end
+
+function isIgnore(player)
+  return isInArr(IGNORE, player) ~= false
+end
+
+while true do
+  local found = findPlayers()
+
+  -- check for new players
+  for k,v in pairs(found) do
+    local pos = getPlayerPos(v)
+    local inArr = isInArr(KNOWN_PLAYERS, v)
+
+    if pos ~= nil and pos.dimension == DIMENSION and not inArr and not isCooldown(v) and not isIgnore(v) then
+      setCooldown(v)
+      print("Player "..v.." entered area")
+      bell()
+      sendWhMessage("Player `"..v.."` entered area "..
+        "at `"..pos.x..","..pos.y..","..pos.z.."`.")
+    
+      table.insert(KNOWN_PLAYERS, v)
+    end
+  end
+  
+  -- check if players left the area
+  for k,v in pairs(KNOWN_PLAYERS) do
+    local pos = getPlayerPos(v)
+    if pos ~= nil and (not isInArr(found, v) or pos.dimension ~= DIMENSION) and not isCooldown(v) and not isIgnore(v) then
+      setCooldown(v)
+      print("Player "..v.." left area")
+      bell()
+      sendWhMessage("Player `"..v.."` left area at `"..
+        pos.x..","..pos.y..","..pos.z.."`.")
+      table.remove(KNOWN_PLAYERS, isInArr(KNOWN_PLAYERS, v))
+    end
+  end
+end