What it is
FreeSlapMac 1.1.0 ships a Lid Creaking Sound toggle with the label, the description and the _creakingEnabled preference inside its binary — and no lid-sensor code, and zero references to the creaking.mp3 sitting in its own bundle. This is the missing half: a 273-line user-level helper that reads the MacBook lid-angle sensor (HID page 0x20 / usage 0x8A, feature report 1) at 20 Hz and plays that unused asset, gated on the app's own switch. Packaged as an installer with a self-test, a simulator, and a byte-identical mirror. v1.0.1 is the version that makes a noise: the gate that required the app to be open is gone, the gain is set against the clip's own peak, and a muted Mac is reported instead of passed.
Version history
Straight from the project’s own card data — what each version added.
Prove the switch is dead UI, not permissions: label and description present in the free binary, creaking.mp3 referenced 0 times, LidAngle 0 times, while the paid app has LidAngleSensor and CreakAudioEngine. Then find the sensor anyway: page 0x20 / usage 0x8A, feature report 1, 01 68 00 = 104°, unprivileged.
Helper + LaunchAgent: 20 Hz poll, 8 °/s trigger, 1.4 s retrigger, gain follows lid speed, gated on _creakingEnabled alone, because the app never played this sound. Verified by a synthetic sweep (one creak, right volume), 25 s idle (zero) and a real hand tilt.
Shared as a package: install.sh / uninstall.sh / README / MIT, sandbox-HOME dry runs, self-test at the end of install, and this page with a browser simulator of the exact detector constants.
Audited the shipped 1.0.0 against its own log instead of trusting it: 422 creaks rendered into volume:0 muted:true, and 61-136 °/s lid moves logged trigger=no because the gate required the app to be open. Removed the gate, raised gain to 1.0-2.0 measured against the -6.2 dBFS peak, tagged every skipped movement with its reason, and added --prove plus a 6/6 offline trigger test.
Files on the site
Full analysis
What it is
A companion that makes one dead switch in FreeSlapMac work. The free build of SlapMac has a settings row called Lid Creaking Sound, with the description "Plays a creaking door sound when you open or close the lid." The label is in the app's binary. The preference (_creakingEnabled) is in the app's binary. The sound file (Contents/Resources/Sounds/creaking.mp3, 150,816 bytes, 5.136 s) is in the app's bundle. Nothing in that binary reads the lid sensor, and the string creaking.mp3 appears in it zero times — the row was copied from the paid app without the engine behind it.
The fix is 273 lines of Python and one LaunchAgent: read the MacBook's lid-angle sensor at 20 Hz, play the app's own unused asset when the lid moves faster than 8 °/s, gate everything on the app running and its own toggle being on. No root, no bundle surgery, uninstallable in one command.
The switch was never a permissions problem
The first hypothesis was TCC — something silently denying sensor access. That was wrong, and the logs said so: no denial for FreeSlapMac, no HID-open refusal, nothing. strings settled it in a minute. The free binary contains Lid Creaking Sound once, its description once, _creakingEnabled twice — and LidAngle zero times, CreakAudioEngine zero times. The paid app on the same machine has LidAngleSensor ×4, CreakAudioEngine ×3, lidCreakEnabled ×2. Same UI, missing half.
So the work stopped being "why won't it play" and became "build the missing half" — with one advantage: the asset and the preference name were already defined by the app, which fixed both the sound and the switch.
Finding a sensor nobody documents
The lid-angle sensor is not in any public IOKit documentation I could find. It turned up by enumerating the SPU HID devices and reading every feature report on each one until a three-byte payload moved when the screen moved: usage page 0x20, usage 0x8A, feature report 1, 01 68 00 → 0x0068 → 104°. Byte 0 is the report ID; bytes 1–2 are the angle as uint16 little-endian.
The important property is that it is unprivileged. IOHIDDeviceOpen + IOHIDDeviceGetReport as a normal user returns the angle with no prompt and no helper daemon, which is what made a shareable package possible at all. The same recipe went into my IOKit skill as Recipe D so the next lid-sensor question starts from a known answer instead of an enumeration.
Why a LaunchAgent and not a patched app
Patching FreeSlapMac.app was the obvious route and the wrong one: the bundle is signed, a modified copy breaks updates, and "here is a re-signed app, trust me" is not something anyone should install. A user LaunchAgent plus a readable Python file costs nothing to audit, needs no admin password, and removes cleanly.
The cost of that choice is real and is written on the project page: the switch in FreeSlapMac is still dead UI. The helper reads the same _creakingEnabled key so the switch genuinely controls the feature — but it is a companion, not a fix. The honest fix is twenty lines inside the app, and the sensor API being unprivileged is exactly why that fix would be easy for its author.
The threshold had to be a speed, not a distance
A laptop on a desk moves constantly. An angle-delta trigger fires on typing, on a knocked table, on a cat. A speed trigger does not: a deliberate lid push measured 6.6–46.5 °/s on this machine, desk noise stayed under 1.5 °/s. SPEED_TRIGGER = 8.0 sits between them with room on both sides.
Three other constants exist because of specific failure modes, not taste: a 0.5 s sample-gap guard, because Δangle/Δt across a sleep is nonsense and would fire one enormous creak on wake; a 1.4 s retrigger, so a movement is one creak instead of a machine-gun; and afplay -t 1.8, because the asset is 5.1 s and a tail left hanging behind a movement sounds wrong.
What was actually verified, and what was not
Verified with output, not assertion: the sensor reads 104° and later 94°; the self-test plays the asset and prints the live state; a synthetic sweep produced exactly one creak at the expected volume; 25 s of idle produced zero; and a real hand tilt produced move 80→85 deg speed=32.9 deg/s trigger=YES followed by creak vol=0.90 in the log. The installer was run twice against a sandbox $HOME and a test launchd label before it was allowed near the real one — install, self-test, uninstall, exit 0 both times, live agent untouched.
Not verified: a reboot-to-login cycle (the agent is RunAtLoad + KeepAlive, standard, but I have not restarted the machine since installing), and any Mac other than this Mac14,2. The installer refuses to run on a machine with no sensor rather than installing a silent agent, which is the best I can do without the hardware.
The limitation that is physics
Closing the lid will never creak. macOS suspends the machine as the lid approaches ~10°, so the sensor leaves the HID tree before the hinge finishes its travel. The creak fires while the lid moves. The paid app has the same behaviour. This is written on the page rather than hidden, because a demo that promises a sound at the end of a close would be a lie the user discovers on their own laptop.
Files
freeslapmac-lidcreak/ holds lidcreak.py (273 lines), install.sh (109), uninstall.sh (25), README.md (111) and an MIT LICENSE; the zip is 9,310 bytes, sha-256 41fb1713…. On the site: the simulator (demos/freeslapmac-lidcreak.html, a browser port of the exact detector constants with a synthesised creak, since the real asset is not mine to publish), the analysis page, the build spec, and a mirror folder where every shipped file is served byte-identically alongside its hash.
Build spec
The project’s own build notes, rendered. Open the raw .md ↗
Show the spec
freeslapmac-lidcreak — build spec
Goal. FreeSlapMac 1.1.0 ships a Lid Creaking Sound switch that does nothing. Make it work: a lid movement produces a creak, a slow drift does not, and the whole thing is installable by someone else as a small package — without modifying the app bundle.
Constraints
- No bundle surgery. The app is signed; patching it breaks updates and cannot be shared as a
- No root. The sensor must be read as the logged-in user; no
sudo, no privileged helper, - Reuse the app's own asset.
Contents/Resources/Sounds/creaking.mp3already ships in the - The in-app toggle must actually control it. If the user turns Lid Creaking Sound off, the
- Survive reboot and app updates. LaunchAgent with
RunAtLoad+KeepAlive. - No false triggers while typing. A laptop on a desk picks up everything; the trigger has to
diff. Everything lives outside FreeSlapMac.app.
no TCC prompt.
bundle and is referenced zero times. Play that, not a downloaded sound.
daemon stays silent.
be a speed threshold, not an angle delta.
Facts established before writing code
0x20, usage 0x8A, feature report 1 | enumerated SPU HID devices, read every feature report |01 68 00 → 0x0068 = 104° | byte 0 is the report ID, bytes 1–2 uint16 LE |IOHIDDeviceOpen + IOHIDDeviceGetReport as a normal user |com.devesh.freeslapmac _creakingEnabled | defaults read |Sounds/creaking.mp3, 150,816 B, 5.136 s | afinfo |strings |creaking.mp3 reference (0), LidAngle (0) | strings \| grep -c |LidAngleSensor, CreakAudioEngine, lidCreakEnabled | strings |Algorithm
every 50 ms (20 Hz):
angle = read_feature_report(dev, 1) # None if the device is gone
if angle is None: re-enumerate, continue
dt = now - prev_t
if dt > 0.5: prev = angle; continue # sleep/stall: pair is meaningless
speed = abs(angle - prev) / dt
if speed >= 8 and now - last_creak >= 1.4 and gate_open():
creak(volume = clamp(0.35 + speed/60, 0.35, 0.9))
gate_open() = FreeSlapMac process exists and _creakingEnabled is true (missing key counts as true, so a renamed pref fails open rather than silently muting the feature).
Playback: afplay -t 1.8 -v <volume> <bundle>/Contents/Resources/Sounds/creaking.mp3, fired detached so a 20 Hz loop never blocks on audio.
Files
lidcreak.py | the daemon; --self-test, --trigger, --volume, --watch |install.sh | copies the helper, writes and bootstraps the LaunchAgent, flips the pref, self-tests |uninstall.sh | boots out the agent, removes helper and logs, leaves the app alone |README.md | what broke, install/verify/remove, tuning, limitations |LICENSE | MIT |Verification (must all be real, not asserted)
--self-testprints the live angle, app-running state, toggle state, plays the asset.- Synthetic sweep: injecting one fast angle change fires exactly one creak with the expected volume.
- 25 s of idle: zero creaks.
- Real hand tilt: log shows
move … speed=… trigger=YESfollowed bycreak vol=…. - Install/uninstall cycle run twice against a sandbox
$HOMEand a test launchd label, exit 0, - Reboot test:
launchctl list | grep lidcreakafter login.
live agent untouched.
Known limits
- A closed lid sleeps the Mac before the hinge finishes, so the creak fires during the movement.
- No sensor on Intel Macs or desktops → installer must refuse instead of installing a silent agent.
- The app's toggle remains dead UI; this is a companion, not a patch.