What it is
FreeSlapMac 1.1.0 cannot be silenced: the slap sounds are not the app's at all, they are 267 MP3s played by the bundled spank process, and neither side has a volume or mute. Its whole preference set is sensitivity, triggerMode, screenFlash, launchAtLogin and _creakingEnabled. So this builds a copy whose entire sound library is digital silence at the original duration — a 417-byte MPEG frame of all-zero side info per 1152 samples — re-signed ad-hoc like the original, with every clip decoded back through AudioToolbox to prove zero non-zero bytes. One bash script, no python, no brew.
Version history
Straight from the project’s own card data — what each version added.
Prove there is no off switch: five preferences and none of them audio; spank exposes --custom/--min-amplitude/--cooldown/--speed/--volume-scaling and no mute. Then rule out the shortcuts — pause is the wrong layer, killing spank gets respawned by the root wrapper, and the world-writable /tmp/freeslapmac_cmd is eval'd as root.
Silence the library: 417-byte MPEG-1 L3 frames, all-zero side info, duration matched per clip. First build used ffmpeg with one shared temp file and corrupted 23 of 267 clips — the verifier reported 244/267 rather than passing, so the builder was rewritten in pure bash with unique outputs.
Ship it so a stranger can use it: ditto copy, rename, ad-hoc re-sign, quarantine strip, then verify 267/267 digitally silent with 0.00 s drift, valid signature, unchanged bundle id and identical executable. Tested end to end from a fresh folder against a copy of the app in /tmp, not the installed one.
Files on the site
Full analysis
FreeSlapMac Silent — build reflection
What was asked
"How do I turn off creaking and tap sound" — then, after the honest answer that the tap sound has no off switch: "how about you build one that works."
The creak half already existed (my lid-angle helper, gated on the app's own _creakingEnabled preference). This build is the tap half: a FreeSlapMac you can run without noise, without losing detection.
What the app actually offers
defaults read com.devesh.freeslapmac→ five keys:sensitivity,triggerMode,screenFlash,spank --help→--custom,--min-amplitude,--cooldown,--speed,--volume-scaling. No mute.- The MP3s live in
Contents/Resources/Sounds/and are played byspank, not by the app.
launchAtLogin, _creakingEnabled. No volume, no soundEnabled.
So the sound is not the app's to turn off. Everything else follows from that sentence.
Routes rejected
spank | the root wrapper respawns it from LAST_CMD |/tmp/freeslapmac_cmd | it is chmod 666 and eval'd as root — works, and that is exactly why not |Build
ditto copy → every MP3 replaced with a hand-built silent MPEG-1 Layer III frame (header FF FB 90 C0, zeroed side info and main data, 417 bytes per 1152 samples = 26.122 ms) at each clip's original duration → CFBundleName/CFBundleDisplayName renamed → ad-hoc re-sign (the original is Signature=adhoc too) → quarantine stripped. CFBundleIdentifier deliberately unchanged, so sensitivity, mode, cooldown and the creak preference carry over.
What broke, and why the verifier exists
The first build used ffmpeg inside a thread pool, and every worker wrote to the same temp filename. 23 of 267 clips came out undecodable. The verifier reported silent 244/267, undecodable 23 instead of passing the build — which is the only reason the bug was caught before the package was published rather than after.
Fixing it removed the dependency as well: the silent frame needs no encoder, and afconvert (AudioToolbox, the same decoder spank uses) is all the checking needs. A tool that makes a stranger brew install ffmpeg before they can silence their own laptop is a tool nobody runs.
Evidence
== files == original: 267 mp3 silent: 267 mp3
== decode check == decoded: 267 digitally silent: 267 audible: 0 duration mismatches: 0
== signature == valid (ad-hoc)
== identity == bundle id unchanged · display name changed · executable identical code
== size == original 15M → silent 14M
PASS
Also tested as a stranger would meet it: package copied to a fresh folder, a copy of the app placed in /tmp/stranger/apps, bash build.sh "<src>" "<dest>" with explicit paths → PASS, and a second run without FORCE=1 → refuses with exit 1.
What I found on the way
The app's launch wrapper runs as root, chmod 666 /tmp/freeslapmac_cmd, and evals whatever lands in that FIFO. Any local process can take root while the app is running. Not used by this build, documented on the analysis page, worth reporting upstream.
Limits
Version-agnostic by construction (it silences whatever MP3s your copy has) but a vendor update installs a fresh loud app, so the build must be re-run. One build at a time — both write the same FIFO. The lid creak is a separate sound from a separate helper and is not affected.
Build spec
The project’s own build notes, rendered. Open the raw .md ↗
Show the spec
Build spec — FreeSlapMac Silent (v1.0.0)
Goal
Make it possible to run FreeSlapMac — and keep every bit of its behaviour except the noise — when the app itself has no mute. Ship it so a stranger can build it from their own copy with no dependencies.
The constraint that shapes everything
The slap/tap sounds are not the app's. spank, the bundled sound engine, plays MP3s from Contents/Resources/Sounds/ and takes no volume or mute argument:
--custom DIR --min-amplitude F --cooldown MS --speed F --volume-scaling
The app stores exactly five preferences — sensitivity, triggerMode, screenFlash, launchAtLogin, _creakingEnabled — and none of them is audio. There is no supported off switch anywhere in 1.1.0.
Approaches considered, and rejected
- Pause detection. Wrong layer: it stops the app reacting, but the sound was never the app's to pause.
- Kill
spank. The root wrapper respawns it fromLAST_CMDon the next loop iteration. - System volume. Silences the entire machine, not the app.
- Rewrite the app's audio path. Binary patch, resigned periodically by the vendor — brittle forever.
- Write to
/tmp/freeslapmac_cmd. The root wrapperevals whatever lands there (see "Security" below). - Replace the audio library. Chosen. Detection and visuals never touch the audio path.
It would work in one line and it is the reason not to: a mute built on a local root-execution channel is a worse bug than the sound.
Design
dittocopy the installed bundle; never modify the original.- Replace every MP3 with a silent MPEG-1 Layer III frame at the original duration:
- Duration matched to the original clip within a frame, so clip timing does not change.
- Rename
CFBundleName/CFBundleDisplayNameto "FreeSlapMac Silent"; keepCFBundleIdentifierso the - Re-sign ad-hoc. The original is
Signature=adhoc, so this reproduces its exact trust posture rather than - Strip
com.apple.quarantine— it is a local build, not a download.
header FF FB 90 C0 + zero side-info + zero main data = 417 bytes per 1152-sample frame (26.122 ms).
user's sensitivity, mode, cooldown and creak preference carry over.
introducing a weaker one.
Dependencies: none
afinfo, afconvert, codesign, ditto, PlistBuddy all ship with macOS. The first build used ffmpeg and was rewritten specifically to drop it: a tool that asks a stranger to brew install something before it can un-mute their own laptop is a tool that will not get used.
Verification requirements (what the package must prove)
- Every clip decodes through AudioToolbox (
afconvert) to zero non-zero PCM bytes — not "quiet". - Duration of every silent clip within 60 ms of the original.
codesign --verify --deep --strictpasses.- Bundle id unchanged.
- Executable byte-identical to the original once signatures are stripped (only the signature blob may differ).
- File count identical (267 → 267).
- A fresh-copy run with arbitrary source/destination paths, and a refusal to overwrite without
FORCE=1.
Failure that must be reported, not hidden
The first implementation used a thread pool with one shared temp filename; 23 of 267 files came out undecodable. The verifier caught it. The package must keep failing loudly on any clip that is not pure silence — a silent build that is 97 % silent is a bug, not a release.
Security note to publish
The app's launch wrapper runs as root, chmods /tmp/freeslapmac_cmd to 666, and evals whatever any local process writes into it. Document it on the page; do not build the tool on top of it.
Non-goals
- Not a fix for the app, and not a report to the vendor (though it should be reported).
- Does not silence the lid-creak helper — that is a separate preference.
- Never redistributes the app or its audio: the silence is generated locally.