Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1913ca5
feat: add Fonts option to pick installed fonts for the rain glyphs
troyfisher Oct 28, 2026
e624a73
fix: size options pages up front to avoid unsatisfiable layout constr…
troyfisher Oct 28, 2026
e33e111
docs: credit and link the Matrix fonts
troyfisher Oct 28, 2026
aa3b03b
test: cover rain font selection
troyfisher Oct 28, 2026
470e1f8
chore: integrate development into rain font selection
patrickschaper Oct 30, 2026
509ab58
fix: improve rain font selection and fallback
patrickschaper Oct 30, 2026
32d5dc3
feat: add Matrix glyph presets and live preview
patrickschaper Oct 30, 2026
81ddef7
feat: list bundled fonts below the system default
patrickschaper Oct 30, 2026
1fa958d
test: allow recovery fixtures to finish queued startup
patrickschaper Oct 30, 2026
50c3950
feat: rename wallpaper app and add playback controls
patrickschaper Oct 31, 2026
9c052a4
docs: require semantic versioning for releases
patrickschaper Oct 31, 2026
4220c07
fix: keep paused wallpaper synced during saver playback
patrickschaper Oct 31, 2026
5a8d7ac
docs: clarify release notes and version bump conventions
patrickschaper Oct 31, 2026
e09c5b1
test: stabilize intro redraw timing
patrickschaper Oct 31, 2026
9a2ddaf
test: allow scrolling fixture to finish command sequence
patrickschaper Oct 31, 2026
643d02b
test: avoid rounding boundary in frame-rate comparison
patrickschaper Oct 31, 2026
db20902
test: report wallpaper state on startup failure
patrickschaper Oct 31, 2026
83f5f0a
test: wait for queued wallpaper startup on slower runners
patrickschaper Oct 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ jobs:
./build.sh
./build-wallpaper.sh
codesign --verify --deep --strict "build/MatrixScreenSaver.saver"
codesign --verify --deep --strict "build/MatrixWallpaper.app"
codesign --verify --deep --strict "build/Matrix Wallpaper.app"

- name: Update CHANGELOG
id: changelog
Expand Down Expand Up @@ -456,9 +456,9 @@ jobs:
./build.sh
./build-wallpaper.sh
bash Scripts/sign-bundle.sh "build/MatrixScreenSaver.saver"
bash Scripts/sign-bundle.sh "build/MatrixWallpaper.app"
bash Scripts/sign-bundle.sh "build/Matrix Wallpaper.app"
codesign --verify --deep --strict "build/MatrixScreenSaver.saver"
codesign --verify --deep --strict "build/MatrixWallpaper.app"
codesign --verify --deep --strict "build/Matrix Wallpaper.app"

- name: Notarize and staple both bundles
if: steps.release.outputs.exists != 'true'
Expand Down Expand Up @@ -491,7 +491,7 @@ jobs:
rm -rf "${release_dir}"
mkdir -p "${release_dir}"
ditto "build/MatrixScreenSaver.saver" "${release_dir}/MatrixScreenSaver.saver"
ditto "build/MatrixWallpaper.app" "${release_dir}/MatrixWallpaper.app"
ditto "build/Matrix Wallpaper.app" "${release_dir}/Matrix Wallpaper.app"

echo "dir=${release_dir}" >> "$GITHUB_OUTPUT"

Expand Down
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class MatrixColumn {
## Git commits

- Follow Conventional Commits, for example: `feat: ...`, `fix: ...`, `docs: ...`, `refactor: ...`, `test: ...`
- Classify version-number bumps as `chore:`, not `fix:`, in commit messages and PR titles.
- Use a short title line.
- Add a few very concise bullet points for the meaningful changes.

Expand Down Expand Up @@ -188,6 +189,8 @@ feat: add character size options

## Releases

- Keep changelog entries and release notes focused on user-facing changes; omit code-signing changes and details.
- Use Semantic Versioning (`MAJOR.MINOR.PATCH`): major for breaking changes, minor for backward-compatible features, patch for backward-compatible fixes. Select the corresponding bump in the release workflow; `VERSION` remains the source of truth.
- Trigger releases by running the **Release** GitHub Actions workflow (`workflow_dispatch`) — never manually.
- The workflow bumps the version, updates `CHANGELOG.md`, and opens a `release/*` PR targeting `main`.
- Merging that `release/*` PR into `main` triggers the publish job, which creates the actual GitHub release with a zipped `.saver` bundle attached.
10 changes: 5 additions & 5 deletions Homebrew/Casks/matrix-screen-saver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
depends_on arch: :arm64
depends_on macos: :sequoia

app "MatrixWallpaper.app"
app "MatrixWallpaper.app", target: "Matrix Wallpaper.app"
screen_saver "MatrixScreenSaver.saver"

preflight_steps do
Expand All @@ -24,13 +24,13 @@
writable_paths: [{ path: "MatrixScreenSaver.saver", base: :screen_saverdir }]
end

if_path_exists "MatrixWallpaper.app", base: :appdir do
if_path_exists "Matrix Wallpaper.app", base: :appdir do
run "/bin/echo",
args: ["Existing app at {{appdir}}/MatrixWallpaper.app. " \
args: ["Existing app at {{appdir}}/Matrix Wallpaper.app. " \
"To replace it while retaining options, run: " \
"brew install --cask --force patrickschaper/tap/matrix-screen-saver"],
print_stdout: true,
writable_paths: [{ path: "MatrixWallpaper.app", base: :appdir }]
writable_paths: [{ path: "Matrix Wallpaper.app", base: :appdir }]
end

run "/bin/echo",
Expand All @@ -53,7 +53,7 @@
args: ["Open System Settings > Wallpaper > Screen Saver and select MatrixScreenSaver."],
print_stdout: true
run "/bin/echo",
args: ["Open {{appdir}}/MatrixWallpaper.app to start Matrix Wallpaper. " \
args: ["Open {{appdir}}/Matrix Wallpaper.app to start Matrix Wallpaper. " \
"Launch at Login is optional in its Matrix menu."],
print_stdout: true
end
Expand Down
30 changes: 20 additions & 10 deletions Homebrew/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ The public tap is [patrickschaper/homebrew-tap](https://github.com/patrickschape
that repository. Users add it with `brew tap patrickschaper/tap`.

The next release payload uses Homebrew's native `screen_saver` and `app` artifacts,
not the local installers, to manage `MatrixScreenSaver.saver` and `MatrixWallpaper.app`
not the local installers, to manage `MatrixScreenSaver.saver` and `Matrix Wallpaper.app`
together. The live tap gains this behavior only after a new dual-bundle release and
tap update; immutable older releases remain saver-only.
tap update; immutable saver-only releases remain saver-only.
The template retains the pinned archive's `MatrixWallpaper.app` source and uses
Homebrew's `target:` to install it as `Matrix Wallpaper.app`. The release renderer
selects the source name from each validated archive, so old dual-bundle downloads
and future renamed bundles both install under the new name.
It retains the `dev.patsch.MatrixScreenSaver` preferences domain and has no zap
or preference-cleanup hook. Its published binary requires Apple Silicon (ARM64)
and macOS 15 (Sequoia) or newer.
Expand All @@ -24,7 +28,7 @@ brew style "$PWD/Homebrew/Casks/matrix-screen-saver.rb"

```bash
brew trust --cask patrickschaper/tap/matrix-screen-saver
brew install --cask patrickschaper/tap/matrix-screen-saver && open /Applications/MatrixWallpaper.app
brew install --cask patrickschaper/tap/matrix-screen-saver && open "/Applications/Matrix Wallpaper.app"
```

The command launches the wallpaper app after installation succeeds, using Homebrew's
Expand All @@ -34,7 +38,7 @@ The fully qualified install trusts this cask, not the entire tap. Explicit
`brew trust --cask` also permits subsequent installs using the short name.

**Security:** preflight removes quarantine recursively only from the
checksum-verified staged `MatrixScreenSaver.saver` and `MatrixWallpaper.app`, before
checksum-verified staged `MatrixScreenSaver.saver` and wallpaper app, before
Homebrew moves them. This bypasses Gatekeeper quarantine checks; it does not make either bundle notarized
or Apple-approved. Install only if you trust the release publisher. The cask
prints this disclosure before invoking `/usr/bin/xattr`; failure aborts installation.
Expand All @@ -43,7 +47,7 @@ After installation, open **System Settings > Wallpaper > Screen Saver** and
select **MatrixScreenSaver** manually. Modern Homebrew's sandbox blocks opening
Settings, so automatic opening was intentionally removed. The cask never selects
the saver, launches the wallpaper on a fresh install, enables login startup, or opens
a browser. The command above launches **MatrixWallpaper** from your shell after Homebrew
a browser. The command above launches **Matrix Wallpaper** from your shell after Homebrew
finishes; use its single **Launch at Login** checkbox if wanted.
Homebrew may reopen an already-running app following an upgrade. Successful install,
upgrade, and reinstall print:
Expand Down Expand Up @@ -79,6 +83,11 @@ Upgrades and reinstalls remain native Homebrew operations. An upgrade may print
the existing-target guidance because Homebrew can leave an empty target directory
during replacement; no prior-receipt snapshot or initial-install-only behavior
is needed. Custom destinations are honored, and other saver copies are not removed.
When upgrading a managed `MatrixWallpaper.app`, Homebrew uses its prior receipt
to remove the old filename and installs `Matrix Wallpaper.app`. A conflict at the
new path aborts the upgrade and restores the previous managed bundles. Unmanaged
old-name copies are not removed; use the local installer to migrate a copy in
`~/Applications`, or remove that copy yourself after confirming the new app works.
The native app and screen-saver artifacts are both installed and removed by the
same cask. Uninstall requests that `dev.patsch.MatrixWallpaper` quit and asks
Homebrew to remove its login items. Homebrew skips login-item cleanup when an
Expand Down Expand Up @@ -143,10 +152,10 @@ The Release publish job invokes the script with explicit `--publish` opt-in,
after validating the published asset and uploading the handoff. It writes only
`Casks/matrix-screen-saver.rb` on the tap's default branch; no tap PR or merge is
required. This replaces the previous optional, human-merged tap PR behavior.
Only version, SHA-256, and minimum macOS metadata may differ from the source
template. For the first dual-bundle release, the exact frozen saver-only predecessor
is also accepted for a strictly newer version, using its normalized structure hash.
This one reviewed transition does not allow arbitrary structural edits. Unrelated
Only version, SHA-256, minimum macOS metadata, and the validated old/new archive
source name may differ from the source template. The exact frozen saver-only and
old-name dual-bundle predecessors are also accepted for a strictly newer version,
using their normalized structure hashes. These reviewed transitions do not allow arbitrary structural edits. Unrelated
cask edits or a missing cask fail closed for manual review.
Identical reruns make no commit, older versions are skipped, and conflicting
same-version metadata is rejected. Each write includes the current file SHA;
Expand Down Expand Up @@ -203,7 +212,8 @@ A separate
sentinel outside the artifact destination verifies preference retention; it does
not access the actual defaults domain. HOME alone is not used as isolation.

Native integration covers saver-only migration, dual install, conflict failure, forced migration, upgrade,
Native integration covers saver-only migration, old-name app migration and rollback,
old/new archive names, dual install, conflict failure, forced migration, upgrade,
reinstall, uninstall, quarantine removal, broken-symlink conflict/force semantics,
and developer-mode acceptance without legacy warnings on definition load or
uninstall. Run workflow lint (for example `actionlint`) separately; never conceal
Expand Down
34 changes: 26 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ The screen saver also comes with an app replacing your wallpaper with the animat

```bash
brew trust --cask patrickschaper/tap/matrix-screen-saver
brew install --cask patrickschaper/tap/matrix-screen-saver && open /Applications/MatrixWallpaper.app
brew install --cask patrickschaper/tap/matrix-screen-saver && open "/Applications/Matrix Wallpaper.app"
```

- Wallpaper: open **MatrixWallpaper** in Applications. options available through menubar icon.
- Wallpaper: open **Matrix Wallpaper** in Applications. options available through menubar icon.
- Screen saver options: **System Settings → Wallpaper → Screen Saver → MatrixScreenSaver → Options…**.

## Buy me a coffee
Expand All @@ -40,6 +40,7 @@ The saver exposes a native **Options…** sheet. The values are stored with `Scr
| Frame rate | Set the frame rate per second. A positive number less than or equal to 1000. | 25 |
| Error rate | Set the factor for the rate of character changes. A non-negative number. | 1.0 |
| Characters | Restrict rain glyphs to a custom set (e.g. ATGC). Leave empty for the default. | *(empty)* |
| Font | Pick one installed font for the rain glyphs. Intro text stays in the system font. See [Matrix fonts](#matrix-fonts). | *(system font)* |
| Neo message scene | Show the Neo message intro before the main scene. | On |
| Typing speed | Typing speed multiplier for Neo messages, custom command entry and the trace program. A positive number; pauses keep their natural duration. Output is not typed. | 1.0 |
| Name | Name used in the intro message ("Wake up, {name}..."). Only applies when Neo message lines is empty. | *(empty — uses "Neo")* |
Expand All @@ -56,6 +57,14 @@ including while the screen is locked. Command text and output are not logged. Li
until exit and retain at most 64 KiB of combined output; stopping or restarting playback
cancels its command. The sandboxed screen saver may not have the same access as the wallpaper app.

### Matrix fonts

The **Glyph set** radio buttons in **Rain** select **Default**, **Classic**, or **Resurrections**. Classic and Resurrections use their original bundled fonts and glyph artwork. Default keeps the existing configurable rain. Switching presets preserves your custom font and character settings; these controls are editable when Default is selected.

The **Font** option selects one installed font family, including hidden fonts discovered in the standard system and user font folders. Choosing another font replaces the selection; Reset restores the system font. Existing multi-font settings retain only the first font. Default and custom characters missing from the selected font use macOS font fallback when glyph images are cached, with no extra font lookup during playback. Install any additional fonts yourself.

The bundled [Matrix Code](https://github.com/Rezmason/matrix/raw/master/assets/Matrix-Code.ttf) and [Matrix Resurrected](https://github.com/Rezmason/matrix/raw/master/assets/Matrix-Resurrected.ttf) fonts are published in [Rezmason/matrix](https://github.com/Rezmason/matrix) (MIT, © Rezmason 2018), which recreate the glyphs from the films. Thanks to Rezmason for making them available. See [font provenance](Resources/Fonts/README.md) and the [included license](Resources/Fonts/LICENSE.txt).

### Wallpaper menubar menu

![menubar.jpg](docs/wallpaper-menubar.jpg)
Expand All @@ -67,7 +76,7 @@ cancels its command. The sandboxed screen saver may not have the same access as
- Native Swift/AppKit screen saver bundle
- Edge-to-edge full-screen saver output, with terminal-style chrome kept in the preview host
- In-process renderer for `rain-forever` with an optional upstream `number` intro
- Native **Options…** sheet for Number scene, Twinkle, Diffuse, Character size, Rain density, Frame rate, Error rate, Characters, Neo message scene/speed/lines, custom shell commands/playback, and Scan lines
- Native **Options…** sheet for Number scene, Twinkle, Diffuse, Character size, Rain density, Frame rate, Error rate, Characters, Fonts, Neo message scene/speed/lines, custom shell commands/playback, and Scan lines
- Preview app for fast iteration without reinstalling

### Repository layout
Expand Down Expand Up @@ -99,7 +108,7 @@ These create the screen saver bundle and wallpaper app:

```text
build/MatrixScreenSaver.saver
build/MatrixWallpaper.app
build/Matrix Wallpaper.app
```

Both build scripts read the current version from `./VERSION` and write it into their bundle metadata.
Expand Down Expand Up @@ -136,7 +145,7 @@ This rebuilds the bundle, compiles the preview host, and opens the saver in a no
To launch the built wallpaper app without installing:

```bash
open build/MatrixWallpaper.app
open "build/Matrix Wallpaper.app"
```

### Install
Expand Down Expand Up @@ -167,11 +176,15 @@ To install and launch the wallpaper app in your user Applications folder:

```bash
./install-wallpaper.sh
open ~/Applications/MatrixWallpaper.app
open "$HOME/Applications/Matrix Wallpaper.app"
```

The installer builds and verifies the app, gracefully quits running copies before
replacement, and retains preferences. It does not launch the app or enable login startup.
It migrates a signed `MatrixWallpaper.app` with the matching bundle ID to
`Matrix Wallpaper.app`, restoring the previous installation if replacement fails.
Unrelated bundles and symlinks at the old path are left alone. The executable remains
`MatrixWallpaper` and the bundle ID remains `dev.patsch.MatrixWallpaper`.

When MatrixScreenSaver is installed in `~/Library/Screen Savers` or `/Library/Screen Savers`,
the wallpaper menu shows **Sync with Screen Saver**. It is checked by default: the saver
Expand All @@ -180,8 +193,13 @@ The choice survives app restarts and saver reinstallation; opening the menu refr
installation detection. This does not change visual options or synchronization between monitors.

While Matrix Wallpaper runs, it saves each display's desktop image and display options,
then sets the underlying wallpaper to plain black. **Stop** and **Quit Matrix Wallpaper**
restore those settings. Temporary pauses and animation restarts keep the original backup.
then sets the underlying wallpaper to plain black. **Stop** and **Pause/Resume** share
one native menu row. **Pause** freezes the visible frame; **Resume** continues the scene.
Pausing is session-only and does not persist across launches. With **Sync with Screen Saver**
enabled, the saver temporarily advances the shared scene even while the wallpaper is paused.
When the saver exits, the wallpaper pauses again at the updated scene. **Stop** and
**Quit Matrix Wallpaper** restore the original wallpaper settings. Temporary pauses
and animation restarts keep the original backup.
If you choose a different wallpaper while Matrix runs, that newer choice is preserved.

Backups are stored in `~/Library/Application Support/MatrixWallpaper/DesktopWallpaper/`.
Expand Down
21 changes: 21 additions & 0 deletions Resources/Fonts/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Rezmason

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Binary file added Resources/Fonts/Matrix-Code.ttf
Binary file not shown.
Binary file added Resources/Fonts/Matrix-Resurrected.ttf
Binary file not shown.
Loading
Loading